From 885fe620c87d5fecfbc75cfe02b63916698c05d7 Mon Sep 17 00:00:00 2001 From: Bruce Collie Date: Tue, 31 Oct 2023 15:24:49 +0000 Subject: [PATCH 1/4] Fix homebrew repo authentication (#3781) The previous version of this workflow was doing something non-standard with SSH keys that broke when we migrated it over to the RV org; this PR fixes the breakage by using our standard `JENKINS_GITHUB_PAT` authentication instead. I have tested that this works by running the steps in isolation on a PR branch (https://github.com/runtimeverification/k/pull/3780) and I'm reasonably confident this fix is correct. --- .github/workflows/release.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ef00f0ce19e..bf86be01c72 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -236,9 +236,9 @@ jobs: id: checkout with: repository: runtimeverification/homebrew-k + token: ${{ secrets.JENKINS_GITHUB_PAT }} path: homebrew-k ref: staging - persist-credentials: false continue-on-error: true - name: 'Check out homebrew repo master branch' @@ -246,8 +246,8 @@ jobs: if: ${{ steps.checkout.outcome == 'failure' }} with: repository: runtimeverification/homebrew-k + token: ${{ secrets.JENKINS_GITHUB_PAT }} path: homebrew-k - persist-credentials: false - name: 'Download bottle' uses: actions/download-artifact@v2 @@ -300,19 +300,16 @@ jobs: version=$(cat k-homebrew-checkout/package/version) mv homebrew-k-old/${BOTTLE_NAME} homebrew-k-old/${REMOTE_BOTTLE_NAME} gh release upload --repo runtimeverification/k --clobber v${version} homebrew-k-old/${REMOTE_BOTTLE_NAME} - # Deprecate After Homebrew tap migration - - name: 'Add ssh key' - uses: shimataro/ssh-key-action@v2 - with: - key: ${{ secrets.HOMEBREW_SSH_KEY }} - known_hosts: ${{ secrets.KNOWN_HOSTS_GITHUB_COM }} + + - run: | + git config --global user.name rv-jenkins + git config --global user.email devops@runtimeverification.com - name: 'Commit changes' run: | cp homebrew-k-old/Formula/kframework.rb homebrew-k/Formula/kframework.rb cd homebrew-k git commit -m 'Update brew package version' Formula/kframework.rb - git remote set-url origin git@github.com:runtimeverification/homebrew-k.git git push origin master - name: 'Delete Release' From c5231390f07b226f983b8d7bea53f06a9d0058ca Mon Sep 17 00:00:00 2001 From: Bruce Collie Date: Wed, 1 Nov 2023 12:03:06 +0000 Subject: [PATCH 2/4] Adopt Google Java style (#3757) This PR is an initial attempt to build some consensus around a consistent, automated code style for the K Frontend's Java code. Other parts of K already do this for other languages, and so I think there's a pretty clear precedent that we should want to set something similar up for our largest, oldest codebase: * The LLVM backend's C++ code is formatted with [`clang-format`](https://github.com/runtimeverification/llvm-backend/blob/master/.clang-format) * The Haskell backend (and booster)'s Haskell code is formatted with [Fourmolu](https://github.com/runtimeverification/hs-backend-booster/blob/main/fourmolu.yaml) * Pyk's Python code is formatted with [Black](https://github.com/runtimeverification/pyk/blob/41706ef5081585a4c71f7fccb4dea2d7a3796421/Makefile#L88-L89) At a high level, the notional benefits of doing this are: * Improved readability of code * More focused PR review; no consideration needs to be given to formatting when reading and reviewing code * Eliminates "diff noise" from unrelated formatting changes * Consistency across the whole codebase; there are nearly 100 unique contributors to K which means that small variations in style have been accrued over time I have done some research into available auto-formatters for Java, focusing on the following points: 1. Is the style agreeable to developers, and do we as a team feel happy with the results it produces? 2. Can the style be applied locally using our existing tools[^1]? 3. Can the style be enforced in CI using our existing Github Actions infrastructure? 4. Is there a community consensus around using this style in practice? Beginning with (4) the standout contender for a "standardised" tool that's used by lots of Java developers in practice is Google's `google-java-format` tool, which is designed to apply the [Google Java Style](https://google.github.io/styleguide/javaguide.html) automatically. This PR focuses on using this tool and evaluating its tradeoffs; if we later decide it's totally unworkable then we can revisit this evaluation with a different tool. My summary of the pros and cons of this format are: #### Pros * Implemented and maintained by a large company who rely on it for their own tooling. * Includes support for new language features and syntax. * It is unlikely that Google will stop using this tool on their Java code, and so the chances that it ends up bit-rotting into uselessness are very small. * Active secondary ecosystem for IDE and CI tooling. * Official IntelliJ plugin * Third-party, actively maintained Maven integration * Third-party, actively maintained Github action * **Personally speaking**, I like the style that's been applied; a skim through the diff suggests that some of the expressions I've found hardest to parse in the frontend are now a bit clearer * Easy enough to get working locally; the only real issue I had was that I seemingly hadn't updated IntelliJ in two years and the JDK version it has internally was too old. * Works well in CI; this PR adds an action to the test workflow that checks formatting. #### Cons * Not configurable beyond 2/4 space indentation; this is by design on Google's part[^2]. * One big diff will end up getting applied to the whole project[^3]. * Others may not prefer the style used. I hope that this is a fair summary of the tradeoffs of doing this kind of tooling update; I'd like to get opinions from everyone who works on this code to make sure that we're all as happy as possible with what we end up doing. Things to think about in particular: * Do you like the code style, from skimming the diff? * Does the "format locally with IntelliJ, check + enforce in CI" workflow work for you, or would you rather have CI make commits to your branch so that you don't have to worry about formatting[^4]? * Are there other tools you're aware of to do the same job? [^1]: By this I really just mean IntelliJ; I'm not aware of anyone using different tools to develop the K Frontend. If you're using some other setup then please let me know! [^2]: This is also the situation we have with Black for Python, however, and that works fine! [^3]: Though this is true for _any_ formatter, and we probably just need to accept this pain as a once-off cost of doing business. [^4]: The former is how we do automatic formatting for the other projects, so I am treating it as the default option here. --- .github/workflows/test-pr.yml | 28 +- .../backend/haskell/HaskellBackend.java | 126 +- .../haskell/HaskellBackendKModule.java | 119 +- .../backend/haskell/HaskellKRunOptions.java | 58 +- .../haskell/HaskellKompileOptions.java | 22 +- .../backend/haskell/HaskellRewriter.java | 848 ++-- .../kframework/kore/convertors/BaseTest.java | 152 +- .../kore/convertors/TstKILtoKOREIT.java | 93 +- .../com/davekoelle/AlphanumComparator.java | 152 +- .../java/org/kframework/backend/Backends.java | 8 +- .../org/kframework/backend/PosterBackend.java | 15 +- .../backend/kore/ConstructorChecks.java | 154 +- .../kframework/backend/kore/KoreBackend.java | 587 ++- .../kframework/backend/kore/ModuleToKORE.java | 4066 +++++++++-------- .../kframework/compile/AbstractBackend.java | 24 +- .../kframework/compile/AddCoolLikeAtt.java | 101 +- .../compile/AddImplicitComputationCell.java | 162 +- .../compile/AddImplicitCounterCell.java | 69 +- .../kframework/compile/AddParentCells.java | 543 +-- .../kframework/compile/AddSortInjections.java | 893 ++-- .../kframework/compile/AddTopCellToRules.java | 184 +- .../java/org/kframework/compile/Backend.java | 48 +- .../org/kframework/compile/CloseCells.java | 503 +- ...ComputeTransitiveFunctionDependencies.java | 155 +- .../compile/ConcretizationInfo.java | 178 +- .../kframework/compile/ConcretizeCells.java | 119 +- .../kframework/compile/ConstantFolding.java | 250 +- .../compile/ConvertDataStructureToLookup.java | 1225 ++--- .../DeconstructIntegerAndFloatLiterals.java | 267 +- .../org/kframework/compile/ExpandMacros.java | 736 +-- .../org/kframework/compile/FloatBuiltin.java | 360 +- .../kframework/compile/GatherVarsVisitor.java | 88 +- .../kframework/compile/GenerateCoverage.java | 50 +- .../GenerateSentencesFromConfigDecl.java | 1353 +++--- .../compile/GenerateSortPredicateRules.java | 84 +- .../compile/GenerateSortPredicateSyntax.java | 59 +- .../compile/GenerateSortProjections.java | 205 +- .../kframework/compile/GuardOrPatterns.java | 161 +- .../compile/IncompleteCellUtils.java | 120 +- .../kframework/compile/LiftToKSequence.java | 127 +- .../compile/MarkExtraConcreteRules.java | 57 +- .../compile/MinimizeTermConstruction.java | 383 +- .../compile/NormalizeVariables.java | 198 +- .../kframework/compile/NumberSentences.java | 28 +- .../compile/PatternValueAwareVisitor.java | 134 +- .../compile/ProcessGroupAttributes.java | 44 +- .../kframework/compile/PropagateMacro.java | 26 +- .../org/kframework/compile/RefreshRules.java | 132 +- .../org/kframework/compile/RemoveUnit.java | 37 +- .../kframework/compile/ResolveAnonVar.java | 240 +- .../org/kframework/compile/ResolveComm.java | 126 +- .../kframework/compile/ResolveContexts.java | 554 +-- .../compile/ResolveFreshConfigConstants.java | 130 +- .../compile/ResolveFreshConstants.java | 490 +- .../org/kframework/compile/ResolveFun.java | 426 +- .../compile/ResolveFunctionWithConfig.java | 377 +- .../compile/ResolveHeatCoolAttribute.java | 104 +- .../kframework/compile/ResolveIOStreams.java | 750 +-- .../compile/ResolveSemanticCasts.java | 263 +- .../org/kframework/compile/ResolveStrict.java | 452 +- .../compile/RewriteAwareTransformer.java | 80 +- .../compile/RewriteAwareVisitor.java | 126 +- .../org/kframework/compile/SortCells.java | 1624 +++---- .../java/org/kframework/compile/SortInfo.java | 81 +- .../compile/checks/CheckAnonymous.java | 170 +- .../kframework/compile/checks/CheckAssoc.java | 99 +- .../kframework/compile/checks/CheckAtt.java | 471 +- .../compile/checks/CheckBracket.java | 41 +- .../checks/CheckConfigurationCells.java | 91 +- .../compile/checks/CheckFunctions.java | 242 +- .../kframework/compile/checks/CheckHOLE.java | 130 +- .../org/kframework/compile/checks/CheckK.java | 69 +- .../compile/checks/CheckKLabels.java | 389 +- .../compile/checks/CheckLabels.java | 41 +- .../compile/checks/CheckListDecl.java | 78 +- .../compile/checks/CheckRHSVariables.java | 183 +- .../compile/checks/CheckRewrite.java | 291 +- .../compile/checks/CheckSmtLemmas.java | 44 +- .../checks/CheckSortTopUniqueness.java | 47 +- .../compile/checks/CheckStreams.java | 44 +- .../compile/checks/CheckSyntaxGroups.java | 46 +- .../compile/checks/CheckTokens.java | 60 +- .../checks/ComputeUnboundVariables.java | 125 +- .../org/kframework/kast/KastFrontEnd.java | 416 +- .../java/org/kframework/kast/KastModule.java | 67 +- .../java/org/kframework/kast/KastOptions.java | 295 +- .../org/kframework/kdep/KDepFrontEnd.java | 192 +- .../java/org/kframework/kdep/KDepModule.java | 46 +- .../java/org/kframework/kdep/KDepOptions.java | 24 +- .../main/java/org/kframework/kil/ASTNode.java | 304 +- .../java/org/kframework/kil/Definition.java | 73 +- .../org/kframework/kil/DefinitionItem.java | 22 +- .../main/java/org/kframework/kil/Import.java | 72 +- .../main/java/org/kframework/kil/Lexical.java | 84 +- .../main/java/org/kframework/kil/Module.java | 112 +- .../java/org/kframework/kil/ModuleItem.java | 27 +- .../java/org/kframework/kil/NonTerminal.java | 84 +- .../org/kframework/kil/PriorityBlock.java | 139 +- .../kframework/kil/PriorityBlockExtended.java | 83 +- .../org/kframework/kil/PriorityExtended.java | 90 +- .../kframework/kil/PriorityExtendedAssoc.java | 99 +- .../java/org/kframework/kil/Production.java | 475 +- .../org/kframework/kil/ProductionItem.java | 6 +- .../main/java/org/kframework/kil/Require.java | 34 +- .../java/org/kframework/kil/SortSynonym.java | 74 +- .../org/kframework/kil/StringSentence.java | 96 +- .../main/java/org/kframework/kil/Syntax.java | 169 +- .../org/kframework/kil/SyntaxLexical.java | 74 +- .../java/org/kframework/kil/Terminal.java | 69 +- .../java/org/kframework/kil/UserList.java | 119 +- .../org/kframework/kil/loader/Context.java | 62 +- .../org/kframework/kompile/BackendModule.java | 34 +- .../kompile/CompiledDefinition.java | 401 +- .../kframework/kompile/DefinitionParsing.java | 1499 +++--- .../java/org/kframework/kompile/Kompile.java | 1188 +++-- .../kframework/kompile/KompileFrontEnd.java | 145 +- .../org/kframework/kompile/KompileModule.java | 78 +- .../kframework/kompile/KompileOptions.java | 354 +- .../kompile/KompileUsageFormatter.java | 744 +-- .../kore/convertors/KILTransformation.java | 69 +- .../kframework/kore/convertors/KILtoKORE.java | 646 +-- .../java/org/kframework/kprove/KProve.java | 133 +- .../org/kframework/kprove/KProveFrontEnd.java | 79 +- .../org/kframework/kprove/KProveModule.java | 77 +- .../org/kframework/kprove/KProveOptions.java | 171 +- .../kprove/ProofDefinitionBuilder.java | 197 +- .../org/kframework/kprove/RewriterModule.java | 37 +- .../KSearchPatternFrontEnd.java | 163 +- .../ksearchpattern/KSearchPatternModule.java | 43 +- .../ksearchpattern/KSearchPatternOptions.java | 29 +- .../kframework/kserver/KServerFrontEnd.java | 299 +- .../org/kframework/kserver/KServerModule.java | 52 +- .../kframework/kserver/KServerOptions.java | 25 +- .../org/kframework/lsp/CompletionHelper.java | 417 +- .../org/kframework/lsp/KLanguageServer.java | 236 +- .../lsp/KLanguageServerLauncher.java | 49 +- .../main/java/org/kframework/lsp/KPos.java | 130 +- .../org/kframework/lsp/KTextDocument.java | 139 +- .../kframework/lsp/KTextDocumentService.java | 200 +- .../org/kframework/lsp/KWorkspaceService.java | 46 +- .../org/kframework/lsp/LSClientLogger.java | 43 +- .../lsp/TextDocumentSyncHandler.java | 1198 +++-- .../org/kframework/main/AbstractKModule.java | 146 +- .../main/AnnotatedByDefinitionModule.java | 43 +- .../org/kframework/main/BinaryToText.java | 48 +- .../java/org/kframework/main/FrontEnd.java | 119 +- .../org/kframework/main/GlobalOptions.java | 279 +- .../java/org/kframework/main/JavaVersion.java | 12 +- .../java/org/kframework/main/KModule.java | 18 +- .../main/java/org/kframework/main/Main.java | 335 +- .../main/java/org/kframework/main/Tool.java | 7 +- .../org/kframework/parser/InputModes.java | 7 +- .../java/org/kframework/parser/KRead.java | 304 +- .../org/kframework/parser/ParserUtils.java | 691 +-- .../parser/binary/BinaryParser.java | 352 +- .../parser/inner/ApplySynonyms.java | 43 +- .../inner/CollectProductionsVisitor.java | 75 +- .../kframework/parser/inner/ParseCache.java | 28 +- .../parser/inner/ParseInModule.java | 758 +-- .../parser/inner/RuleGrammarGenerator.java | 1215 +++-- .../inner/disambiguation/AddEmptyLists.java | 458 +- .../inner/disambiguation/AmbFilter.java | 86 +- .../inner/disambiguation/AmbFilterError.java | 91 +- .../CollapseRecordProdsVisitor.java | 155 +- .../disambiguation/KAppToTermConsVisitor.java | 181 +- .../inner/disambiguation/PriorityVisitor.java | 432 +- .../PushAmbiguitiesDownAndPreferAvoid.java | 210 +- .../disambiguation/PushTopAmbiguityUp.java | 62 +- .../disambiguation/RemoveBracketVisitor.java | 17 +- .../inner/disambiguation/RemoveOverloads.java | 41 +- .../ResolveOverloadedTerminators.java | 58 +- .../disambiguation/TreeCleanerVisitor.java | 25 +- .../disambiguation/TypeInferenceVisitor.java | 236 +- .../inner/disambiguation/TypeInferencer.java | 358 +- .../parser/inner/kernel/EarleyParser.java | 416 +- .../parser/inner/kernel/KSyntax2Bison.java | 578 ++- .../parser/inner/kernel/Scanner.java | 893 ++-- .../kframework/parser/json/JsonParser.java | 768 ++-- .../outer/ExtractFencedKCodeFromMarkdown.java | 171 +- .../org/kframework/unparser/AddBrackets.java | 369 +- .../org/kframework/unparser/ColorSetting.java | 7 +- .../org/kframework/unparser/Formatter.java | 254 +- .../org/kframework/unparser/Indenter.java | 112 +- .../java/org/kframework/unparser/KPrint.java | 726 +-- .../org/kframework/unparser/OutputModes.java | 40 +- .../org/kframework/unparser/PrintOptions.java | 207 +- .../org/kframework/unparser/ToBinary.java | 213 +- .../java/org/kframework/unparser/ToJson.java | 769 ++-- .../java/org/kframework/unparser/ToLatex.java | 237 +- .../org/kframework/utils/BinaryLoader.java | 130 +- .../java/org/kframework/utils/ColorUtil.java | 972 ++-- .../kframework/utils/ExitOnTimeoutThread.java | 31 +- .../kframework/utils/IndentingFormatter.java | 58 +- .../kframework/utils/InterrupterRunnable.java | 22 +- .../java/org/kframework/utils/RunProcess.java | 130 +- .../java/org/kframework/utils/Stopwatch.java | 99 +- .../utils/errorsystem/KExceptionManager.java | 349 +- .../kframework/utils/file/DefinitionDir.java | 11 +- .../kframework/utils/file/Environment.java | 11 +- .../org/kframework/utils/file/FileUtil.java | 581 ++- .../org/kframework/utils/file/JarInfo.java | 141 +- .../kframework/utils/file/KompiledDir.java | 11 +- .../org/kframework/utils/file/TTYInfo.java | 7 +- .../org/kframework/utils/file/TempDir.java | 11 +- .../org/kframework/utils/file/WorkingDir.java | 11 +- .../kframework/utils/inject/Annotations.java | 163 +- .../org/kframework/utils/inject/Builtins.java | 11 +- .../kframework/utils/inject/CommonModule.java | 110 +- .../org/kframework/utils/inject/Concrete.java | 11 +- .../utils/inject/DefinitionLoadingModule.java | 181 +- .../utils/inject/DefinitionScope.java | 98 +- .../utils/inject/DefinitionScoped.java | 11 +- .../utils/inject/GraphInjector.java | 36 +- .../utils/inject/JCommanderModule.java | 118 +- .../org/kframework/utils/inject/Main.java | 13 +- .../org/kframework/utils/inject/Options.java | 11 +- .../utils/inject/OuterParsingModule.java | 85 +- .../utils/inject/RequestScoped.java | 11 +- .../kframework/utils/inject/SimpleScope.java | 148 +- .../org/kframework/utils/inject/Spec1.java | 13 +- .../org/kframework/utils/inject/Spec2.java | 13 +- .../kframework/utils/inject/StartTime.java | 14 +- .../utils/options/BackendOptions.java | 11 +- .../utils/options/BaseEnumConverter.java | 52 +- .../options/DefinitionLoadingOptions.java | 29 +- .../utils/options/DurationConverter.java | 51 +- .../utils/options/EnumSetConverter.java | 35 +- .../utils/options/InnerParsingOptions.java | 17 +- .../utils/options/OnOffConverter.java | 25 +- .../utils/options/OuterParsingOptions.java | 66 +- .../utils/options/OutputDirectoryOptions.java | 29 +- .../kframework/utils/options/SMTOptions.java | 89 +- .../kframework/utils/options/SMTSolver.java | 16 +- .../utils/options/StringListConverter.java | 41 +- .../compile/ConstantFoldingTest.java | 460 +- .../org/kframework/kast/KastModuleTest.java | 25 +- .../kompile/KompileFrontEndTest.java | 82 +- .../kframework/kompile/KompileModuleTest.java | 38 +- .../kompile/KompileOptionsTest.java | 78 +- .../kore/compile/AddParentsCellsTest.java | 516 ++- .../kore/compile/CloseCellsTest.java | 254 +- .../GenerateSentencesFromConfigDeclTest.java | 413 +- .../kore/compile/SortCellsTest.java | 758 +-- .../kore/compile/TestConfiguration.java | 389 +- .../java/org/kframework/lsp/LSPTests.java | 251 +- .../parser/inner/RuleGrammarTest.java | 1071 +++-- .../disambiguation/AddEmptyListsTest.java | 386 +- .../parser/json/JsonSerializationTests.java | 132 +- .../kframework/parser/outer/MDsourceTest.java | 186 +- .../parser/outer/OuterParsingTests.java | 70 +- .../kframework/unparser/AddBracketsTest.java | 151 +- .../kframework/unparser/BinaryKASTTest.java | 84 +- .../org/kframework/unparser/KPrintTest.java | 96 +- .../org/kframework/utils/BaseTestCase.java | 109 +- .../org/kframework/utils/ColorUtilTest.java | 18 +- .../java/org/kframework/utils/IOTestCase.java | 31 +- .../org/kframework/utils/StringUtilTest.java | 171 +- .../inject/DefinitionLoadingModuleTest.java | 122 +- kore/src/main/java/org/kframework/API.java | 8 +- kore/src/main/java/org/kframework/List.java | 40 +- .../src/main/java/org/kframework/Warning.java | 4 +- .../kframework/attributes/HasLocation.java | 5 +- .../org/kframework/builtin/BooleanUtils.java | 28 +- .../java/org/kframework/builtin/Hooks.java | 66 +- .../java/org/kframework/builtin/KLabels.java | 122 +- .../java/org/kframework/builtin/Rules.java | 18 +- .../kframework/compile/ConfigurationInfo.java | 158 +- .../org/kframework/compile/LabelInfo.java | 167 +- .../kframework/definition/Associativity.java | 5 +- .../org/kframework/definition/UserList.java | 132 +- .../main/java/org/kframework/kore/AddAtt.java | 89 +- .../java/org/kframework/kore/AddAttRec.java | 83 +- .../java/org/kframework/kore/AttCompare.java | 117 +- .../java/org/kframework/kore/ExistsK.java | 20 +- .../main/java/org/kframework/kore/FindK.java | 20 +- .../java/org/kframework/kore/TransformK.java | 134 +- .../main/java/org/kframework/kore/VisitK.java | 8 +- .../org/kframework/parser/KoreParser.java | 63 +- .../org/kframework/rewriter/SearchType.java | 12 +- .../main/java/org/kframework/utils/OS.java | 90 +- .../java/org/kframework/utils/StringUtil.java | 1381 +++--- .../utils/errorsystem/KEMException.java | 373 +- .../utils/errorsystem/KException.java | 558 +-- .../java/org/kframework/CollectionsTest.java | 64 +- .../org/kframework/kore/InterfaceTest.java | 67 +- .../java/org/kframework/kore/VisitorTest.java | 122 +- .../kframework/backend/llvm/LLVMBackend.java | 292 +- .../backend/llvm/LLVMBackendKModule.java | 49 +- .../backend/llvm/LLVMKompileOptions.java | 109 +- 289 files changed, 34355 insertions(+), 29016 deletions(-) diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index d27cb8e808f..d13803a5e11 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -29,10 +29,32 @@ jobs: git push origin HEAD:${GITHUB_HEAD_REF} fi + format-check: + name: 'Check Java code formatting' + runs-on: ubuntu-latest + needs: version-sync + steps: + - name: 'Check out code' + uses: actions/checkout@v3 + with: + token: ${{ secrets.JENKINS_GITHUB_PAT }} + # fetch-depth 0 means deep clone the repo + fetch-depth: 0 + - name: 'Set up Java 17' + uses: actions/setup-java@v3 + with: + distribution: 'zulu' + java-version: 17 + - name: 'Check code is formatted correctly' + uses: axel-op/googlejavaformat-action@v3 + with: + version: 1.18.1 + args: "--dry-run --set-exit-if-changed" + nix-maven: name: 'Nix: Maven' runs-on: ubuntu-20.04 - needs: version-sync + needs: format-check steps: - name: 'Check out code, set up Git' @@ -75,7 +97,7 @@ jobs: test-k: name: 'K Tests' runs-on: [self-hosted, linux, normal] - needs: version-sync + needs: format-check steps: - name: 'Check out code' uses: actions/checkout@v3 @@ -112,7 +134,7 @@ jobs: test-package-ubuntu-jammy: name: 'K Ubuntu Jammy Package' runs-on: [self-hosted, linux, normal] - needs: version-sync + needs: format-check steps: - uses: actions/checkout@v3 - name: 'Build and Test' diff --git a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackend.java b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackend.java index 610d83eef8f..9d4da4f131d 100644 --- a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackend.java +++ b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackend.java @@ -2,6 +2,12 @@ package org.kframework.backend.haskell; import com.google.inject.Inject; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.backend.kore.KoreBackend; import org.kframework.compile.Backend; @@ -9,76 +15,70 @@ import org.kframework.main.GlobalOptions; import org.kframework.main.Tool; import org.kframework.utils.Stopwatch; -import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.HashSet; - public class HaskellBackend extends KoreBackend { - private final KompileOptions kompileOptions; - private final GlobalOptions globalOptions; - private final FileUtil files; - private final HaskellKompileOptions haskellKompileOptions; - - @Inject - public HaskellBackend( - KompileOptions kompileOptions, - GlobalOptions globalOptions, - HaskellKompileOptions haskellKompileOptions, - FileUtil files, - KExceptionManager kem, - Tool tool) { - super(kompileOptions, files, kem, false, tool); - this.files = files; - this.haskellKompileOptions = haskellKompileOptions; - this.kompileOptions = kompileOptions; - this.globalOptions = globalOptions; - } + private final KompileOptions kompileOptions; + private final GlobalOptions globalOptions; + private final FileUtil files; + private final HaskellKompileOptions haskellKompileOptions; + @Inject + public HaskellBackend( + KompileOptions kompileOptions, + GlobalOptions globalOptions, + HaskellKompileOptions haskellKompileOptions, + FileUtil files, + KExceptionManager kem, + Tool tool) { + super(kompileOptions, files, kem, false, tool); + this.files = files; + this.haskellKompileOptions = haskellKompileOptions; + this.kompileOptions = kompileOptions; + this.globalOptions = globalOptions; + } - @Override - public void accept(Backend.Holder h) { - Stopwatch sw = new Stopwatch(globalOptions); - String kore = getKompiledString(h.def, true); - h.def = null; - files.saveToKompiled("definition.kore", kore); - sw.printIntermediate(" Print definition.kore"); - ProcessBuilder pb = files.getProcessBuilder(); - List args = new ArrayList<>(); - if (haskellKompileOptions.noHaskellBinary) { - args.add("kore-parser"); - args.add("--no-print-definition"); - args.add("definition.kore"); - } else { - args.add(haskellKompileOptions.haskellBackendCommand); - args.add("definition.kore"); - args.add("--module"); - args.add(kompileOptions.mainModule(files)); - args.add("--output"); - args.add("haskellDefinition.bin"); - args.add("--serialize"); - } - try { - Process p = pb.command(args).directory(files.resolveKompiled(".")).inheritIO().start(); - int exit = p.waitFor(); - if (exit != 0) { - throw KEMException.criticalError("Haskell backend reported errors validating compiled definition.\nExamine output to see errors."); - } - } catch (IOException | InterruptedException e) { - throw KEMException.criticalError("Error with I/O while executing kore-parser", e); - } - sw.printIntermediate(" Validate def"); + @Override + public void accept(Backend.Holder h) { + Stopwatch sw = new Stopwatch(globalOptions); + String kore = getKompiledString(h.def, true); + h.def = null; + files.saveToKompiled("definition.kore", kore); + sw.printIntermediate(" Print definition.kore"); + ProcessBuilder pb = files.getProcessBuilder(); + List args = new ArrayList<>(); + if (haskellKompileOptions.noHaskellBinary) { + args.add("kore-parser"); + args.add("--no-print-definition"); + args.add("definition.kore"); + } else { + args.add(haskellKompileOptions.haskellBackendCommand); + args.add("definition.kore"); + args.add("--module"); + args.add(kompileOptions.mainModule(files)); + args.add("--output"); + args.add("haskellDefinition.bin"); + args.add("--serialize"); } - - @Override - public Set excludedModuleTags() { - return new HashSet<>(Arrays.asList(Att.CONCRETE(), Att.KAST())); + try { + Process p = pb.command(args).directory(files.resolveKompiled(".")).inheritIO().start(); + int exit = p.waitFor(); + if (exit != 0) { + throw KEMException.criticalError( + "Haskell backend reported errors validating compiled definition.\n" + + "Examine output to see errors."); + } + } catch (IOException | InterruptedException e) { + throw KEMException.criticalError("Error with I/O while executing kore-parser", e); } + sw.printIntermediate(" Validate def"); + } + + @Override + public Set excludedModuleTags() { + return new HashSet<>(Arrays.asList(Att.CONCRETE(), Att.KAST())); + } } diff --git a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackendKModule.java b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackendKModule.java index d86230dbafa..7eda4dc7a61 100644 --- a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackendKModule.java +++ b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellBackendKModule.java @@ -6,80 +6,81 @@ import com.google.inject.Module; import com.google.inject.TypeLiteral; import com.google.inject.multibindings.MapBinder; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; import org.apache.commons.lang3.tuple.Pair; import org.kframework.definition.Definition; import org.kframework.main.AbstractKModule; import org.kframework.rewriter.Rewriter; -import java.util.Collections; -import java.util.List; -import java.util.function.Function; - -/** - * Created by traiansf on 9/13/18. - */ +/** Created by traiansf on 9/13/18. */ public class HaskellBackendKModule extends AbstractKModule { - @Override - public List getKompileModules() { - List mods = super.getKompileModules(); - mods.add(new AbstractModule() { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bindOptions(HaskellBackendKModule.this::kompileOptions, binder()); - installHaskellBackend(binder()); - } + @Override + public List getKompileModules() { + List mods = super.getKompileModules(); + mods.add( + new AbstractModule() { + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bindOptions(HaskellBackendKModule.this::kompileOptions, binder()); + installHaskellBackend(binder()); + } }); - return mods; - } + return mods; + } - private void installHaskellBackend(Binder binder) { - MapBinder mapBinder = MapBinder.newMapBinder( - binder, String.class, org.kframework.compile.Backend.class); - mapBinder.addBinding("haskell").to(HaskellBackend.class); - } + private void installHaskellBackend(Binder binder) { + MapBinder mapBinder = + MapBinder.newMapBinder(binder, String.class, org.kframework.compile.Backend.class); + mapBinder.addBinding("haskell").to(HaskellBackend.class); + } - @Override - public List, Boolean>> krunOptions() { - return Collections.singletonList(Pair.of(HaskellKRunOptions.class, true)); - } + @Override + public List, Boolean>> krunOptions() { + return Collections.singletonList(Pair.of(HaskellKRunOptions.class, true)); + } - @Override - public List, Boolean>> kompileOptions() { - return Collections.singletonList(Pair.of(HaskellKompileOptions.class, true)); - } + @Override + public List, Boolean>> kompileOptions() { + return Collections.singletonList(Pair.of(HaskellKompileOptions.class, true)); + } - @Override - public List getKRunModules() { - return Collections.singletonList(new AbstractModule() { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - installHaskellRewriter(binder()); - } + @Override + public List getKRunModules() { + return Collections.singletonList( + new AbstractModule() { + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + installHaskellRewriter(binder()); + } }); - } - - private void installHaskellRewriter(Binder binder) { - bindOptions(HaskellBackendKModule.this::krunOptions, binder); + } - MapBinder> rewriterBinder = MapBinder.newMapBinder( - binder, TypeLiteral.get(String.class), new TypeLiteral>() { - }); - rewriterBinder.addBinding("haskell").to(HaskellRewriter.class); - } + private void installHaskellRewriter(Binder binder) { + bindOptions(HaskellBackendKModule.this::krunOptions, binder); + MapBinder> rewriterBinder = + MapBinder.newMapBinder( + binder, + TypeLiteral.get(String.class), + new TypeLiteral>() {}); + rewriterBinder.addBinding("haskell").to(HaskellRewriter.class); + } - @Override - public List getKProveModules() { - return Collections.singletonList(new AbstractModule() { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - installHaskellBackend(binder()); - installHaskellRewriter(binder()); - } + @Override + public List getKProveModules() { + return Collections.singletonList( + new AbstractModule() { + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + installHaskellBackend(binder()); + installHaskellRewriter(binder()); + } }); - } + } } diff --git a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKRunOptions.java b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKRunOptions.java index 3a6649ef34c..aff63eface2 100644 --- a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKRunOptions.java +++ b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKRunOptions.java @@ -9,31 +9,39 @@ @RequestScoped public class HaskellKRunOptions { - @Inject - public HaskellKRunOptions() {} - - @Parameter(names="--haskell-backend-command", descriptionKey = "command", - description="Command to run the Haskell backend execution engine.", hidden = true) - public String haskellBackendCommand = "kore-exec"; - - @Parameter(names="--haskell-backend-home", descriptionKey = "directory", - description="Directory where the Haskell backend source installation resides.", hidden = true) - public String haskellBackendHome = System.getenv("KORE_HOME"); - - @Parameter(names="--default-claim-type", descriptionKey = "type", converter = SentenceTypeConverter.class, - description="Default type for claims. Values: [all-path|one-path].") - public ModuleToKORE.SentenceType defaultClaimType = ModuleToKORE.SentenceType.ALL_PATH; - - public static class SentenceTypeConverter extends BaseEnumConverter { - - public SentenceTypeConverter(String optionName) { - super(optionName); - } - - @Override - public Class enumClass() { - return ModuleToKORE.SentenceType.class; - } + @Inject + public HaskellKRunOptions() {} + + @Parameter( + names = "--haskell-backend-command", + descriptionKey = "command", + description = "Command to run the Haskell backend execution engine.", + hidden = true) + public String haskellBackendCommand = "kore-exec"; + + @Parameter( + names = "--haskell-backend-home", + descriptionKey = "directory", + description = "Directory where the Haskell backend source installation resides.", + hidden = true) + public String haskellBackendHome = System.getenv("KORE_HOME"); + + @Parameter( + names = "--default-claim-type", + descriptionKey = "type", + converter = SentenceTypeConverter.class, + description = "Default type for claims. Values: [all-path|one-path].") + public ModuleToKORE.SentenceType defaultClaimType = ModuleToKORE.SentenceType.ALL_PATH; + + public static class SentenceTypeConverter extends BaseEnumConverter { + + public SentenceTypeConverter(String optionName) { + super(optionName); } + @Override + public Class enumClass() { + return ModuleToKORE.SentenceType.class; + } + } } diff --git a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKompileOptions.java b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKompileOptions.java index 081be372136..fba09ea18bb 100644 --- a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKompileOptions.java +++ b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellKompileOptions.java @@ -8,11 +8,21 @@ @RequestScoped public class HaskellKompileOptions { - @Inject - public HaskellKompileOptions() {} - @Parameter(names="--haskell-backend-command", description="Command to run the Haskell backend execution engine.", descriptionKey = "command", hidden = true) - public String haskellBackendCommand = "kore-exec"; + @Inject + public HaskellKompileOptions() {} - @Parameter(names="--no-haskell-binary", description="Use the textual KORE format in the haskell backend instead of the binary KORE format. This is a development option, but may be necessary on MacOS due to known issues with the binary format.") - public boolean noHaskellBinary = false; + @Parameter( + names = "--haskell-backend-command", + description = "Command to run the Haskell backend execution engine.", + descriptionKey = "command", + hidden = true) + public String haskellBackendCommand = "kore-exec"; + + @Parameter( + names = "--no-haskell-binary", + description = + "Use the textual KORE format in the haskell backend instead of the binary KORE format." + + " This is a development option, but may be necessary on MacOS due to known issues" + + " with the binary format.") + public boolean noHaskellBinary = false; } diff --git a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellRewriter.java b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellRewriter.java index 0c5c7e4a435..43760f0ec54 100644 --- a/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellRewriter.java +++ b/haskell-backend/src/main/java/org/kframework/backend/haskell/HaskellRewriter.java @@ -1,7 +1,19 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.backend.haskell; +import static org.kframework.builtin.BooleanUtils.*; + import com.google.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import org.kframework.RewriterResult; import org.kframework.attributes.Att; import org.kframework.backend.kore.KoreBackend; import org.kframework.backend.kore.ModuleToKORE; @@ -26,7 +38,6 @@ import org.kframework.main.Tool; import org.kframework.parser.KoreParser; import org.kframework.parser.kore.parser.ParseError; -import org.kframework.RewriterResult; import org.kframework.rewriter.Rewriter; import org.kframework.rewriter.SearchType; import org.kframework.unparser.KPrint; @@ -39,419 +50,460 @@ import org.kframework.utils.inject.RequestScoped; import org.kframework.utils.options.BackendOptions; import org.kframework.utils.options.SMTOptions; - import scala.Tuple2; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; - -import static org.kframework.builtin.BooleanUtils.*; - @RequestScoped public record HaskellRewriter( - GlobalOptions globalOptions, - SMTOptions smtOptions, - KompileOptions kompileOptions, - KProveOptions kProveOptions, - HaskellKRunOptions haskellKRunOptions, - BackendOptions backendOptions, - FileUtil files, - CompiledDefinition def, - KExceptionManager kem, - KPrint kprint, - Tool tool -) implements Function { - - @Inject - public HaskellRewriter {} - - @Override - public Rewriter apply(Definition definition) { - Module module = definition.mainModule(); - return new Rewriter() { - @Override - public RewriterResult execute(K k, Optional depth) { - Module mod = getExecutionModule(module); - ModuleToKORE converter = new ModuleToKORE(mod, def.topCellInitializer, kompileOptions); - String koreOutput = getKoreString(k, mod, converter); - String defPath = files.resolveKompiled("haskellDefinition.bin").exists() ? - files.resolveKompiled("haskellDefinition.bin").getAbsolutePath() : - files.resolveKompiled("definition.kore").getAbsolutePath(); - String moduleName = mod.name(); - - files.saveToTemp("execute-initial.kore", koreOutput); - String pgmPath = files.resolveTemp("execute-initial.kore").getAbsolutePath(); - String[] koreCommand = haskellKRunOptions.haskellBackendCommand.split("\\s+"); - String koreDirectory = haskellKRunOptions.haskellBackendHome; - File koreOutputFile = files.resolveTemp("execute-result.kore"); - List args = new ArrayList(); - args.addAll(Arrays.asList(koreCommand)); - args.addAll(Arrays.asList( - defPath, - "--module", moduleName, - "--pattern", pgmPath, - "--output", koreOutputFile.getAbsolutePath())); - if (depth.isPresent()) { - args.add("--depth"); - args.add(Integer.toString(depth.get())); - } - if (smtOptions.smtPrelude != null) { - args.add("--smt-prelude"); - args.add(smtOptions.smtPrelude); - } - if (smtOptions.smtTimeout != null) { - args.add("--smt-timeout"); - args.add(Integer.toString(smtOptions.smtTimeout)); - } - koreCommand = args.toArray(koreCommand); - if (backendOptions.dryRun) { - System.out.println(String.join(" ", koreCommand)); - kprint.options.output = OutputModes.NONE; - return new RewriterResult(Optional.empty(), Optional.empty(), k); - } - try { - File korePath = koreDirectory == null ? null : new File(koreDirectory); - int execStatus = executeCommandBasic(korePath, koreCommand); - checkOutput(koreOutputFile, execStatus); - K outputK = new KoreParser(mod.sortAttributesFor()).parseFile(koreOutputFile); - return new RewriterResult(Optional.empty(), Optional.of(execStatus), outputK); - } catch (IOException e) { - throw KEMException.criticalError("I/O Error while executing", e); - } catch (InterruptedException e) { - throw KEMException.criticalError("Interrupted while executing", e); - } catch (ParseError parseError) { - throw KEMException.criticalError("Error parsing haskell backend output", parseError); - } - } - - @Override - public K match(K k, Rule rule) { - return search(k, Optional.of(0), Optional.empty(), rule, SearchType.STAR); - } - - @Override - public Tuple2 executeAndMatch(K k, Optional depth, Rule rule) { - RewriterResult res = execute(k, depth); - return Tuple2.apply(res, match(res.k(), rule)); - } - - @Override - public K search(K initialConfiguration, Optional depth, Optional bound, Rule pattern, SearchType searchType) { - Module mod = getExecutionModule(module); - String koreOutput = getKoreString(initialConfiguration, mod, new ModuleToKORE(mod, def.topCellInitializer, kompileOptions)); - Sort initializerSort = mod.productionsFor().get(def.topCellInitializer).get().head().sort(); - K patternTerm = RewriteToTop.toLeft(pattern.body()); - if (patternTerm instanceof KVariable) { - patternTerm = KORE.KVariable(((KVariable) patternTerm).name(), Att.empty().add(Sort.class, initializerSort)); - } - K patternCondition = pattern.requires(); - String patternTermKore = getKoreString(patternTerm, mod, new ModuleToKORE(mod, def.topCellInitializer, kompileOptions)); - String patternConditionKore; - if (patternCondition.equals(TRUE)) { - patternConditionKore = "\\top{Sort" + initializerSort.name() + "{}}()"; - } else { - patternConditionKore = - "\\equals{SortBool{},Sort" + initializerSort.name() + "{}}(" - + getKoreString(patternCondition, mod, new ModuleToKORE(mod, def.topCellInitializer, kompileOptions)) - + ", \\dv{SortBool{}}(\"true\")" - + ")"; - } - String korePatternOutput = "\\and{Sort" + initializerSort.name() + "{}}(" - + patternTermKore - + ", " + patternConditionKore - + ")"; - String defPath = files.resolveKompiled("haskellDefinition.bin").exists() ? - files.resolveKompiled("haskellDefinition.bin").getAbsolutePath() : - files.resolveKompiled("definition.kore").getAbsolutePath(); - String moduleName = mod.name(); - - files.saveToTemp("search-initial.kore", koreOutput); - String pgmPath = files.resolveTemp("search-initial.kore").getAbsolutePath(); - files.saveToTemp("search-pattern.kore", korePatternOutput); - String patternPath = files.resolveTemp("search-pattern.kore").getAbsolutePath(); - String[] koreCommand = haskellKRunOptions.haskellBackendCommand.split("\\s+"); - String koreDirectory = haskellKRunOptions.haskellBackendHome; - File koreOutputFile = files.resolveTemp("search-result.kore"); - List args = new ArrayList(); - args.addAll(Arrays.asList(koreCommand)); - args.addAll(Arrays.asList( - defPath, - "--module", moduleName, - "--pattern", pgmPath, - "--output", koreOutputFile.getAbsolutePath(), - "--searchType", searchType.toString(), - "--search", patternPath - ) - - ); - if (depth.isPresent()) { - args.add("--depth"); - args.add(depth.get().toString()); - } - if (bound.isPresent()) { - args.add("--bound"); - args.add(bound.get().toString()); - } - if (smtOptions.smtPrelude != null) { - args.add("--smt-prelude"); - args.add(smtOptions.smtPrelude); - } - if (smtOptions.smtTimeout != null) { - args.add("--smt-timeout"); - args.add(Integer.toString(smtOptions.smtTimeout)); - } - koreCommand = args.toArray(koreCommand); - if (backendOptions.dryRun) { - System.out.println(String.join(" ", koreCommand)); - kprint.options.output = OutputModes.NONE; - return initialConfiguration; - } - try { - File korePath = koreDirectory == null ? null : new File(koreDirectory); - if (executeCommandBasic(korePath, koreCommand) != 0) { - throw KEMException.criticalError("Haskell backend returned non-zero exit code"); - } - K outputK = new KoreParser(mod.sortAttributesFor()).parseFile(koreOutputFile); - outputK = addAnonymousAttributes(outputK, pattern); - return outputK; - } catch (IOException e) { - throw KEMException.criticalError("I/O Error while executing", e); - } catch (InterruptedException e) { - throw KEMException.criticalError("Interrupted while executing", e); - } catch (ParseError parseError) { - throw KEMException.criticalError("Error parsing haskell backend output", parseError); - } - } - - private K addAnonymousAttributes(K input, Rule pattern) { - Map anonVars = new HashMap<>(); - VisitK visitor = new VisitK() { - @Override - public void apply(KVariable var) { - anonVars.put(var, var); - } - }; - visitor.apply(pattern.body()); - visitor.apply(pattern.requires()); - visitor.apply(pattern.ensures()); - return new TransformK() { - @Override - public K apply(KVariable var) { - return anonVars.getOrDefault(var, var); - } - }.apply(input); - } - - private Module getExecutionModule(Module module) { - Module mod = def.executionModule(); - if (!module.equals(mod)) { - throw KEMException.criticalError("Invalid module specified for rewriting. Haskell backend only supports rewriting over" + - " the definition's main module."); - } - return mod; - } - - - private String saveKoreDefinitionToTemp(ModuleToKORE converter) { - String kompiledString = KoreBackend.getKompiledString(converter, files, false, tool); - files.saveToTemp("vdefinition.kore", kompiledString); - String defPath = files.resolveTemp("vdefinition.kore").getAbsolutePath(); - return defPath; - } - - private String saveKoreSpecToTemp(ModuleToKORE converter, Module rules) { - StringBuilder sb = new StringBuilder(); - String koreOutput = converter.convertSpecificationModule(module, rules, - haskellKRunOptions.defaultClaimType, sb); - files.saveToTemp("spec.kore", koreOutput); - return files.resolveTemp("spec.kore").getAbsolutePath(); - } - - private List buildCommonProvingCommand(String defPath, String specPath, String outPath, - String defModuleName, String specModuleName){ - String[] koreCommand; - if (kProveOptions.debugger && !haskellKRunOptions.haskellBackendCommand.equals("kore-exec")) { - throw KEMException.criticalError("Cannot pass --debugger with --haskell-backend-command."); - } else if (kProveOptions.debugger) { - koreCommand = "kore-repl".split("\\s+"); - } else { - koreCommand = haskellKRunOptions.haskellBackendCommand.split("\\s+"); - } - - List args = new ArrayList<>(); - args.addAll(Arrays.asList(koreCommand)); - args.addAll(Arrays.asList( - defPath, - "--module", defModuleName, - "--prove", specPath, - "--spec-module", specModuleName, - "--output", outPath)); - if (smtOptions.smtPrelude != null) { - args.add("--smt-prelude"); - args.add(smtOptions.smtPrelude); - } - if (smtOptions.smtTimeout != null) { - args.add("--smt-timeout"); - args.add(Integer.toString(smtOptions.smtTimeout)); - } - if (kProveOptions.debugScript != null) { - if (!kProveOptions.debugger) { - throw KEMException.criticalError("Can only use --debug-script with --debugger."); - } - args.add("--repl-script"); - args.add(files.resolveWorkingDirectory(kProveOptions.debugScript).getAbsolutePath()); - } - return args; - } - - private RewriterResult executeKoreCommands(Module rules, String[] koreCommand, - String koreDirectory, File koreOutputFile) { - int exit; - try { - File korePath = koreDirectory == null ? null : new File(koreDirectory); - exit = executeCommandBasic(korePath, koreCommand); - checkOutput(koreOutputFile, exit); - } catch (IOException e) { - throw KEMException.criticalError("I/O Error while executing", e); - } catch (InterruptedException e) { - throw KEMException.criticalError("Interrupted while executing", e); - } - K outputK; - try { - outputK = new KoreParser(rules.sortAttributesFor()) - .parseFile(koreOutputFile); - } catch (ParseError parseError) { - kem.registerCriticalWarning(ExceptionType.PROOF_LINT, "Error parsing haskell backend output", parseError); - outputK = KORE.KApply(KLabels.ML_FALSE); - } - return new RewriterResult(Optional.empty(), Optional.of(exit), outputK); - } - - @Override - public RewriterResult prove(Module rules, Boolean reuseDef) { - Module kompiledModule = KoreBackend.getKompiledModule(module, true); - ModuleToKORE converter = new ModuleToKORE(kompiledModule, def.topCellInitializer, kompileOptions, kem); - String defPath = reuseDef ? files.resolveKompiled("definition.kore").getAbsolutePath() : saveKoreDefinitionToTemp(converter); - String specPath = saveKoreSpecToTemp(converter, rules); - File koreOutputFile = files.resolveTemp("result.kore"); - - String koreDirectory = haskellKRunOptions.haskellBackendHome; + GlobalOptions globalOptions, + SMTOptions smtOptions, + KompileOptions kompileOptions, + KProveOptions kProveOptions, + HaskellKRunOptions haskellKRunOptions, + BackendOptions backendOptions, + FileUtil files, + CompiledDefinition def, + KExceptionManager kem, + KPrint kprint, + Tool tool) + implements Function { + + @Inject + public HaskellRewriter {} + + @Override + public Rewriter apply(Definition definition) { + Module module = definition.mainModule(); + return new Rewriter() { + @Override + public RewriterResult execute(K k, Optional depth) { + Module mod = getExecutionModule(module); + ModuleToKORE converter = new ModuleToKORE(mod, def.topCellInitializer, kompileOptions); + String koreOutput = getKoreString(k, mod, converter); + String defPath = + files.resolveKompiled("haskellDefinition.bin").exists() + ? files.resolveKompiled("haskellDefinition.bin").getAbsolutePath() + : files.resolveKompiled("definition.kore").getAbsolutePath(); + String moduleName = mod.name(); + + files.saveToTemp("execute-initial.kore", koreOutput); + String pgmPath = files.resolveTemp("execute-initial.kore").getAbsolutePath(); + String[] koreCommand = haskellKRunOptions.haskellBackendCommand.split("\\s+"); + String koreDirectory = haskellKRunOptions.haskellBackendHome; + File koreOutputFile = files.resolveTemp("execute-result.kore"); + List args = new ArrayList(); + args.addAll(Arrays.asList(koreCommand)); + args.addAll( + Arrays.asList( + defPath, + "--module", + moduleName, + "--pattern", + pgmPath, + "--output", + koreOutputFile.getAbsolutePath())); + if (depth.isPresent()) { + args.add("--depth"); + args.add(Integer.toString(depth.get())); + } + if (smtOptions.smtPrelude != null) { + args.add("--smt-prelude"); + args.add(smtOptions.smtPrelude); + } + if (smtOptions.smtTimeout != null) { + args.add("--smt-timeout"); + args.add(Integer.toString(smtOptions.smtTimeout)); + } + koreCommand = args.toArray(koreCommand); + if (backendOptions.dryRun) { + System.out.println(String.join(" ", koreCommand)); + kprint.options.output = OutputModes.NONE; + return new RewriterResult(Optional.empty(), Optional.empty(), k); + } + try { + File korePath = koreDirectory == null ? null : new File(koreDirectory); + int execStatus = executeCommandBasic(korePath, koreCommand); + checkOutput(koreOutputFile, execStatus); + K outputK = new KoreParser(mod.sortAttributesFor()).parseFile(koreOutputFile); + return new RewriterResult(Optional.empty(), Optional.of(execStatus), outputK); + } catch (IOException e) { + throw KEMException.criticalError("I/O Error while executing", e); + } catch (InterruptedException e) { + throw KEMException.criticalError("Interrupted while executing", e); + } catch (ParseError parseError) { + throw KEMException.criticalError("Error parsing haskell backend output", parseError); + } + } + + @Override + public K match(K k, Rule rule) { + return search(k, Optional.of(0), Optional.empty(), rule, SearchType.STAR); + } + + @Override + public Tuple2 executeAndMatch(K k, Optional depth, Rule rule) { + RewriterResult res = execute(k, depth); + return Tuple2.apply(res, match(res.k(), rule)); + } + + @Override + public K search( + K initialConfiguration, + Optional depth, + Optional bound, + Rule pattern, + SearchType searchType) { + Module mod = getExecutionModule(module); + String koreOutput = + getKoreString( + initialConfiguration, + mod, + new ModuleToKORE(mod, def.topCellInitializer, kompileOptions)); + Sort initializerSort = mod.productionsFor().get(def.topCellInitializer).get().head().sort(); + K patternTerm = RewriteToTop.toLeft(pattern.body()); + if (patternTerm instanceof KVariable) { + patternTerm = + KORE.KVariable( + ((KVariable) patternTerm).name(), Att.empty().add(Sort.class, initializerSort)); + } + K patternCondition = pattern.requires(); + String patternTermKore = + getKoreString( + patternTerm, mod, new ModuleToKORE(mod, def.topCellInitializer, kompileOptions)); + String patternConditionKore; + if (patternCondition.equals(TRUE)) { + patternConditionKore = "\\top{Sort" + initializerSort.name() + "{}}()"; + } else { + patternConditionKore = + "\\equals{SortBool{},Sort" + + initializerSort.name() + + "{}}(" + + getKoreString( + patternCondition, + mod, + new ModuleToKORE(mod, def.topCellInitializer, kompileOptions)) + + ", \\dv{SortBool{}}(\"true\")" + + ")"; + } + String korePatternOutput = + "\\and{Sort" + + initializerSort.name() + + "{}}(" + + patternTermKore + + ", " + + patternConditionKore + + ")"; + String defPath = + files.resolveKompiled("haskellDefinition.bin").exists() + ? files.resolveKompiled("haskellDefinition.bin").getAbsolutePath() + : files.resolveKompiled("definition.kore").getAbsolutePath(); + String moduleName = mod.name(); + + files.saveToTemp("search-initial.kore", koreOutput); + String pgmPath = files.resolveTemp("search-initial.kore").getAbsolutePath(); + files.saveToTemp("search-pattern.kore", korePatternOutput); + String patternPath = files.resolveTemp("search-pattern.kore").getAbsolutePath(); + String[] koreCommand = haskellKRunOptions.haskellBackendCommand.split("\\s+"); + String koreDirectory = haskellKRunOptions.haskellBackendHome; + File koreOutputFile = files.resolveTemp("search-result.kore"); + List args = new ArrayList(); + args.addAll(Arrays.asList(koreCommand)); + args.addAll( + Arrays.asList( + defPath, + "--module", + moduleName, + "--pattern", + pgmPath, + "--output", + koreOutputFile.getAbsolutePath(), + "--searchType", + searchType.toString(), + "--search", + patternPath)); + if (depth.isPresent()) { + args.add("--depth"); + args.add(depth.get().toString()); + } + if (bound.isPresent()) { + args.add("--bound"); + args.add(bound.get().toString()); + } + if (smtOptions.smtPrelude != null) { + args.add("--smt-prelude"); + args.add(smtOptions.smtPrelude); + } + if (smtOptions.smtTimeout != null) { + args.add("--smt-timeout"); + args.add(Integer.toString(smtOptions.smtTimeout)); + } + koreCommand = args.toArray(koreCommand); + if (backendOptions.dryRun) { + System.out.println(String.join(" ", koreCommand)); + kprint.options.output = OutputModes.NONE; + return initialConfiguration; + } + try { + File korePath = koreDirectory == null ? null : new File(koreDirectory); + if (executeCommandBasic(korePath, koreCommand) != 0) { + throw KEMException.criticalError("Haskell backend returned non-zero exit code"); + } + K outputK = new KoreParser(mod.sortAttributesFor()).parseFile(koreOutputFile); + outputK = addAnonymousAttributes(outputK, pattern); + return outputK; + } catch (IOException e) { + throw KEMException.criticalError("I/O Error while executing", e); + } catch (InterruptedException e) { + throw KEMException.criticalError("Interrupted while executing", e); + } catch (ParseError parseError) { + throw KEMException.criticalError("Error parsing haskell backend output", parseError); + } + } + + private K addAnonymousAttributes(K input, Rule pattern) { + Map anonVars = new HashMap<>(); + VisitK visitor = + new VisitK() { + @Override + public void apply(KVariable var) { + anonVars.put(var, var); + } + }; + visitor.apply(pattern.body()); + visitor.apply(pattern.requires()); + visitor.apply(pattern.ensures()); + return new TransformK() { + @Override + public K apply(KVariable var) { + return anonVars.getOrDefault(var, var); + } + }.apply(input); + } + + private Module getExecutionModule(Module module) { + Module mod = def.executionModule(); + if (!module.equals(mod)) { + throw KEMException.criticalError( + "Invalid module specified for rewriting. Haskell backend only supports rewriting over" + + " the definition's main module."); + } + return mod; + } - String defModuleName = def.executionModule().name(); - String specModuleName = kProveOptions.specModule == null ? rules.name() : kProveOptions.specModule; + private String saveKoreDefinitionToTemp(ModuleToKORE converter) { + String kompiledString = KoreBackend.getKompiledString(converter, files, false, tool); + files.saveToTemp("vdefinition.kore", kompiledString); + String defPath = files.resolveTemp("vdefinition.kore").getAbsolutePath(); + return defPath; + } - List args = buildCommonProvingCommand(defPath, specPath, koreOutputFile.getAbsolutePath(), - defModuleName, specModuleName); + private String saveKoreSpecToTemp(ModuleToKORE converter, Module rules) { + StringBuilder sb = new StringBuilder(); + String koreOutput = + converter.convertSpecificationModule( + module, rules, haskellKRunOptions.defaultClaimType, sb); + files.saveToTemp("spec.kore", koreOutput); + return files.resolveTemp("spec.kore").getAbsolutePath(); + } + + private List buildCommonProvingCommand( + String defPath, + String specPath, + String outPath, + String defModuleName, + String specModuleName) { + String[] koreCommand; + if (kProveOptions.debugger + && !haskellKRunOptions.haskellBackendCommand.equals("kore-exec")) { + throw KEMException.criticalError( + "Cannot pass --debugger with --haskell-backend-command."); + } else if (kProveOptions.debugger) { + koreCommand = "kore-repl".split("\\s+"); + } else { + koreCommand = haskellKRunOptions.haskellBackendCommand.split("\\s+"); + } - if (kProveOptions.depth != null) { - args.addAll(Arrays.asList( - "--depth", kProveOptions.depth.toString())); - } - if (kProveOptions.branchingAllowed != Integer.MAX_VALUE) { - args.add("--breadth"); - args.add(String.valueOf(kProveOptions.branchingAllowed)); - } - String[] koreCommand = args.toArray(new String[args.size()]); - if (backendOptions.dryRun) { - globalOptions.debugWarnings = true; // sets this so the kprove directory is not removed. - System.out.println(String.join(" ", koreCommand)); - kprint.options.output = OutputModes.NONE; - return new RewriterResult(Optional.empty(), Optional.of(0),KORE.KApply(KLabels.ML_FALSE)); - } - if (globalOptions.verbose) { - System.err.println("Executing " + args); - } + List args = new ArrayList<>(); + args.addAll(Arrays.asList(koreCommand)); + args.addAll( + Arrays.asList( + defPath, + "--module", + defModuleName, + "--prove", + specPath, + "--spec-module", + specModuleName, + "--output", + outPath)); + if (smtOptions.smtPrelude != null) { + args.add("--smt-prelude"); + args.add(smtOptions.smtPrelude); + } + if (smtOptions.smtTimeout != null) { + args.add("--smt-timeout"); + args.add(Integer.toString(smtOptions.smtTimeout)); + } + if (kProveOptions.debugScript != null) { + if (!kProveOptions.debugger) { + throw KEMException.criticalError("Can only use --debug-script with --debugger."); + } + args.add("--repl-script"); + args.add(files.resolveWorkingDirectory(kProveOptions.debugScript).getAbsolutePath()); + } + return args; + } - return executeKoreCommands(rules, koreCommand, koreDirectory, koreOutputFile); - } + private RewriterResult executeKoreCommands( + Module rules, String[] koreCommand, String koreDirectory, File koreOutputFile) { + int exit; + try { + File korePath = koreDirectory == null ? null : new File(koreDirectory); + exit = executeCommandBasic(korePath, koreCommand); + checkOutput(koreOutputFile, exit); + } catch (IOException e) { + throw KEMException.criticalError("I/O Error while executing", e); + } catch (InterruptedException e) { + throw KEMException.criticalError("Interrupted while executing", e); + } + K outputK; + try { + outputK = new KoreParser(rules.sortAttributesFor()).parseFile(koreOutputFile); + } catch (ParseError parseError) { + kem.registerCriticalWarning( + ExceptionType.PROOF_LINT, "Error parsing haskell backend output", parseError); + outputK = KORE.KApply(KLabels.ML_FALSE); + } + return new RewriterResult(Optional.empty(), Optional.of(exit), outputK); + } + + @Override + public RewriterResult prove(Module rules, Boolean reuseDef) { + Module kompiledModule = KoreBackend.getKompiledModule(module, true); + ModuleToKORE converter = + new ModuleToKORE(kompiledModule, def.topCellInitializer, kompileOptions, kem); + String defPath = + reuseDef + ? files.resolveKompiled("definition.kore").getAbsolutePath() + : saveKoreDefinitionToTemp(converter); + String specPath = saveKoreSpecToTemp(converter, rules); + File koreOutputFile = files.resolveTemp("result.kore"); + + String koreDirectory = haskellKRunOptions.haskellBackendHome; + + String defModuleName = def.executionModule().name(); + String specModuleName = + kProveOptions.specModule == null ? rules.name() : kProveOptions.specModule; + + List args = + buildCommonProvingCommand( + defPath, specPath, koreOutputFile.getAbsolutePath(), defModuleName, specModuleName); + + if (kProveOptions.depth != null) { + args.addAll(Arrays.asList("--depth", kProveOptions.depth.toString())); + } + if (kProveOptions.branchingAllowed != Integer.MAX_VALUE) { + args.add("--breadth"); + args.add(String.valueOf(kProveOptions.branchingAllowed)); + } + String[] koreCommand = args.toArray(new String[args.size()]); + if (backendOptions.dryRun) { + globalOptions.debugWarnings = true; // sets this so the kprove directory is not removed. + System.out.println(String.join(" ", koreCommand)); + kprint.options.output = OutputModes.NONE; + return new RewriterResult( + Optional.empty(), Optional.of(0), KORE.KApply(KLabels.ML_FALSE)); + } + if (globalOptions.verbose) { + System.err.println("Executing " + args); + } - @Override - public boolean equivalence(Rewriter firstDef, Rewriter secondDef, Module firstSpec, Module secondSpec) { - throw new UnsupportedOperationException(); - } - }; + return executeKoreCommands(rules, koreCommand, koreDirectory, koreOutputFile); + } + + @Override + public boolean equivalence( + Rewriter firstDef, Rewriter secondDef, Module firstSpec, Module secondSpec) { + throw new UnsupportedOperationException(); + } + }; + } + + private void checkOutput(File koreOutputFile, int execStatus) { + if (execStatus != 0) { + if (!koreOutputFile.isFile()) { + throw KEMException.criticalError( + "Haskell Backend execution failed with code " + + execStatus + + " and produced no output."); + } } - - private void checkOutput(File koreOutputFile, int execStatus) { - if (execStatus != 0) { - if (!koreOutputFile.isFile()) { - throw KEMException.criticalError("Haskell Backend execution failed with code " + execStatus - + " and produced no output."); - } - } + } + + private String getKoreString(K initialConfiguration, Module mod, ModuleToKORE converter) { + ExpandMacros macroExpander = ExpandMacros.forNonSentences(mod, files, kompileOptions, false); + K withMacros = macroExpander.expand(initialConfiguration); + K kWithInjections = new AddSortInjections(mod).addInjections(withMacros); + StringBuilder sb = new StringBuilder(); + converter.convert(kWithInjections, sb); + return sb.toString(); + } + + /** + * Runs a command in the given directory, + * + * @param workingDir directory to run in + * @param command commandline to run + * @return + * @throws IOException + * @throws InterruptedException + */ + private int executeCommandBasic(File workingDir, String... command) + throws IOException, InterruptedException { + if (globalOptions.verbose) { + System.err.println("Executing command: " + String.join(" ", Arrays.asList(command))); } - - private String getKoreString(K initialConfiguration, Module mod, ModuleToKORE converter) { - ExpandMacros macroExpander = ExpandMacros.forNonSentences(mod, files, kompileOptions, false); - K withMacros = macroExpander.expand(initialConfiguration); - K kWithInjections = new AddSortInjections(mod).addInjections(withMacros); - StringBuilder sb = new StringBuilder(); - converter.convert(kWithInjections, sb); - return sb.toString(); + int exit; + ProcessBuilder pb = files.getProcessBuilder().command(command); + if (workingDir != null) { + pb.directory(workingDir); } + if (Main.isNailgun()) { + Process p2 = pb.start(); - /** - * Runs a command in the given directory, - * @param workingDir directory to run in - * @param command commandline to run - * @return - * @throws IOException - * @throws InterruptedException - */ - private int executeCommandBasic(File workingDir, String... command) throws IOException, InterruptedException { - if (globalOptions.verbose) { - System.err.println("Executing command: " + String.join(" ", Arrays.asList(command))); - } - int exit; - ProcessBuilder pb = files.getProcessBuilder() - .command(command); - if (workingDir != null) { - pb.directory(workingDir); - } - if (Main.isNailgun()) { - - Process p2 = pb.start(); - - Thread in = new Thread(() -> { + Thread in = + new Thread( + () -> { int count; byte[] buffer = new byte[8192]; try { - while (true) { - count = System.in.read(buffer); - if (count < 0) - break; - p2.getOutputStream().write(buffer, 0, count); - p2.getOutputStream().flush(); - } - } catch (IOException ignored) {} - }); - Thread out = RunProcess.getOutputStreamThread(p2::getInputStream, System.out); - Thread err = RunProcess.getOutputStreamThread(p2::getErrorStream, System.err); - in.start(); - out.start(); - err.start(); - - exit = p2.waitFor(); - in.interrupt(); - in.join(); - out.join(); - err.join(); - System.out.flush(); - System.err.flush(); - return exit; - } else { - // if we're not nailgun, we can't do the above because System.in won't be interruptible, - // and we don't really want or need to anyway. - return pb.inheritIO().start().waitFor(); - } + while (true) { + count = System.in.read(buffer); + if (count < 0) break; + p2.getOutputStream().write(buffer, 0, count); + p2.getOutputStream().flush(); + } + } catch (IOException ignored) { + } + }); + Thread out = RunProcess.getOutputStreamThread(p2::getInputStream, System.out); + Thread err = RunProcess.getOutputStreamThread(p2::getErrorStream, System.err); + in.start(); + out.start(); + err.start(); + + exit = p2.waitFor(); + in.interrupt(); + in.join(); + out.join(); + err.join(); + System.out.flush(); + System.err.flush(); + return exit; + } else { + // if we're not nailgun, we can't do the above because System.in won't be interruptible, + // and we don't really want or need to anyway. + return pb.inheritIO().start().waitFor(); } + } } - diff --git a/k-distribution/src/test/java/org/kframework/kore/convertors/BaseTest.java b/k-distribution/src/test/java/org/kframework/kore/convertors/BaseTest.java index 7cebecbbefe..20fc21dea5d 100644 --- a/k-distribution/src/test/java/org/kframework/kore/convertors/BaseTest.java +++ b/k-distribution/src/test/java/org/kframework/kore/convertors/BaseTest.java @@ -2,109 +2,111 @@ package org.kframework.kore.convertors; +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Calendar; +import java.util.function.Function; import org.apache.commons.io.FileUtils; import org.junit.Rule; import org.junit.rules.TestName; import org.kframework.attributes.Source; import org.kframework.compile.ProcessGroupAttributes; import org.kframework.kil.Definition; -import org.kframework.parser.inner.CollectProductionsVisitor; import org.kframework.kil.loader.Context; +import org.kframework.parser.inner.CollectProductionsVisitor; import org.kframework.parser.outer.Outer; -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Calendar; -import java.util.function.Function; - -import static org.junit.Assert.assertEquals; - public abstract class BaseTest { - private static final String COPYRIGHT_HEADER = "// Copyright (c) " + Calendar.getInstance().get(Calendar.YEAR) + " K Team. All Rights Reserved."; - private static final String COPYRIGHT_HEADER_REGEX = "// Copyright \\(c\\) [0-9\\-]* K Team. All Rights Reserved."; + private static final String COPYRIGHT_HEADER = + "// Copyright (c) " + + Calendar.getInstance().get(Calendar.YEAR) + + " K Team. All Rights Reserved."; + private static final String COPYRIGHT_HEADER_REGEX = + "// Copyright \\(c\\) [0-9\\-]* K Team. All Rights Reserved."; - @Rule - public TestName name = new TestName(); + @Rule public TestName name = new TestName(); - public BaseTest() { - super(); - } + public BaseTest() { + super(); + } - protected void outerOnlyTest() throws IOException { - testConversion(this::parseUsingOuter); - } + protected void outerOnlyTest() throws IOException { + testConversion(this::parseUsingOuter); + } - public static class DefinitionWithContext { - public final Definition definition; - public final Context context; + public static class DefinitionWithContext { + public final Definition definition; + public final Context context; - public DefinitionWithContext(Definition d, Context c) { - this.definition = d; - this.context = c; - new CollectProductionsVisitor(c).visit(d); - } + public DefinitionWithContext(Definition d, Context c) { + this.definition = d; + this.context = c; + new CollectProductionsVisitor(c).visit(d); } + } - protected File testResource(String baseName) { - return new File("src/test/resources" + baseName); - // a bit of a hack to get around not having a clear working directory - // Eclipse runs tests within k/k-distribution, IntelliJ within /k - } + protected File testResource(String baseName) { + return new File("src/test/resources" + baseName); + // a bit of a hack to get around not having a clear working directory + // Eclipse runs tests within k/k-distribution, IntelliJ within /k + } - // WARNING: only use this after checking the results manually - private static final boolean forceFixAssertionFiles = false; + // WARNING: only use this after checking the results manually + private static final boolean forceFixAssertionFiles = false; - private void testConversion(Function parse) throws IOException { - File kilDefinitionFile = testResource("/convertor-tests/" + name.getMethodName() + ".k"); - File kilExpectedDefinitionFile = testResource("/convertor-tests/" + name.getMethodName() + expectedFilePostfix()); + private void testConversion(Function parse) throws IOException { + File kilDefinitionFile = testResource("/convertor-tests/" + name.getMethodName() + ".k"); + File kilExpectedDefinitionFile = + testResource("/convertor-tests/" + name.getMethodName() + expectedFilePostfix()); - DefinitionWithContext defWithContext = parse.apply(kilDefinitionFile); + DefinitionWithContext defWithContext = parse.apply(kilDefinitionFile); - String actualOutput = convert(defWithContext); + String actualOutput = convert(defWithContext); - if (forceFixAssertionFiles) { - PrintWriter printWriter = new PrintWriter(kilExpectedDefinitionFile); - String sep = "\n"; - if (actualOutput.startsWith("\n")) - sep = ""; + if (forceFixAssertionFiles) { + PrintWriter printWriter = new PrintWriter(kilExpectedDefinitionFile); + String sep = "\n"; + if (actualOutput.startsWith("\n")) sep = ""; - actualOutput = actualOutput.replaceAll(" +\n", "\n"); + actualOutput = actualOutput.replaceAll(" +\n", "\n"); - printWriter.print(COPYRIGHT_HEADER + sep + actualOutput + "\n"); - printWriter.close(); - } else { - String expectedOutput = FileUtils.readFileToString(kilExpectedDefinitionFile).replaceAll("\r\n", "\n"); - // fixing Windows line endings (git autocrlf=auto generates Windows line endings on checkout) + printWriter.print(COPYRIGHT_HEADER + sep + actualOutput + "\n"); + printWriter.close(); + } else { + String expectedOutput = + FileUtils.readFileToString(kilExpectedDefinitionFile).replaceAll("\r\n", "\n"); + // fixing Windows line endings (git autocrlf=auto generates Windows line endings on checkout) - assertEquals(clean(expectedOutput), clean(actualOutput)); - } + assertEquals(clean(expectedOutput), clean(actualOutput)); } + } - protected abstract String convert(DefinitionWithContext defWithContext); - - protected abstract String expectedFilePostfix(); - - protected DefinitionWithContext parseUsingOuter(File definitionFile) { - Definition def = new Definition(); - String definitionText; - try { - definitionText = FileUtils.readFileToString(definitionFile); - } catch (IOException e) { - throw new RuntimeException(e); - } - def.setItems(Outer.parse(Source.apply(definitionFile.getPath()), definitionText, null)); - def.setMainModule("TEST"); - def.setMainSyntaxModule("TEST"); - - ProcessGroupAttributes.apply(def); - Context context = new Context(); - return new DefinitionWithContext(def, context); - } + protected abstract String convert(DefinitionWithContext defWithContext); - private String clean(String definitionText) { - return definitionText.replaceAll(COPYRIGHT_HEADER_REGEX, "").replaceAll(" *\n", "\n").trim(); - } + protected abstract String expectedFilePostfix(); + protected DefinitionWithContext parseUsingOuter(File definitionFile) { + Definition def = new Definition(); + String definitionText; + try { + definitionText = FileUtils.readFileToString(definitionFile); + } catch (IOException e) { + throw new RuntimeException(e); + } + def.setItems(Outer.parse(Source.apply(definitionFile.getPath()), definitionText, null)); + def.setMainModule("TEST"); + def.setMainSyntaxModule("TEST"); + + ProcessGroupAttributes.apply(def); + Context context = new Context(); + return new DefinitionWithContext(def, context); + } + + private String clean(String definitionText) { + return definitionText.replaceAll(COPYRIGHT_HEADER_REGEX, "").replaceAll(" *\n", "\n").trim(); + } } diff --git a/k-distribution/src/test/java/org/kframework/kore/convertors/TstKILtoKOREIT.java b/k-distribution/src/test/java/org/kframework/kore/convertors/TstKILtoKOREIT.java index 5448cb26827..03ea8aac08d 100644 --- a/k-distribution/src/test/java/org/kframework/kore/convertors/TstKILtoKOREIT.java +++ b/k-distribution/src/test/java/org/kframework/kore/convertors/TstKILtoKOREIT.java @@ -2,64 +2,71 @@ package org.kframework.kore.convertors; +import java.io.IOException; import org.junit.FixMethodOrder; import org.junit.Ignore; import org.junit.Test; import org.junit.runners.MethodSorters; -import java.io.IOException; - @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class TstKILtoKOREIT extends BaseTest { - @Test @Ignore - public void emptyModule() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void emptyModule() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void simpleSyntax() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void simpleSyntax() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void syntaxWithAttributes() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void syntaxWithAttributes() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void syntaxWithRhs() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void syntaxWithRhs() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void imports() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void imports() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void syntaxPriorities() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void syntaxPriorities() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void syntaxWithPriorities() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void syntaxWithPriorities() throws IOException { + outerOnlyTest(); + } - @Test @Ignore - public void syntaxWithOR() throws IOException { - outerOnlyTest(); - } + @Test + @Ignore + public void syntaxWithOR() throws IOException { + outerOnlyTest(); + } - protected String convert(DefinitionWithContext defWithContext) { - KILtoKORE kilToKore = new KILtoKORE(defWithContext.context, false, false); - org.kframework.definition.Definition koreDef = kilToKore.apply(defWithContext.definition); - String koreDefString = koreDef.toString(); - return koreDefString; - } + protected String convert(DefinitionWithContext defWithContext) { + KILtoKORE kilToKore = new KILtoKORE(defWithContext.context, false, false); + org.kframework.definition.Definition koreDef = kilToKore.apply(defWithContext.definition); + String koreDefString = koreDef.toString(); + return koreDefString; + } - protected String expectedFilePostfix() { - return "-expected.k"; - } + protected String expectedFilePostfix() { + return "-expected.k"; + } } diff --git a/kernel/src/main/java/com/davekoelle/AlphanumComparator.java b/kernel/src/main/java/com/davekoelle/AlphanumComparator.java index 7bb24b20402..da8e2491046 100644 --- a/kernel/src/main/java/com/davekoelle/AlphanumComparator.java +++ b/kernel/src/main/java/com/davekoelle/AlphanumComparator.java @@ -27,106 +27,86 @@ import java.util.Comparator; /** - * This is an updated version with enhancements made by Daniel Migowski, - * Andre Bogus, and David Koelle + * This is an updated version with enhancements made by Daniel Migowski, Andre Bogus, and David + * Koelle * - * To convert to use Templates (Java 1.5+): - * - Change "implements Comparator" to "implements Comparator" - * - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)" - * - Remove the type checking and casting in compare(). + *

To convert to use Templates (Java 1.5+): - Change "implements Comparator" to "implements + * Comparator" - Change "compare(Object o1, Object o2)" to "compare(String s1, String s2)" - + * Remove the type checking and casting in compare(). * - * To use this class: - * Use the static "sort" method from the java.util.Collections class: - * Collections.sort(your list, new AlphanumComparator()); + *

To use this class: Use the static "sort" method from the java.util.Collections class: + * Collections.sort(your list, new AlphanumComparator()); */ -public class AlphanumComparator implements Comparator -{ - private final boolean isDigit(char ch) - { - return ch >= 48 && ch <= 57; - } +public class AlphanumComparator implements Comparator { + private final boolean isDigit(char ch) { + return ch >= 48 && ch <= 57; + } - /** Length of string is passed in for improved efficiency (only need to calculate it once) **/ - private final String getChunk(String s, int slength, int marker) - { - StringBuilder chunk = new StringBuilder(); - char c = s.charAt(marker); + /** Length of string is passed in for improved efficiency (only need to calculate it once) * */ + private final String getChunk(String s, int slength, int marker) { + StringBuilder chunk = new StringBuilder(); + char c = s.charAt(marker); + chunk.append(c); + marker++; + if (isDigit(c)) { + while (marker < slength) { + c = s.charAt(marker); + if (!isDigit(c)) break; chunk.append(c); marker++; - if (isDigit(c)) - { - while (marker < slength) - { - c = s.charAt(marker); - if (!isDigit(c)) - break; - chunk.append(c); - marker++; - } - } else - { - while (marker < slength) - { - c = s.charAt(marker); - if (isDigit(c)) - break; - chunk.append(c); - marker++; - } - } - return chunk.toString(); + } + } else { + while (marker < slength) { + c = s.charAt(marker); + if (isDigit(c)) break; + chunk.append(c); + marker++; + } } + return chunk.toString(); + } - public int compare(String o1, String o2) - { - if (!(o1 instanceof String) || !(o2 instanceof String)) - { - return 0; - } - String s1 = o1; - String s2 = o2; + public int compare(String o1, String o2) { + if (!(o1 instanceof String) || !(o2 instanceof String)) { + return 0; + } + String s1 = o1; + String s2 = o2; - int thisMarker = 0; - int thatMarker = 0; - int s1Length = s1.length(); - int s2Length = s2.length(); + int thisMarker = 0; + int thatMarker = 0; + int s1Length = s1.length(); + int s2Length = s2.length(); - while (thisMarker < s1Length && thatMarker < s2Length) - { - String thisChunk = getChunk(s1, s1Length, thisMarker); - thisMarker += thisChunk.length(); + while (thisMarker < s1Length && thatMarker < s2Length) { + String thisChunk = getChunk(s1, s1Length, thisMarker); + thisMarker += thisChunk.length(); - String thatChunk = getChunk(s2, s2Length, thatMarker); - thatMarker += thatChunk.length(); + String thatChunk = getChunk(s2, s2Length, thatMarker); + thatMarker += thatChunk.length(); - // If both chunks contain numeric characters, sort them numerically - int result = 0; - if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) - { - // Simple chunk comparison by length. - int thisChunkLength = thisChunk.length(); - result = thisChunkLength - thatChunk.length(); - // If equal, the first different number counts - if (result == 0) - { - for (int i = 0; i < thisChunkLength; i++) - { - result = thisChunk.charAt(i) - thatChunk.charAt(i); - if (result != 0) - { - return result; - } - } - } - } else - { - result = thisChunk.compareTo(thatChunk); + // If both chunks contain numeric characters, sort them numerically + int result = 0; + if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) { + // Simple chunk comparison by length. + int thisChunkLength = thisChunk.length(); + result = thisChunkLength - thatChunk.length(); + // If equal, the first different number counts + if (result == 0) { + for (int i = 0; i < thisChunkLength; i++) { + result = thisChunk.charAt(i) - thatChunk.charAt(i); + if (result != 0) { + return result; } - - if (result != 0) - return result; + } } + } else { + result = thisChunk.compareTo(thatChunk); + } - return s1Length - s2Length; + if (result != 0) return result; } + + return s1Length - s2Length; + } } diff --git a/kernel/src/main/java/org/kframework/backend/Backends.java b/kernel/src/main/java/org/kframework/backend/Backends.java index 00ec358b18f..1877bb898fb 100644 --- a/kernel/src/main/java/org/kframework/backend/Backends.java +++ b/kernel/src/main/java/org/kframework/backend/Backends.java @@ -3,8 +3,8 @@ public class Backends { - public static final String PDF = "pdf"; - public static final String HTML = "html"; - public static final String HASKELL = "haskell"; - public static final String LLVM = "llvm"; + public static final String PDF = "pdf"; + public static final String HTML = "html"; + public static final String HASKELL = "haskell"; + public static final String LLVM = "llvm"; } diff --git a/kernel/src/main/java/org/kframework/backend/PosterBackend.java b/kernel/src/main/java/org/kframework/backend/PosterBackend.java index e6eb54af744..4aa49a5c831 100644 --- a/kernel/src/main/java/org/kframework/backend/PosterBackend.java +++ b/kernel/src/main/java/org/kframework/backend/PosterBackend.java @@ -7,14 +7,13 @@ public abstract class PosterBackend { - protected final Stopwatch sw; - protected final Context context; + protected final Stopwatch sw; + protected final Context context; - public PosterBackend(Stopwatch sw, Context context) { - this.sw = sw; - this.context = context; - } - - public abstract void run(Definition def); + public PosterBackend(Stopwatch sw, Context context) { + this.sw = sw; + this.context = context; + } + public abstract void run(Definition def); } diff --git a/kernel/src/main/java/org/kframework/backend/kore/ConstructorChecks.java b/kernel/src/main/java/org/kframework/backend/kore/ConstructorChecks.java index 7e058f2e729..56f195c5a73 100644 --- a/kernel/src/main/java/org/kframework/backend/kore/ConstructorChecks.java +++ b/kernel/src/main/java/org/kframework/backend/kore/ConstructorChecks.java @@ -14,85 +14,99 @@ import scala.collection.Set; public class ConstructorChecks { - private final Module module; + private final Module module; - public ConstructorChecks(Module m) { - module = m; - } + public ConstructorChecks(Module m) { + module = m; + } - /** - * Checks whether a lhs pattern is constructor-based, i.e., an application of a - * function symbol to a list of constructor terms. - * - * @param term - * @return - */ - public boolean isConstructorBased(K term) { - if (term instanceof KApply) { - return ((KApply) term).klist().items().stream().allMatch(this::isConstructorTerm); - } - if (term instanceof KAs) { - return isConstructorBased(((KAs) term).pattern()); - } - KException.criticalError("Unexpecting isConstructorBased call on " + term.getClass()); - return false; + /** + * Checks whether a lhs pattern is constructor-based, i.e., an application of a function symbol to + * a list of constructor terms. + * + * @param term + * @return + */ + public boolean isConstructorBased(K term) { + if (term instanceof KApply) { + return ((KApply) term).klist().items().stream().allMatch(this::isConstructorTerm); } - - /** - * Checks whether a pattern is a constructor term, i.e., - * it is not formed by means of reducible symbols (functions). - * - * @param term - * @return - */ - public boolean isConstructorTerm(K term) { - return (new FoldK() { - @Override - public Boolean unit() { - return true; - } - - @Override - public Boolean merge(Boolean a, Boolean b) { - return a && b; - } - - @Override - public Boolean apply(KApply k) { - return isConstructorLike(k.klabel()) && super.apply(k); - } - }).apply(term); + if (term instanceof KAs) { + return isConstructorBased(((KAs) term).pattern()); } + KException.criticalError("Unexpecting isConstructorBased call on " + term.getClass()); + return false; + } - // the functions below could be moved to a common place and made public + /** + * Checks whether a pattern is a constructor term, i.e., it is not formed by means of reducible + * symbols (functions). + * + * @param term + * @return + */ + public boolean isConstructorTerm(K term) { + return (new FoldK() { + @Override + public Boolean unit() { + return true; + } - private boolean isConstructorLike(KLabel klabel) { - String labelName = klabel.name(); - if (isBuiltinLabel(klabel)) return false; - if (isInjectionLabel(labelName) || isBuiltinModuloConstructor(klabel)) return true; - Set productionSet = module.productionsFor().apply(klabel.head()); - assert productionSet.size() == 1 : "Should not have more than one production"; - Production production = productionSet.head(); - return !production.att().contains(Att.FUNCTION()); - } + @Override + public Boolean merge(Boolean a, Boolean b) { + return a && b; + } - public static boolean isBuiltinLabel(KLabel label) { - return label.name().equals(KLabels.ML_FALSE.name()) || label.name().equals(KLabels.ML_TRUE.name()) || label.name().equals(KLabels.ML_NOT.name()) || - label.name().equals(KLabels.ML_OR.name()) || label.name().equals(KLabels.ML_AND.name()) || label.name().equals(KLabels.ML_IMPLIES.name()) || - label.name().equals(KLabels.ML_EQUALS.name()) || label.name().equals(KLabels.ML_CEIL.name()) || label.name().equals(KLabels.ML_FLOOR.name()) || - label.name().equals(KLabels.ML_EXISTS.name()) || label.name().equals(KLabels.ML_FORALL.name()) || label.name().equals(KLabels.CTL_AG.name()) || - label.name().equals(KLabels.RL_wEF.name()) || label.name().equals(KLabels.RL_wAF.name()); - } + @Override + public Boolean apply(KApply k) { + return isConstructorLike(k.klabel()) && super.apply(k); + } + }) + .apply(term); + } - private boolean isBuiltinModuloConstructor(KLabel label) { - return label.equals(KLabels.DotMap) || label.equals(KLabels.Map) || label.equals(KLabels.MapItem) || - label.equals(KLabels.DotList) || label.equals(KLabels.List) || label.equals(KLabels.ListItem) || - label.equals(KLabels.DotSet) || label.equals(KLabels.Set) || label.equals(KLabels.SetItem); - } + // the functions below could be moved to a common place and made public - private boolean isInjectionLabel(String labelName) { - return labelName.equals(KLabels.INJ); - } + private boolean isConstructorLike(KLabel klabel) { + String labelName = klabel.name(); + if (isBuiltinLabel(klabel)) return false; + if (isInjectionLabel(labelName) || isBuiltinModuloConstructor(klabel)) return true; + Set productionSet = module.productionsFor().apply(klabel.head()); + assert productionSet.size() == 1 : "Should not have more than one production"; + Production production = productionSet.head(); + return !production.att().contains(Att.FUNCTION()); + } + + public static boolean isBuiltinLabel(KLabel label) { + return label.name().equals(KLabels.ML_FALSE.name()) + || label.name().equals(KLabels.ML_TRUE.name()) + || label.name().equals(KLabels.ML_NOT.name()) + || label.name().equals(KLabels.ML_OR.name()) + || label.name().equals(KLabels.ML_AND.name()) + || label.name().equals(KLabels.ML_IMPLIES.name()) + || label.name().equals(KLabels.ML_EQUALS.name()) + || label.name().equals(KLabels.ML_CEIL.name()) + || label.name().equals(KLabels.ML_FLOOR.name()) + || label.name().equals(KLabels.ML_EXISTS.name()) + || label.name().equals(KLabels.ML_FORALL.name()) + || label.name().equals(KLabels.CTL_AG.name()) + || label.name().equals(KLabels.RL_wEF.name()) + || label.name().equals(KLabels.RL_wAF.name()); + } + private boolean isBuiltinModuloConstructor(KLabel label) { + return label.equals(KLabels.DotMap) + || label.equals(KLabels.Map) + || label.equals(KLabels.MapItem) + || label.equals(KLabels.DotList) + || label.equals(KLabels.List) + || label.equals(KLabels.ListItem) + || label.equals(KLabels.DotSet) + || label.equals(KLabels.Set) + || label.equals(KLabels.SetItem); + } + private boolean isInjectionLabel(String labelName) { + return labelName.equals(KLabels.INJ); + } } diff --git a/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java b/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java index a0101f9bead..1e1e1ec6418 100644 --- a/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java +++ b/kernel/src/main/java/org/kframework/backend/kore/KoreBackend.java @@ -1,14 +1,21 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.backend.kore; +import static org.kframework.Collections.*; + import com.google.inject.Inject; +import java.io.File; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; import org.apache.commons.io.FilenameUtils; import org.kframework.Strategy; import org.kframework.attributes.Att; import org.kframework.backend.Backends; import org.kframework.compile.*; -import org.kframework.definition.Module; import org.kframework.definition.*; +import org.kframework.definition.Module; import org.kframework.kompile.CompiledDefinition; import org.kframework.kompile.Kompile; import org.kframework.kompile.KompileOptions; @@ -20,256 +27,384 @@ import org.kframework.utils.file.FileUtil; import scala.Function1; -import java.io.File; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.function.Function; - -import static org.kframework.Collections.*; - public class KoreBackend extends AbstractBackend { - private final KompileOptions kompileOptions; - protected final FileUtil files; - private final KExceptionManager kem; - protected final boolean heatCoolEquations; - private final Tool tool; + private final KompileOptions kompileOptions; + protected final FileUtil files; + private final KExceptionManager kem; + protected final boolean heatCoolEquations; + private final Tool tool; - @Inject - public KoreBackend( - KompileOptions kompileOptions, - FileUtil files, - KExceptionManager kem, - Tool tool) { - this(kompileOptions, files, kem, false, tool); - } + @Inject + public KoreBackend( + KompileOptions kompileOptions, FileUtil files, KExceptionManager kem, Tool tool) { + this(kompileOptions, files, kem, false, tool); + } - public KoreBackend(KompileOptions kompileOptions, FileUtil files, KExceptionManager kem, boolean heatCoolEquations, Tool tool) { - this.kompileOptions = kompileOptions; - this.files = files; - this.kem = kem; - this.heatCoolEquations = heatCoolEquations; - this.tool = tool; - } + public KoreBackend( + KompileOptions kompileOptions, + FileUtil files, + KExceptionManager kem, + boolean heatCoolEquations, + Tool tool) { + this.kompileOptions = kompileOptions; + this.files = files; + this.kem = kem; + this.heatCoolEquations = heatCoolEquations; + this.tool = tool; + } - @Override - public void accept(Backend.Holder h) { - CompiledDefinition def = h.def; - String kore = getKompiledString(def, true); - File defFile = kompileOptions.outerParsing.mainDefinitionFile(files); - String name = defFile.getName(); - String basename = FilenameUtils.removeExtension(name); - files.saveToDefinitionDirectory(basename + ".kore", kore); - } + @Override + public void accept(Backend.Holder h) { + CompiledDefinition def = h.def; + String kore = getKompiledString(def, true); + File defFile = kompileOptions.outerParsing.mainDefinitionFile(files); + String name = defFile.getName(); + String basename = FilenameUtils.removeExtension(name); + files.saveToDefinitionDirectory(basename + ".kore", kore); + } - /** - * Convert a CompiledDefinition to a String of a KORE definition. - * @param hasAnd whether the backend in question supports and-patterns during pattern matching. - */ - protected String getKompiledString(CompiledDefinition def, boolean hasAnd) { - Module mainModule = getKompiledModule(def.kompiledDefinition.mainModule(), hasAnd); - ModuleToKORE converter = new ModuleToKORE(mainModule, def.topCellInitializer, def.kompileOptions); - return getKompiledString(converter, files, heatCoolEquations, tool); - } + /** + * Convert a CompiledDefinition to a String of a KORE definition. + * + * @param hasAnd whether the backend in question supports and-patterns during pattern matching. + */ + protected String getKompiledString(CompiledDefinition def, boolean hasAnd) { + Module mainModule = getKompiledModule(def.kompiledDefinition.mainModule(), hasAnd); + ModuleToKORE converter = + new ModuleToKORE(mainModule, def.topCellInitializer, def.kompileOptions); + return getKompiledString(converter, files, heatCoolEquations, tool); + } - public static String getKompiledString(ModuleToKORE converter, FileUtil files, boolean heatCoolEquations, Tool t) { - StringBuilder sb = new StringBuilder(); - String kompiledString = getKompiledStringAndWriteSyntaxMacros(converter, files, heatCoolEquations, sb, t); - return kompiledString; - } + public static String getKompiledString( + ModuleToKORE converter, FileUtil files, boolean heatCoolEquations, Tool t) { + StringBuilder sb = new StringBuilder(); + String kompiledString = + getKompiledStringAndWriteSyntaxMacros(converter, files, heatCoolEquations, sb, t); + return kompiledString; + } - public static String getKompiledStringAndWriteSyntaxMacros(ModuleToKORE converter, FileUtil files, boolean heatCoolEq, StringBuilder sb, Tool t) { - StringBuilder semantics = new StringBuilder(); - StringBuilder syntax = new StringBuilder(); - StringBuilder macros = new StringBuilder(); - String prelude = files.loadFromKIncludeDir("kore/prelude.kore"); - converter.convert(heatCoolEq, prelude, semantics, syntax, macros); - if (t == Tool.KOMPILE) { - files.saveToKompiled("syntaxDefinition.kore", syntax.toString()); - files.saveToKompiled("macros.kore", macros.toString()); - } - return semantics.toString(); + public static String getKompiledStringAndWriteSyntaxMacros( + ModuleToKORE converter, FileUtil files, boolean heatCoolEq, StringBuilder sb, Tool t) { + StringBuilder semantics = new StringBuilder(); + StringBuilder syntax = new StringBuilder(); + StringBuilder macros = new StringBuilder(); + String prelude = files.loadFromKIncludeDir("kore/prelude.kore"); + converter.convert(heatCoolEq, prelude, semantics, syntax, macros); + if (t == Tool.KOMPILE) { + files.saveToKompiled("syntaxDefinition.kore", syntax.toString()); + files.saveToKompiled("macros.kore", macros.toString()); } + return semantics.toString(); + } - public static Module getKompiledModule(Module mainModule, boolean hasAnd) { - mainModule = ModuleTransformer.fromSentenceTransformer(new AddSortInjections(mainModule)::addInjections, "Add sort injections").apply(mainModule); - mainModule = ModuleTransformer.from(new RemoveUnit()::apply, "Remove unit applications for collections").apply(mainModule); - if (hasAnd) { - mainModule = ModuleTransformer.fromSentenceTransformer(new MinimizeTermConstruction(mainModule)::resolve, "Minimize term construction").apply(mainModule); - } - return mainModule; + public static Module getKompiledModule(Module mainModule, boolean hasAnd) { + mainModule = + ModuleTransformer.fromSentenceTransformer( + new AddSortInjections(mainModule)::addInjections, "Add sort injections") + .apply(mainModule); + mainModule = + ModuleTransformer.from(new RemoveUnit()::apply, "Remove unit applications for collections") + .apply(mainModule); + if (hasAnd) { + mainModule = + ModuleTransformer.fromSentenceTransformer( + new MinimizeTermConstruction(mainModule)::resolve, "Minimize term construction") + .apply(mainModule); } + return mainModule; + } - @Override - public Function steps() { - DefinitionTransformer resolveComm = DefinitionTransformer.from(new ResolveComm(kem)::resolve, "resolve comm simplification rules"); - Function1 resolveStrict = d -> DefinitionTransformer.from(new ResolveStrict(kompileOptions, d)::resolve, "resolving strict and seqstrict attributes").apply(d); - DefinitionTransformer resolveHeatCoolAttribute = DefinitionTransformer.fromSentenceTransformer(new ResolveHeatCoolAttribute(new HashSet<>())::resolve, "resolving heat and cool attributes"); - DefinitionTransformer resolveAnonVars = DefinitionTransformer.fromSentenceTransformer(new ResolveAnonVar()::resolve, "resolving \"_\" vars"); - DefinitionTransformer guardOrs = DefinitionTransformer.fromSentenceTransformer(new GuardOrPatterns()::resolve, "resolving or patterns"); - DefinitionTransformer resolveSemanticCasts = - DefinitionTransformer.fromSentenceTransformer(new ResolveSemanticCasts(true)::resolve, "resolving semantic casts"); - DefinitionTransformer resolveFun = DefinitionTransformer.from(new ResolveFun()::resolve, "resolving #fun"); - Function1 resolveFunctionWithConfig = d -> DefinitionTransformer.from(new ResolveFunctionWithConfig(d)::moduleResolve, "resolving functions with config context").apply(d); - DefinitionTransformer generateSortPredicateSyntax = DefinitionTransformer.from(new GenerateSortPredicateSyntax()::gen, "adding sort predicate productions"); - DefinitionTransformer generateSortPredicateRules = DefinitionTransformer.from(new GenerateSortPredicateRules()::gen, "adding sort predicate rules"); - DefinitionTransformer generateSortProjections = DefinitionTransformer.from(new GenerateSortProjections(kompileOptions.coverage)::gen, "adding sort projections"); - DefinitionTransformer subsortKItem = DefinitionTransformer.from(Kompile::subsortKItem, "subsort all sorts to KItem"); - Function1 addCoolLikeAtt = d -> DefinitionTransformer.fromSentenceTransformer(new AddCoolLikeAtt(d.mainModule())::add, "add cool-like attribute").apply(d); - Function1 propagateMacroToRules = - d -> DefinitionTransformer.fromSentenceTransformer((m, s) -> new PropagateMacro(m).propagate(s), "propagate macro labels from production to rules").apply(d); - Function1 expandMacros = d -> { + @Override + public Function steps() { + DefinitionTransformer resolveComm = + DefinitionTransformer.from( + new ResolveComm(kem)::resolve, "resolve comm simplification rules"); + Function1 resolveStrict = + d -> + DefinitionTransformer.from( + new ResolveStrict(kompileOptions, d)::resolve, + "resolving strict and seqstrict attributes") + .apply(d); + DefinitionTransformer resolveHeatCoolAttribute = + DefinitionTransformer.fromSentenceTransformer( + new ResolveHeatCoolAttribute(new HashSet<>())::resolve, + "resolving heat and cool attributes"); + DefinitionTransformer resolveAnonVars = + DefinitionTransformer.fromSentenceTransformer( + new ResolveAnonVar()::resolve, "resolving \"_\" vars"); + DefinitionTransformer guardOrs = + DefinitionTransformer.fromSentenceTransformer( + new GuardOrPatterns()::resolve, "resolving or patterns"); + DefinitionTransformer resolveSemanticCasts = + DefinitionTransformer.fromSentenceTransformer( + new ResolveSemanticCasts(true)::resolve, "resolving semantic casts"); + DefinitionTransformer resolveFun = + DefinitionTransformer.from(new ResolveFun()::resolve, "resolving #fun"); + Function1 resolveFunctionWithConfig = + d -> + DefinitionTransformer.from( + new ResolveFunctionWithConfig(d)::moduleResolve, + "resolving functions with config context") + .apply(d); + DefinitionTransformer generateSortPredicateSyntax = + DefinitionTransformer.from( + new GenerateSortPredicateSyntax()::gen, "adding sort predicate productions"); + DefinitionTransformer generateSortPredicateRules = + DefinitionTransformer.from( + new GenerateSortPredicateRules()::gen, "adding sort predicate rules"); + DefinitionTransformer generateSortProjections = + DefinitionTransformer.from( + new GenerateSortProjections(kompileOptions.coverage)::gen, "adding sort projections"); + DefinitionTransformer subsortKItem = + DefinitionTransformer.from(Kompile::subsortKItem, "subsort all sorts to KItem"); + Function1 addCoolLikeAtt = + d -> + DefinitionTransformer.fromSentenceTransformer( + new AddCoolLikeAtt(d.mainModule())::add, "add cool-like attribute") + .apply(d); + Function1 propagateMacroToRules = + d -> + DefinitionTransformer.fromSentenceTransformer( + (m, s) -> new PropagateMacro(m).propagate(s), + "propagate macro labels from production to rules") + .apply(d); + Function1 expandMacros = + d -> { ResolveFunctionWithConfig transformer = new ResolveFunctionWithConfig(d); - return DefinitionTransformer.fromSentenceTransformer((m, s) -> new ExpandMacros(transformer, m, files, kem, kompileOptions, false).expand(s), "expand macros").apply(d); + return DefinitionTransformer.fromSentenceTransformer( + (m, s) -> + new ExpandMacros(transformer, m, files, kem, kompileOptions, false).expand(s), + "expand macros") + .apply(d); }; - Function1 checkSimplificationRules = d -> DefinitionTransformer.from(m -> { m.localRules().foreach(r -> checkSimpIsFunc(m, r)); return m;}, "Check simplification rules").apply(d); - DefinitionTransformer constantFolding = DefinitionTransformer.fromSentenceTransformer(new ConstantFolding()::fold, "constant expression folding"); - ResolveFreshConfigConstants freshConfigResolver = new ResolveFreshConfigConstants(); - Function1 resolveFreshConfigConstants = d -> - DefinitionTransformer.from(m -> freshConfigResolver.resolve(m), "resolving !Var config variables").apply(d); - Function1 resolveFreshConstants = d -> - DefinitionTransformer.from(m -> new ResolveFreshConstants(d, kompileOptions.topCell, files, freshConfigResolver.getCurrentFresh()).resolve(m), "resolving !Var variables").apply(d); - GenerateCoverage cov = new GenerateCoverage(kompileOptions.coverage, files); - Function1 genCoverage = d -> DefinitionTransformer.fromRuleBodyTransformerWithRule((r, body) -> cov.gen(r, body, d.mainModule()), "generate coverage instrumentation").apply(d); - DefinitionTransformer numberSentences = DefinitionTransformer.fromSentenceTransformer(NumberSentences::number, "number sentences uniquely"); - Function1 resolveConfigVar = d -> DefinitionTransformer.fromSentenceTransformer(new ResolveFunctionWithConfig(d)::resolveConfigVar, "Adding configuration variable to lhs").apply(d); - Function1 resolveIO = (d -> Kompile.resolveIOStreams(kem, d)); - Function1 markExtraConcreteRules = d -> MarkExtraConcreteRules.mark(d, kompileOptions.extraConcreteRuleLabels); - Function1 removeAnywhereRules = - d -> DefinitionTransformer.from(this::removeAnywhereRules, - "removing anywhere rules for the Haskell backend").apply(d); + Function1 checkSimplificationRules = + d -> + DefinitionTransformer.from( + m -> { + m.localRules().foreach(r -> checkSimpIsFunc(m, r)); + return m; + }, + "Check simplification rules") + .apply(d); + DefinitionTransformer constantFolding = + DefinitionTransformer.fromSentenceTransformer( + new ConstantFolding()::fold, "constant expression folding"); + ResolveFreshConfigConstants freshConfigResolver = new ResolveFreshConfigConstants(); + Function1 resolveFreshConfigConstants = + d -> + DefinitionTransformer.from( + m -> freshConfigResolver.resolve(m), "resolving !Var config variables") + .apply(d); + Function1 resolveFreshConstants = + d -> + DefinitionTransformer.from( + m -> + new ResolveFreshConstants( + d, + kompileOptions.topCell, + files, + freshConfigResolver.getCurrentFresh()) + .resolve(m), + "resolving !Var variables") + .apply(d); + GenerateCoverage cov = new GenerateCoverage(kompileOptions.coverage, files); + Function1 genCoverage = + d -> + DefinitionTransformer.fromRuleBodyTransformerWithRule( + (r, body) -> cov.gen(r, body, d.mainModule()), + "generate coverage instrumentation") + .apply(d); + DefinitionTransformer numberSentences = + DefinitionTransformer.fromSentenceTransformer( + NumberSentences::number, "number sentences uniquely"); + Function1 resolveConfigVar = + d -> + DefinitionTransformer.fromSentenceTransformer( + new ResolveFunctionWithConfig(d)::resolveConfigVar, + "Adding configuration variable to lhs") + .apply(d); + Function1 resolveIO = (d -> Kompile.resolveIOStreams(kem, d)); + Function1 markExtraConcreteRules = + d -> MarkExtraConcreteRules.mark(d, kompileOptions.extraConcreteRuleLabels); + Function1 removeAnywhereRules = + d -> + DefinitionTransformer.from( + this::removeAnywhereRules, "removing anywhere rules for the Haskell backend") + .apply(d); - return def -> resolveComm - .andThen(resolveIO) - .andThen(resolveFun) - .andThen(resolveFunctionWithConfig) - .andThen(resolveStrict) - .andThen(resolveAnonVars) - .andThen(d -> new ResolveContexts(kompileOptions).resolve(d)) - .andThen(numberSentences) - .andThen(resolveHeatCoolAttribute) - .andThen(resolveSemanticCasts) - .andThen(subsortKItem) - .andThen(generateSortPredicateSyntax) - .andThen(generateSortProjections) - .andThen(constantFolding) - .andThen(propagateMacroToRules) - .andThen(expandMacros) - .andThen(checkSimplificationRules) - .andThen(guardOrs) - .andThen(AddImplicitComputationCell::transformDefinition) - .andThen(resolveFreshConfigConstants) - .andThen(resolveFreshConstants) - .andThen(generateSortPredicateSyntax) - .andThen(generateSortProjections) - .andThen(subsortKItem) - .andThen(d -> new Strategy().addStrategyCellToRulesTransformer(d).apply(d)) - .andThen(d -> Strategy.addStrategyRuleToMainModule(def.mainModule().name()).apply(d)) - .andThen(d -> ConcretizeCells.transformDefinition(d)) - .andThen(genCoverage) - .andThen(Kompile::addSemanticsModule) - .andThen(resolveConfigVar) - .andThen(addCoolLikeAtt) - .andThen(markExtraConcreteRules) - .andThen(removeAnywhereRules) - .andThen(generateSortPredicateRules) - .andThen(numberSentences) - .apply(def); - } + return def -> + resolveComm + .andThen(resolveIO) + .andThen(resolveFun) + .andThen(resolveFunctionWithConfig) + .andThen(resolveStrict) + .andThen(resolveAnonVars) + .andThen(d -> new ResolveContexts(kompileOptions).resolve(d)) + .andThen(numberSentences) + .andThen(resolveHeatCoolAttribute) + .andThen(resolveSemanticCasts) + .andThen(subsortKItem) + .andThen(generateSortPredicateSyntax) + .andThen(generateSortProjections) + .andThen(constantFolding) + .andThen(propagateMacroToRules) + .andThen(expandMacros) + .andThen(checkSimplificationRules) + .andThen(guardOrs) + .andThen(AddImplicitComputationCell::transformDefinition) + .andThen(resolveFreshConfigConstants) + .andThen(resolveFreshConstants) + .andThen(generateSortPredicateSyntax) + .andThen(generateSortProjections) + .andThen(subsortKItem) + .andThen(d -> new Strategy().addStrategyCellToRulesTransformer(d).apply(d)) + .andThen(d -> Strategy.addStrategyRuleToMainModule(def.mainModule().name()).apply(d)) + .andThen(d -> ConcretizeCells.transformDefinition(d)) + .andThen(genCoverage) + .andThen(Kompile::addSemanticsModule) + .andThen(resolveConfigVar) + .andThen(addCoolLikeAtt) + .andThen(markExtraConcreteRules) + .andThen(removeAnywhereRules) + .andThen(generateSortPredicateRules) + .andThen(numberSentences) + .apply(def); + } - @Override - public Function specificationSteps(Definition def) { - ModuleTransformer resolveComm = ModuleTransformer.from(new ResolveComm(kem)::resolve, "resolve comm simplification rules"); - Module mod = def.mainModule(); - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); - LabelInfo labelInfo = new LabelInfoFromModule(mod); - SortInfo sortInfo = SortInfo.fromModule(mod); - ModuleTransformer resolveAnonVars = ModuleTransformer.fromSentenceTransformer( - new ResolveAnonVar()::resolve, - "resolving \"_\" vars"); - ModuleTransformer numberSentences = ModuleTransformer.fromSentenceTransformer(NumberSentences::number, "number sentences uniquely"); - ModuleTransformer resolveSemanticCasts = ModuleTransformer.fromSentenceTransformer( - new ResolveSemanticCasts(true)::resolve, - "resolving semantic casts"); - Function1 propagateMacroToRules = - m -> ModuleTransformer.fromSentenceTransformer((m2, s) -> new PropagateMacro(m2).propagate(s), "propagate macro labels from production to rules").apply(m); - Function1 expandMacros = m -> { + @Override + public Function specificationSteps(Definition def) { + ModuleTransformer resolveComm = + ModuleTransformer.from(new ResolveComm(kem)::resolve, "resolve comm simplification rules"); + Module mod = def.mainModule(); + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); + LabelInfo labelInfo = new LabelInfoFromModule(mod); + SortInfo sortInfo = SortInfo.fromModule(mod); + ModuleTransformer resolveAnonVars = + ModuleTransformer.fromSentenceTransformer( + new ResolveAnonVar()::resolve, "resolving \"_\" vars"); + ModuleTransformer numberSentences = + ModuleTransformer.fromSentenceTransformer( + NumberSentences::number, "number sentences uniquely"); + ModuleTransformer resolveSemanticCasts = + ModuleTransformer.fromSentenceTransformer( + new ResolveSemanticCasts(true)::resolve, "resolving semantic casts"); + Function1 propagateMacroToRules = + m -> + ModuleTransformer.fromSentenceTransformer( + (m2, s) -> new PropagateMacro(m2).propagate(s), + "propagate macro labels from production to rules") + .apply(m); + Function1 expandMacros = + m -> { ResolveFunctionWithConfig transformer = new ResolveFunctionWithConfig(m); - return ModuleTransformer.fromSentenceTransformer((m2, s) -> new ExpandMacros(transformer, m2, files, kem, kompileOptions, false).expand(s), "expand macros").apply(m); + return ModuleTransformer.fromSentenceTransformer( + (m2, s) -> + new ExpandMacros(transformer, m2, files, kem, kompileOptions, false) + .expand(s), + "expand macros") + .apply(m); }; - Function1 checkSimplificationRules = ModuleTransformer.from(m -> { m.localRules().foreach(r -> checkSimpIsFunc(m, r)); return m;}, "Check simplification rules"); - ModuleTransformer subsortKItem = ModuleTransformer.from(Kompile::subsortKItem, "subsort all sorts to KItem"); - ModuleTransformer addImplicitComputationCell = ModuleTransformer.fromSentenceTransformer( - new AddImplicitComputationCell(configInfo, labelInfo)::apply, - "concretizing configuration"); - Function1 resolveFreshConstants = d -> - ModuleTransformer.from(new ResolveFreshConstants(def, kompileOptions.topCell, files)::resolve, "resolving !Var variables").apply(d); - Function1 addImplicitCounterCell = ModuleTransformer.fromSentenceTransformer( - new AddImplicitCounterCell()::apply, - "adding to claims if necessary"); - ModuleTransformer concretizeCells = ModuleTransformer.fromSentenceTransformer( - new ConcretizeCells(configInfo, labelInfo, sortInfo, mod)::concretize, - "concretizing configuration"); - ModuleTransformer generateSortProjections = ModuleTransformer.from(new GenerateSortProjections(false)::gen, "adding sort projections"); + Function1 checkSimplificationRules = + ModuleTransformer.from( + m -> { + m.localRules().foreach(r -> checkSimpIsFunc(m, r)); + return m; + }, + "Check simplification rules"); + ModuleTransformer subsortKItem = + ModuleTransformer.from(Kompile::subsortKItem, "subsort all sorts to KItem"); + ModuleTransformer addImplicitComputationCell = + ModuleTransformer.fromSentenceTransformer( + new AddImplicitComputationCell(configInfo, labelInfo)::apply, + "concretizing configuration"); + Function1 resolveFreshConstants = + d -> + ModuleTransformer.from( + new ResolveFreshConstants(def, kompileOptions.topCell, files)::resolve, + "resolving !Var variables") + .apply(d); + Function1 addImplicitCounterCell = + ModuleTransformer.fromSentenceTransformer( + new AddImplicitCounterCell()::apply, + "adding to claims if necessary"); + ModuleTransformer concretizeCells = + ModuleTransformer.fromSentenceTransformer( + new ConcretizeCells(configInfo, labelInfo, sortInfo, mod)::concretize, + "concretizing configuration"); + ModuleTransformer generateSortProjections = + ModuleTransformer.from(new GenerateSortProjections(false)::gen, "adding sort projections"); - return m -> resolveComm - .andThen(addImplicitCounterCell) - .andThen(resolveAnonVars) - .andThen(numberSentences) - .andThen(resolveSemanticCasts) - .andThen(generateSortProjections) - .andThen(propagateMacroToRules) - .andThen(expandMacros) - .andThen(checkSimplificationRules) - .andThen(addImplicitComputationCell) - .andThen(resolveFreshConstants) - .andThen(concretizeCells) - .andThen(subsortKItem) - .andThen(restoreDefinitionModulesTransformer(def)) - .andThen(numberSentences) - .apply(m); - } + return m -> + resolveComm + .andThen(addImplicitCounterCell) + .andThen(resolveAnonVars) + .andThen(numberSentences) + .andThen(resolveSemanticCasts) + .andThen(generateSortProjections) + .andThen(propagateMacroToRules) + .andThen(expandMacros) + .andThen(checkSimplificationRules) + .andThen(addImplicitComputationCell) + .andThen(resolveFreshConstants) + .andThen(concretizeCells) + .andThen(subsortKItem) + .andThen(restoreDefinitionModulesTransformer(def)) + .andThen(numberSentences) + .apply(m); + } - // check that simplification rules have a functional symbol on the LHS - public Sentence checkSimpIsFunc(Module m, Sentence s) { - // need to check after macro expansion - if (s instanceof Rule && (s.att().contains(Att.SIMPLIFICATION()))) { - KLabel kl = m.matchKLabel((Rule) s); - Att atts = m.attributesFor().get(kl).getOrElse(Att::empty); - if (!(atts.contains(Att.FUNCTION()) || atts.contains(Att.FUNCTIONAL()) || atts.contains(Att.ML_OP()))) - throw KEMException.compilerError("Simplification rules expect function/functional/mlOp symbols at the top of the left hand side term.", s); - } - return s; + // check that simplification rules have a functional symbol on the LHS + public Sentence checkSimpIsFunc(Module m, Sentence s) { + // need to check after macro expansion + if (s instanceof Rule && (s.att().contains(Att.SIMPLIFICATION()))) { + KLabel kl = m.matchKLabel((Rule) s); + Att atts = m.attributesFor().get(kl).getOrElse(Att::empty); + if (!(atts.contains(Att.FUNCTION()) + || atts.contains(Att.FUNCTIONAL()) + || atts.contains(Att.ML_OP()))) + throw KEMException.compilerError( + "Simplification rules expect function/functional/mlOp symbols at the top of the left" + + " hand side term.", + s); } + return s; + } - // If a user guarantees that their semantics will never _dynamically_ try to rewrite an anywhere rule on the - // Haskell backend (with the --allow-anywhere-haskell flag), but cannot prove this statically, we allow them to - // strip out all those rules before sending the definition to the backend. If this transformation is applied - // unsoundly (i.e. an anywhere rule would have been attempted if it had not been stripped), the behaviour of the - // Haskell backend on that program is essentially undefined. - private Module removeAnywhereRules(Module m) { - java.util.Set sentences = mutable(m.localSentences()); - - if(kompileOptions.backend.equals(Backends.HASKELL) && kompileOptions.allowAnywhereRulesHaskell) { - java.util.Set filtered = new HashSet(); + /** + * If a user guarantees that their semantics will never _dynamically_ try to rewrite an anywhere + * rule on the Haskell backend (with the --allow-anywhere-haskell flag), but cannot prove this + * statically, we allow them to strip out all those rules before sending the definition to the + * backend. If this transformation is applied unsoundly (i.e. an anywhere rule would have been + * attempted if it had not been stripped), the behaviour of the Haskell backend on that program is + * essentially undefined. + */ + private Module removeAnywhereRules(Module m) { + java.util.Set sentences = mutable(m.localSentences()); - for(var s : sentences) { - if(s instanceof Rule && s.att().contains(Att.ANYWHERE())) { - kem.registerCompilerWarning(KException.ExceptionType.REMOVED_ANYWHERE, - "Removed anywhere rule for Haskell backend execution; this may change the behavior of your code.", s); - } else { - filtered.add(s); - } - } + if (kompileOptions.backend.equals(Backends.HASKELL) + && kompileOptions.allowAnywhereRulesHaskell) { + java.util.Set filtered = new HashSet(); - sentences = filtered; + for (var s : sentences) { + if (s instanceof Rule && s.att().contains(Att.ANYWHERE())) { + kem.registerCompilerWarning( + KException.ExceptionType.REMOVED_ANYWHERE, + "Removed anywhere rule for Haskell backend execution; this may change the behavior of" + + " your code.", + s); + } else { + filtered.add(s); } - return new Module(m.name(), m.imports(), immutable(sentences), m.att()); - } + } - @Override - public Set excludedModuleTags() { - return Collections.singleton(Att.SYMBOLIC()); + sentences = filtered; } + return new Module(m.name(), m.imports(), immutable(sentences), m.att()); + } + + @Override + public Set excludedModuleTags() { + return Collections.singleton(Att.SYMBOLIC()); + } } diff --git a/kernel/src/main/java/org/kframework/backend/kore/ModuleToKORE.java b/kernel/src/main/java/org/kframework/backend/kore/ModuleToKORE.java index fda179960ff..8996a6e19df 100644 --- a/kernel/src/main/java/org/kframework/backend/kore/ModuleToKORE.java +++ b/kernel/src/main/java/org/kframework/backend/kore/ModuleToKORE.java @@ -1,13 +1,29 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.backend.kore; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.HashMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.SetMultimap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.kframework.Collections; import org.kframework.attributes.Att; -import org.kframework.attributes.Att.Key; import org.kframework.attributes.HasLocation; import org.kframework.attributes.Source; import org.kframework.builtin.BooleanUtils; @@ -53,2000 +69,2242 @@ import scala.collection.JavaConverters; import scala.collection.Seq; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - class RuleInfo { - boolean isEquation; - boolean isOwise; - boolean isKore; - boolean isCeil; - Production production; - String productionSortStr; - List prodChildrenSorts; - KLabel productionLabel; - List leftChildren; - - public RuleInfo(boolean equation, boolean owise, boolean kore, boolean ceil, Production production, - String prodSortStr, List prodChildrenSorts, KLabel prodLabel, List leftChildren) { - this.isEquation = equation; - this.isOwise = owise; - this.isKore = kore; - this.isCeil = ceil; - this.production = production; - this.productionSortStr = prodSortStr; - this.prodChildrenSorts = prodChildrenSorts; - this.productionLabel = prodLabel; - this.leftChildren = leftChildren; - } + boolean isEquation; + boolean isOwise; + boolean isKore; + boolean isCeil; + Production production; + String productionSortStr; + List prodChildrenSorts; + KLabel productionLabel; + List leftChildren; + + public RuleInfo( + boolean equation, + boolean owise, + boolean kore, + boolean ceil, + Production production, + String prodSortStr, + List prodChildrenSorts, + KLabel prodLabel, + List leftChildren) { + this.isEquation = equation; + this.isOwise = owise; + this.isKore = kore; + this.isCeil = ceil; + this.production = production; + this.productionSortStr = prodSortStr; + this.prodChildrenSorts = prodChildrenSorts; + this.productionLabel = prodLabel; + this.leftChildren = leftChildren; + } } public class ModuleToKORE { - public enum SentenceType { - REWRITE_RULE, - ONE_PATH, - ALL_PATH - } - - public static final String ONE_PATH_OP = KLabels.RL_wEF.name(); - public static final String ALL_PATH_OP = KLabels.RL_wAF.name(); - private final Module module; - private final AddSortInjections addSortInjections; - private final KLabel topCellInitializer; - private final Set mlBinders = new HashSet<>(); - private final KompileOptions options; - - private final KExceptionManager kem; - - public ModuleToKORE(Module module, KLabel topCellInitializer, KompileOptions options) { - this(module, topCellInitializer, options, null); - } - - public ModuleToKORE(Module module, KLabel topCellInitializer, KompileOptions options, KExceptionManager kem) { - this.kem = kem; - this.module = module; - this.addSortInjections = new AddSortInjections(module); - this.topCellInitializer = topCellInitializer; - this.options = options; - for (Production prod : iterable(module.sortedProductions())) { - if (prod.att().contains(Att.ML_BINDER())) { - mlBinders.add(prod.klabel().get().name()); - } - } + public enum SentenceType { + REWRITE_RULE, + ONE_PATH, + ALL_PATH + } + + public static final String ONE_PATH_OP = KLabels.RL_wEF.name(); + public static final String ALL_PATH_OP = KLabels.RL_wAF.name(); + private final Module module; + private final AddSortInjections addSortInjections; + private final KLabel topCellInitializer; + private final Set mlBinders = new HashSet<>(); + private final KompileOptions options; + + private final KExceptionManager kem; + + public ModuleToKORE(Module module, KLabel topCellInitializer, KompileOptions options) { + this(module, topCellInitializer, options, null); + } + + public ModuleToKORE( + Module module, KLabel topCellInitializer, KompileOptions options, KExceptionManager kem) { + this.kem = kem; + this.module = module; + this.addSortInjections = new AddSortInjections(module); + this.topCellInitializer = topCellInitializer; + this.options = options; + for (Production prod : iterable(module.sortedProductions())) { + if (prod.att().contains(Att.ML_BINDER())) { + mlBinders.add(prod.klabel().get().name()); + } } - private static final boolean METAVAR = false; - - public void convert(boolean heatCoolEq, String prelude, StringBuilder semantics, StringBuilder syntax, StringBuilder macros) { - Sort topCellSort = Sorts.GeneratedTopCell(); - String topCellSortStr = getSortStr(topCellSort); - semantics.append("[topCellInitializer{}("); - convert(topCellInitializer, semantics); - semantics.append("()), "); - StringBuilder sb = new StringBuilder(); - HashMap considerSource = new HashMap<>(); - considerSource.put(Att.SOURCE(), true); - // insert the location of the main module so the backend can provide better error location - convert(considerSource, Att.empty().add(Source.class, module.att().get(Source.class)), sb, null, null); - semantics.append(sb.subSequence(1, sb.length() - 1)); - semantics.append("]\n\n"); - - semantics.append(prelude); - semantics.append("\n"); - - SentenceType sentenceType = getSentenceType(module.att()).orElse(SentenceType.REWRITE_RULE); - semantics.append("module "); - convert(module.name(), semantics); - semantics.append("\n\n// imports\n"); - semantics.append(" import K []\n\n// sorts\n"); - - Set tokenSorts = new HashSet<>(); - // Map attribute name to whether the attribute has a value - Map attributes = new HashMap<>(); - attributes.put(Att.NAT(), true); - attributes.put(Att.TERMINALS(), true); - attributes.put(Att.COLORS(), true); - attributes.put(Att.PRIORITY(), true); - Set priorities = new HashSet<>(); - collectTokenSortsAndAttributes(tokenSorts, attributes, priorities, heatCoolEq, topCellSortStr); - Map priorityToPreviousGroup = new HashMap<>(); - List priorityList = new ArrayList<>(priorities); - java.util.Collections.sort(priorityList); - if (priorityList.size() > 0 ) { - priorityToPreviousGroup.put(priorityList.get(0), ""); - } - for (int i = 1; i < priorityList.size(); i++) { - Integer previous = priorityList.get(i - 1); - Integer current = priorityList.get(i); - priorityToPreviousGroup.put(current, String.format("priorityLE%d", previous)); - } - - Set collectionSorts = new HashSet<>(); - collectionSorts.add("SET.Set"); - collectionSorts.add("MAP.Map"); - collectionSorts.add("LIST.List"); - collectionSorts.add("ARRAY.Array"); - collectionSorts.add("RANGEMAP.RangeMap"); - attributes.remove(Att.HAS_DOMAIN_VALUES()); - if (attributes.containsKey(Att.TOKEN())) { - attributes.put(Att.HAS_DOMAIN_VALUES(), false); - } - translateSorts(tokenSorts, attributes, collectionSorts, semantics); - - List sortedRules = new ArrayList<>(JavaConverters.seqAsJavaList(module.sortedRules())); - if (options.backend.equals("haskell")) { - module.sortedProductions().toStream().filter(this::isGeneratedInKeysOp).foreach( - prod -> { - if (!options.disableCeilSimplificationRules) { - genMapCeilAxioms(prod, sortedRules); - } - return prod; - } - ); - } - SetMultimap functionRules = HashMultimap.create(); - for (Rule rule : sortedRules) { - K left = RewriteToTop.toLeft(rule.body()); - if (left instanceof KApply kapp) { - Production prod = production(kapp); - if (prod.att().contains(Att.FUNCTION()) || rule.att().contains(Att.ANYWHERE()) || ExpandMacros.isMacro(rule)) { - functionRules.put(kapp.klabel(), rule); + } + + private static final boolean METAVAR = false; + + public void convert( + boolean heatCoolEq, + String prelude, + StringBuilder semantics, + StringBuilder syntax, + StringBuilder macros) { + Sort topCellSort = Sorts.GeneratedTopCell(); + String topCellSortStr = getSortStr(topCellSort); + semantics.append("[topCellInitializer{}("); + convert(topCellInitializer, semantics); + semantics.append("()), "); + StringBuilder sb = new StringBuilder(); + HashMap considerSource = new HashMap<>(); + considerSource.put(Att.SOURCE(), true); + // insert the location of the main module so the backend can provide better error location + convert( + considerSource, + Att.empty().add(Source.class, module.att().get(Source.class)), + sb, + null, + null); + semantics.append(sb.subSequence(1, sb.length() - 1)); + semantics.append("]\n\n"); + + semantics.append(prelude); + semantics.append("\n"); + + SentenceType sentenceType = getSentenceType(module.att()).orElse(SentenceType.REWRITE_RULE); + semantics.append("module "); + convert(module.name(), semantics); + semantics.append("\n\n// imports\n"); + semantics.append(" import K []\n\n// sorts\n"); + + Set tokenSorts = new HashSet<>(); + // Map attribute name to whether the attribute has a value + Map attributes = new HashMap<>(); + attributes.put(Att.NAT(), true); + attributes.put(Att.TERMINALS(), true); + attributes.put(Att.COLORS(), true); + attributes.put(Att.PRIORITY(), true); + Set priorities = new HashSet<>(); + collectTokenSortsAndAttributes(tokenSorts, attributes, priorities, heatCoolEq, topCellSortStr); + Map priorityToPreviousGroup = new HashMap<>(); + List priorityList = new ArrayList<>(priorities); + java.util.Collections.sort(priorityList); + if (priorityList.size() > 0) { + priorityToPreviousGroup.put(priorityList.get(0), ""); + } + for (int i = 1; i < priorityList.size(); i++) { + Integer previous = priorityList.get(i - 1); + Integer current = priorityList.get(i); + priorityToPreviousGroup.put(current, String.format("priorityLE%d", previous)); + } + + Set collectionSorts = new HashSet<>(); + collectionSorts.add("SET.Set"); + collectionSorts.add("MAP.Map"); + collectionSorts.add("LIST.List"); + collectionSorts.add("ARRAY.Array"); + collectionSorts.add("RANGEMAP.RangeMap"); + attributes.remove(Att.HAS_DOMAIN_VALUES()); + if (attributes.containsKey(Att.TOKEN())) { + attributes.put(Att.HAS_DOMAIN_VALUES(), false); + } + translateSorts(tokenSorts, attributes, collectionSorts, semantics); + + List sortedRules = new ArrayList<>(JavaConverters.seqAsJavaList(module.sortedRules())); + if (options.backend.equals("haskell")) { + module + .sortedProductions() + .toStream() + .filter(this::isGeneratedInKeysOp) + .foreach( + prod -> { + if (!options.disableCeilSimplificationRules) { + genMapCeilAxioms(prod, sortedRules); } - } - } - - semantics.append("\n// symbols\n"); - Set overloads = new HashSet<>(); - for (Production lesser : iterable(module.overloads().elements())) { - for (Production greater : iterable(module.overloads().relations().get(lesser).getOrElse(Collections::Set))) { - overloads.add(greater); - } - } - translateSymbols(attributes, functionRules, overloads, semantics); - - // print syntax definition - syntax.append(semantics); - for (Tuple2> sort : iterable(module.bracketProductionsFor())) { - for (Production prod : iterable(sort._2())) { - translateSymbol(attributes, functionRules, overloads, prod.att().get(Att.BRACKET_LABEL(), KLabel.class), prod, syntax); - } - } - for (Production prod : iterable(module.sortedProductions())) { - if (isBuiltinProduction(prod)) { - continue; - } - if (prod.isSubsort() && !prod.sort().equals(Sorts.K())) { - genSubsortAxiom(prod, syntax); - continue; - } - } - - for (Production lesser : iterable(module.overloads().elements())) { - for (Production greater : iterable(module.overloads().relations().get(lesser).getOrElse(() -> Collections.Set()))) { - genOverloadedAxiom(lesser, greater, syntax); - } - } - - syntax.append("endmodule []\n"); - - semantics.append("\n// generated axioms\n"); - Set> noConfusion = new HashSet<>(); - for (Production prod : iterable(module.sortedProductions())) { - if (isBuiltinProduction(prod)) { - continue; - } - if (prod.isSubsort() && !prod.sort().equals(Sorts.K())) { - genSubsortAxiom(prod, semantics); - continue; - } - if (prod.klabel().isEmpty()) { - continue; - } - if (prod.att().contains(Att.ASSOC())) { - genAssocAxiom(prod, semantics); - } - //if (prod.att().contains(Att.COMM())) { - // genCommAxiom(prod, semantics); - //} - if (prod.att().contains(Att.IDEM())) { - genIdemAxiom(prod, semantics); - } - if (isFunction(prod) && prod.att().contains(Att.UNIT())) { - genUnitAxiom(prod, semantics); - } - if (isFunctional(prod, functionRules)) { - genFunctionalAxiom(prod, semantics); - } - if (isConstructor(prod, functionRules)) { - genNoConfusionAxioms(prod, noConfusion, functionRules, semantics); - } - } - - for (Sort sort : iterable(module.sortedAllSorts())) { - genNoJunkAxiom(sort, semantics); - } - - for (Production lesser : iterable(module.overloads().elements())) { - for (Production greater : iterable(module.overloads().relations().get(lesser).getOrElse(() -> Collections.Set()))) { - genOverloadedAxiom(lesser, greater, semantics); - } + return prod; + }); + } + SetMultimap functionRules = HashMultimap.create(); + for (Rule rule : sortedRules) { + K left = RewriteToTop.toLeft(rule.body()); + if (left instanceof KApply kapp) { + Production prod = production(kapp); + if (prod.att().contains(Att.FUNCTION()) + || rule.att().contains(Att.ANYWHERE()) + || ExpandMacros.isMacro(rule)) { + functionRules.put(kapp.klabel(), rule); } + } + } - semantics.append("\n// rules\n"); + semantics.append("\n// symbols\n"); + Set overloads = new HashSet<>(); + for (Production lesser : iterable(module.overloads().elements())) { + for (Production greater : + iterable( + module.overloads().relations().get(lesser).getOrElse(Collections::Set))) { + overloads.add(greater); + } + } + translateSymbols(attributes, functionRules, overloads, semantics); + + // print syntax definition + syntax.append(semantics); + for (Tuple2> sort : + iterable(module.bracketProductionsFor())) { + for (Production prod : iterable(sort._2())) { + translateSymbol( + attributes, + functionRules, + overloads, + prod.att().get(Att.BRACKET_LABEL(), KLabel.class), + prod, + syntax); + } + } + for (Production prod : iterable(module.sortedProductions())) { + if (isBuiltinProduction(prod)) { + continue; + } + if (prod.isSubsort() && !prod.sort().equals(Sorts.K())) { + genSubsortAxiom(prod, syntax); + continue; + } + } - macros.append("// macros\n"); - int ruleIndex = 0; - ListMultimap priorityToAlias = ArrayListMultimap.create(); - for (Rule rule : sortedRules) { - if (ExpandMacros.isMacro(rule)) { - convertRule(rule, ruleIndex, heatCoolEq, topCellSortStr, attributes, functionRules, - priorityToPreviousGroup, priorityToAlias, sentenceType, macros); - } else { - convertRule(rule, ruleIndex, heatCoolEq, topCellSortStr, attributes, functionRules, - priorityToPreviousGroup, priorityToAlias, sentenceType, semantics); - } - ruleIndex++; - } + for (Production lesser : iterable(module.overloads().elements())) { + for (Production greater : + iterable( + module + .overloads() + .relations() + .get(lesser) + .getOrElse(() -> Collections.Set()))) { + genOverloadedAxiom(lesser, greater, syntax); + } + } - if (options.enableKoreAntileft) { - semantics.append("\n// priority groups\n"); - genPriorityGroups(priorityList, priorityToPreviousGroup, priorityToAlias, topCellSortStr, semantics); - } + syntax.append("endmodule []\n"); - semantics.append("endmodule "); - convert(attributes, module.att().remove(Att.DIGEST()), semantics, null, null); - semantics.append("\n"); + semantics.append("\n// generated axioms\n"); + Set> noConfusion = new HashSet<>(); + for (Production prod : iterable(module.sortedProductions())) { + if (isBuiltinProduction(prod)) { + continue; + } + if (prod.isSubsort() && !prod.sort().equals(Sorts.K())) { + genSubsortAxiom(prod, semantics); + continue; + } + if (prod.klabel().isEmpty()) { + continue; + } + if (prod.att().contains(Att.ASSOC())) { + genAssocAxiom(prod, semantics); + } + // if (prod.att().contains(Att.COMM())) { + // genCommAxiom(prod, semantics); + // } + if (prod.att().contains(Att.IDEM())) { + genIdemAxiom(prod, semantics); + } + if (isFunction(prod) && prod.att().contains(Att.UNIT())) { + genUnitAxiom(prod, semantics); + } + if (isFunctional(prod, functionRules)) { + genFunctionalAxiom(prod, semantics); + } + if (isConstructor(prod, functionRules)) { + genNoConfusionAxioms(prod, noConfusion, functionRules, semantics); + } } - private void collectTokenSortsAndAttributes(Set tokenSorts, Map attributes, - Set priorities, boolean heatCoolEq, String topCellSortStr) { - for (SortHead sort : iterable(module.sortedDefinedSorts())) { - Att att = module.sortAttributesFor().get(sort).getOrElse(() -> KORE.Att()); - if (att.contains(Att.TOKEN())) { - tokenSorts.add(sort); - } - collectAttributes(attributes, att); - } - for (Production prod : iterable(module.sortedProductions())) { - Att att = prod.att(); - if (att.contains(Att.TOKEN())) { - tokenSorts.add(prod.sort().head()); - } - collectAttributes(attributes, att); - } - for (Rule r : iterable(module.sortedRules())) { - Att att = r.att(); - collectAttributes(attributes, att); - RuleInfo ruleInfo = getRuleInfo(r, heatCoolEq, topCellSortStr); - // only collect priorities of semantics rules - if (!ruleInfo.isEquation && !ruleInfo.isKore && !ExpandMacros.isMacro(r)) { - priorities.add(getPriority(att)); - } - } + for (Sort sort : iterable(module.sortedAllSorts())) { + genNoJunkAxiom(sort, semantics); } - private void translateSorts(Set tokenSorts, Map attributes, - Set collectionSorts, StringBuilder sb) { - for (SortHead sort : iterable(module.sortedDefinedSorts())) { - if (sort.equals(Sorts.K().head()) || sort.equals(Sorts.KItem().head())) { - continue; - } - sb.append(" "); - Att att = module.sortAttributesFor().get(sort).getOrElse(() -> KORE.Att()); - if (att.contains(Att.HOOK())) { - if (collectionSorts.contains(att.get(Att.HOOK()))) { - if (att.get(Att.HOOK()).equals("ARRAY.Array")) { - att = att.remove(Att.ELEMENT()); - att = att.remove(Att.UNIT()); - att = att.remove(Att.HOOK()); - } else { - Production concatProd = stream(module.productionsForSort().apply(sort)).filter(p -> p.att().contains(Att.ELEMENT())).findAny().get(); - att = att.add(Att.ELEMENT(), K.class, KApply(KLabel(concatProd.att().get(Att.ELEMENT())))); - att = att.add(Att.CONCAT(), K.class, KApply(concatProd.klabel().get())); - att = att.add(Att.UNIT(), K.class, KApply(KLabel(concatProd.att().get(Att.UNIT())))); - sb.append("hooked-"); - } - } else { - sb.append("hooked-"); - } - } - att = att.remove(Att.HAS_DOMAIN_VALUES()); - if (tokenSorts.contains(sort)) { - att = att.add(Att.HAS_DOMAIN_VALUES()); - } - if (sort.params() == 0 && Sort(sort).isNat()) { - att = att.add(Att.NAT(), sort.name()); - } - sb.append("sort "); - convert(sort, sb); - sb.append(" "); - convert(attributes, att, sb, null, null); - sb.append("\n"); - } + for (Production lesser : iterable(module.overloads().elements())) { + for (Production greater : + iterable( + module + .overloads() + .relations() + .get(lesser) + .getOrElse(() -> Collections.Set()))) { + genOverloadedAxiom(lesser, greater, semantics); + } } - private void translateSymbols(Map attributes, SetMultimap functionRules, - Set overloads, StringBuilder sb) { - for (Production prod : iterable(module.sortedProductions())) { - if (isBuiltinProduction(prod)) { - continue; - } - if (prod.klabel().isEmpty()) { - continue; - } - translateSymbol(attributes, functionRules, overloads, prod.klabel().get(), prod, sb); - } + semantics.append("\n// rules\n"); + + macros.append("// macros\n"); + int ruleIndex = 0; + ListMultimap priorityToAlias = ArrayListMultimap.create(); + for (Rule rule : sortedRules) { + if (ExpandMacros.isMacro(rule)) { + convertRule( + rule, + ruleIndex, + heatCoolEq, + topCellSortStr, + attributes, + functionRules, + priorityToPreviousGroup, + priorityToAlias, + sentenceType, + macros); + } else { + convertRule( + rule, + ruleIndex, + heatCoolEq, + topCellSortStr, + attributes, + functionRules, + priorityToPreviousGroup, + priorityToAlias, + sentenceType, + semantics); + } + ruleIndex++; + } + + if (options.enableKoreAntileft) { + semantics.append("\n// priority groups\n"); + genPriorityGroups( + priorityList, priorityToPreviousGroup, priorityToAlias, topCellSortStr, semantics); + } + + semantics.append("endmodule "); + convert(attributes, module.att().remove(Att.DIGEST()), semantics, null, null); + semantics.append("\n"); + } + + private void collectTokenSortsAndAttributes( + Set tokenSorts, + Map attributes, + Set priorities, + boolean heatCoolEq, + String topCellSortStr) { + for (SortHead sort : iterable(module.sortedDefinedSorts())) { + Att att = module.sortAttributesFor().get(sort).getOrElse(() -> KORE.Att()); + if (att.contains(Att.TOKEN())) { + tokenSorts.add(sort); + } + collectAttributes(attributes, att); + } + for (Production prod : iterable(module.sortedProductions())) { + Att att = prod.att(); + if (att.contains(Att.TOKEN())) { + tokenSorts.add(prod.sort().head()); + } + collectAttributes(attributes, att); + } + for (Rule r : iterable(module.sortedRules())) { + Att att = r.att(); + collectAttributes(attributes, att); + RuleInfo ruleInfo = getRuleInfo(r, heatCoolEq, topCellSortStr); + // only collect priorities of semantics rules + if (!ruleInfo.isEquation && !ruleInfo.isKore && !ExpandMacros.isMacro(r)) { + priorities.add(getPriority(att)); + } } + } - private void translateSymbol(Map attributes, SetMultimap functionRules, Set overloads, - KLabel label, Production prod, StringBuilder sb) { - sb.append(" "); - if (isFunction(prod) && prod.att().contains(Att.HOOK()) && isRealHook(prod.att())) { + private void translateSorts( + Set tokenSorts, + Map attributes, + Set collectionSorts, + StringBuilder sb) { + for (SortHead sort : iterable(module.sortedDefinedSorts())) { + if (sort.equals(Sorts.K().head()) || sort.equals(Sorts.KItem().head())) { + continue; + } + sb.append(" "); + Att att = module.sortAttributesFor().get(sort).getOrElse(() -> KORE.Att()); + if (att.contains(Att.HOOK())) { + if (collectionSorts.contains(att.get(Att.HOOK()))) { + if (att.get(Att.HOOK()).equals("ARRAY.Array")) { + att = att.remove(Att.ELEMENT()); + att = att.remove(Att.UNIT()); + att = att.remove(Att.HOOK()); + } else { + Production concatProd = + stream(module.productionsForSort().apply(sort)) + .filter(p -> p.att().contains(Att.ELEMENT())) + .findAny() + .get(); + att = + att.add( + Att.ELEMENT(), K.class, KApply(KLabel(concatProd.att().get(Att.ELEMENT())))); + att = att.add(Att.CONCAT(), K.class, KApply(concatProd.klabel().get())); + att = att.add(Att.UNIT(), K.class, KApply(KLabel(concatProd.att().get(Att.UNIT())))); sb.append("hooked-"); + } + } else { + sb.append("hooked-"); } - sb.append("symbol "); - convert(label, prod.params(), sb); - String conn; - sb.append("("); - conn = ""; - for (NonTerminal nt : iterable(prod.nonterminals())) { - Sort sort = nt.sort(); - sb.append(conn); - convert(sort, prod, sb); - conn = ", "; - } - sb.append(") : "); - convert(prod.sort(), prod, sb); - sb.append(" "); - Att koreAtt = addKoreAttributes(prod, functionRules, overloads); - convert(attributes, koreAtt, sb, null, null); - sb.append("\n"); - } - - - private void genSubsortAxiom(Production prod, StringBuilder sb) { - Production finalProd = prod; - functionalPattern(prod, () -> { - sb.append("inj{"); - convert(finalProd.getSubsortSort(), finalProd, sb); - sb.append(", "); - convert(finalProd.sort(), finalProd, sb); - sb.append("} (From:"); - convert(finalProd.getSubsortSort(), finalProd, sb); - sb.append(")"); - }, sb); - sb.append(" [subsort{"); - convert(prod.getSubsortSort(), prod, sb); - sb.append(", "); - convert(prod.sort(), prod, sb); - sb.append("}()] // subsort\n"); + } + att = att.remove(Att.HAS_DOMAIN_VALUES()); + if (tokenSorts.contains(sort)) { + att = att.add(Att.HAS_DOMAIN_VALUES()); + } + if (sort.params() == 0 && Sort(sort).isNat()) { + att = att.add(Att.NAT(), sort.name()); + } + sb.append("sort "); + convert(sort, sb); + sb.append(" "); + convert(attributes, att, sb, null, null); + sb.append("\n"); + } + } + + private void translateSymbols( + Map attributes, + SetMultimap functionRules, + Set overloads, + StringBuilder sb) { + for (Production prod : iterable(module.sortedProductions())) { + if (isBuiltinProduction(prod)) { + continue; + } + if (prod.klabel().isEmpty()) { + continue; + } + translateSymbol(attributes, functionRules, overloads, prod.klabel().get(), prod, sb); + } + } + + private void translateSymbol( + Map attributes, + SetMultimap functionRules, + Set overloads, + KLabel label, + Production prod, + StringBuilder sb) { + sb.append(" "); + if (isFunction(prod) && prod.att().contains(Att.HOOK()) && isRealHook(prod.att())) { + sb.append("hooked-"); + } + sb.append("symbol "); + convert(label, prod.params(), sb); + String conn; + sb.append("("); + conn = ""; + for (NonTerminal nt : iterable(prod.nonterminals())) { + Sort sort = nt.sort(); + sb.append(conn); + convert(sort, prod, sb); + conn = ", "; + } + sb.append(") : "); + convert(prod.sort(), prod, sb); + sb.append(" "); + Att koreAtt = addKoreAttributes(prod, functionRules, overloads); + convert(attributes, koreAtt, sb, null, null); + sb.append("\n"); + } + + private void genSubsortAxiom(Production prod, StringBuilder sb) { + Production finalProd = prod; + functionalPattern( + prod, + () -> { + sb.append("inj{"); + convert(finalProd.getSubsortSort(), finalProd, sb); + sb.append(", "); + convert(finalProd.sort(), finalProd, sb); + sb.append("} (From:"); + convert(finalProd.getSubsortSort(), finalProd, sb); + sb.append(")"); + }, + sb); + sb.append(" [subsort{"); + convert(prod.getSubsortSort(), prod, sb); + sb.append(", "); + convert(prod.sort(), prod, sb); + sb.append("}()] // subsort\n"); + } + + private void genAssocAxiom(Production prod, StringBuilder sb) { + // s(s(K1,K2),K3) = s(K1,s(K2,K3)) + if (prod.arity() != 2) { + throw KEMException.compilerError( + "Found a non-binary production with the assoc attribute", prod); + } + if (!(module.subsorts().lessThanEq(prod.sort(), prod.nonterminal(0).sort()) + && module.subsorts().lessThanEq(prod.sort(), prod.nonterminal(1).sort()))) { + throw KEMException.compilerError( + "Found an associative production with ill formed sorts", prod); + } + sb.append(" axiom"); + convertParams(prod.klabel(), true, sb); + sb.append(" \\equals{"); + convert(prod.sort(), prod, sb); + sb.append(", R} ("); + convert(prod.klabel().get(), prod, sb); + sb.append("("); + convert(prod.klabel().get(), prod, sb); + sb.append("(K1:"); + convert(prod.sort(), prod, sb); + sb.append(",K2:"); + convert(prod.sort(), prod, sb); + sb.append("),K3:"); + convert(prod.sort(), prod, sb); + sb.append("),"); + convert(prod.klabel().get(), prod, sb); + sb.append("(K1:"); + convert(prod.sort(), prod, sb); + sb.append(","); + convert(prod.klabel().get(), prod, sb); + sb.append("(K2:"); + convert(prod.sort(), prod, sb); + sb.append(",K3:"); + convert(prod.sort(), prod, sb); + sb.append("))) [assoc{}()] // associativity\n"); + } + + private void genCommAxiom(Production prod, StringBuilder sb) { + // s(K1, K2) = s(K2, K1) + if (prod.arity() != 2) { + throw KEMException.compilerError( + "Found a non-binary production with the comm attribute", prod); + } + if (!(prod.nonterminal(0).sort().equals(prod.nonterminal(1).sort()))) { + throw KEMException.compilerError( + "Found a commutative production with ill formed sorts", prod); + } + Sort childSort = prod.nonterminal(0).sort(); + sb.append(" axiom"); + convertParams(prod.klabel(), true, sb); + sb.append(" \\equals{"); + convert(prod.sort(), prod, sb); + sb.append(", R} ("); + convert(prod.klabel().get(), prod, sb); + sb.append("(K1:"); + convert(childSort, prod, sb); + sb.append(",K2:"); + convert(childSort, prod, sb); + sb.append("),"); + convert(prod.klabel().get(), prod, sb); + sb.append("(K2:"); + convert(childSort, prod, sb); + sb.append(",K1:"); + convert(childSort, prod, sb); + sb.append(")) [comm{}()] // commutativity\n"); + } + + private void genIdemAxiom(Production prod, StringBuilder sb) { + // s(K, K) = K + if (prod.arity() != 2) { + throw KEMException.compilerError( + "Found a non-binary production with the assoc attribute", prod); + } + if (!(prod.sort().equals(prod.nonterminal(0).sort()) + && prod.sort().equals(prod.nonterminal(1).sort()))) { + throw KEMException.compilerError( + "Found an associative production with ill formed sorts", prod); + } + sb.append(" axiom"); + convertParams(prod.klabel(), true, sb); + sb.append(" \\equals{"); + convert(prod.sort(), prod, sb); + sb.append(", R} ("); + convert(prod.klabel().get(), prod, sb); + sb.append("(K:"); + convert(prod.sort(), prod, sb); + sb.append(",K:"); + convert(prod.sort(), prod, sb); + sb.append("),K:"); + convert(prod.sort(), prod, sb); + sb.append(") [idem{}()] // idempotency\n"); + } + + private void genUnitAxiom(Production prod, StringBuilder sb) { + // s(K, unit) = K + // s(unit, K) = K + if (prod.arity() != 2) { + throw KEMException.compilerError( + "Found a non-binary production with the assoc attribute", prod); + } + if (!(prod.sort().equals(prod.nonterminal(0).sort()) + && prod.sort().equals(prod.nonterminal(1).sort()))) { + throw KEMException.compilerError( + "Found an associative production with ill formed sorts", prod); + } + KLabel unit = KLabel(prod.att().get(Att.UNIT())); + sb.append(" axiom"); + convertParams(prod.klabel(), true, sb); + sb.append("\\equals{"); + convert(prod.sort(), prod, sb); + sb.append(", R} ("); + convert(prod.klabel().get(), prod, sb); + sb.append("(K:"); + convert(prod.sort(), prod, sb); + sb.append(","); + convert(unit, sb); + sb.append("()),K:"); + convert(prod.sort(), prod, sb); + sb.append(") [unit{}()] // right unit\n"); + + sb.append(" axiom"); + convertParams(prod.klabel(), true, sb); + sb.append("\\equals{"); + convert(prod.sort(), prod, sb); + sb.append(", R} ("); + convert(prod.klabel().get(), prod, sb); + sb.append("("); + convert(unit, sb); + sb.append("(),K:"); + convert(prod.sort(), prod, sb); + sb.append("),K:"); + convert(prod.sort(), prod, sb); + sb.append(") [unit{}()] // left unit\n"); + } + + private void genMapCeilAxioms(Production prod, Collection rules) { + Sort mapSort = prod.nonterminal(1).sort(); + scala.collection.Set mapProds = module.productionsForSort().apply(mapSort.head()); + Production concatProd = mapProds.find(p -> hasHookValue(p.att(), "MAP.concat")).get(); + Production elementProd = mapProds.find(p -> hasHookValue(p.att(), "MAP.element")).get(); + Seq nonterminals = elementProd.nonterminals(); + Sort sortParam = Sort(AddSortInjections.SORTPARAM_NAME, Sort("Q")); + + // rule + // #Ceil(MapItem(K1, K2, ..., Kn) Rest:Map) + // => + // {(@K1 in_keys(@Rest)) #Equals false} #And #Ceil(@K2) #And ... #And #Ceil(@Kn) + // Note: The {_ in_keys(_) #Equals false} condition implies + // #Ceil(@K1) and #Ceil(@Rest). + // [simplification] + + K restMapSet = KVariable("@Rest", Att.empty().add(Sort.class, mapSort)); + KLabel ceilMapLabel = KLabel(KLabels.ML_CEIL.name(), mapSort, sortParam); + KLabel andLabel = KLabel(KLabels.ML_AND.name(), sortParam); + + // arguments of MapItem and their #Ceils + List setArgs = new ArrayList<>(); + K setArgsCeil = KApply(KLabel(KLabels.ML_TRUE.name(), sortParam)); + for (int i = 0; i < nonterminals.length(); i++) { + Sort sort = nonterminals.apply(i).sort(); + KVariable setVar = KVariable("@K" + i, Att.empty().add(Sort.class, sort)); + setArgs.add(setVar); + if (i > 0) { + KLabel ceil = KLabel(KLabels.ML_CEIL.name(), sort, sortParam); + setArgsCeil = KApply(andLabel, setArgsCeil, KApply(ceil, setVar)); + } } - - private void genAssocAxiom(Production prod, StringBuilder sb) { - // s(s(K1,K2),K3) = s(K1,s(K2,K3)) - if (prod.arity() != 2) { - throw KEMException.compilerError("Found a non-binary production with the assoc attribute", prod); - } - if (!(module.subsorts().lessThanEq(prod.sort(), prod.nonterminal(0).sort()) && - module.subsorts().lessThanEq(prod.sort(), prod.nonterminal(1).sort()))) { - throw KEMException.compilerError("Found an associative production with ill formed sorts", prod); - } - sb.append(" axiom"); - convertParams(prod.klabel(), true, sb); - sb.append(" \\equals{"); - convert(prod.sort(), prod, sb); - sb.append(", R} ("); - convert(prod.klabel().get(), prod, sb); - sb.append("("); - convert(prod.klabel().get(), prod, sb); - sb.append("(K1:"); - convert(prod.sort(), prod, sb); - sb.append(",K2:"); - convert(prod.sort(), prod, sb); - sb.append("),K3:"); - convert(prod.sort(), prod, sb); - sb.append("),"); - convert(prod.klabel().get(), prod, sb); - sb.append("(K1:"); - convert(prod.sort(), prod, sb); - sb.append(","); - convert(prod.klabel().get(), prod, sb); - sb.append("(K2:"); - convert(prod.sort(), prod, sb); - sb.append(",K3:"); - convert(prod.sort(), prod, sb); - sb.append("))) [assoc{}()] // associativity\n"); - } - - private void genCommAxiom(Production prod, StringBuilder sb) { - // s(K1, K2) = s(K2, K1) - if (prod.arity() != 2) { - throw KEMException.compilerError("Found a non-binary production with the comm attribute", prod); - } - if (!(prod.nonterminal(0).sort().equals(prod.nonterminal(1).sort()))) { - throw KEMException.compilerError("Found a commutative production with ill formed sorts", prod); - } - Sort childSort = prod.nonterminal(0).sort(); - sb.append(" axiom"); - convertParams(prod.klabel(), true, sb); - sb.append(" \\equals{"); - convert(prod.sort(), prod, sb); - sb.append(", R} ("); - convert(prod.klabel().get(), prod, sb); - sb.append("(K1:"); - convert(childSort, prod, sb); - sb.append(",K2:"); - convert(childSort, prod, sb); - sb.append("),"); - convert(prod.klabel().get(), prod, sb); - sb.append("(K2:"); - convert(childSort, prod, sb); - sb.append(",K1:"); - convert(childSort, prod, sb); - sb.append(")) [comm{}()] // commutativity\n"); - } - - private void genIdemAxiom(Production prod, StringBuilder sb) { - // s(K, K) = K - if (prod.arity() != 2) { - throw KEMException.compilerError("Found a non-binary production with the assoc attribute", prod); - } - if (!(prod.sort().equals(prod.nonterminal(0).sort()) && prod.sort().equals(prod.nonterminal(1).sort()))) { - throw KEMException.compilerError("Found an associative production with ill formed sorts", prod); - } - sb.append(" axiom"); - convertParams(prod.klabel(), true, sb); - sb.append(" \\equals{"); - convert(prod.sort(), prod, sb); - sb.append(", R} ("); - convert(prod.klabel().get(), prod, sb); - sb.append("(K:"); - convert(prod.sort(), prod, sb); - sb.append(",K:"); - convert(prod.sort(), prod, sb); - sb.append("),K:"); - convert(prod.sort(), prod, sb); - sb.append(") [idem{}()] // idempotency\n"); - } - - private void genUnitAxiom(Production prod, StringBuilder sb) { - // s(K, unit) = K - // s(unit, K) = K - if (prod.arity() != 2) { - throw KEMException.compilerError("Found a non-binary production with the assoc attribute", prod); - } - if (!(prod.sort().equals(prod.nonterminal(0).sort()) && prod.sort().equals(prod.nonterminal(1).sort()))) { - throw KEMException.compilerError("Found an associative production with ill formed sorts", prod); - } - KLabel unit = KLabel(prod.att().get(Att.UNIT())); - sb.append(" axiom"); - convertParams(prod.klabel(), true, sb); - sb.append("\\equals{"); - convert(prod.sort(), prod, sb); - sb.append(", R} ("); - convert(prod.klabel().get(), prod, sb); - sb.append("(K:"); - convert(prod.sort(), prod, sb); - sb.append(","); - convert(unit, sb); - sb.append("()),K:"); - convert(prod.sort(), prod, sb); - sb.append(") [unit{}()] // right unit\n"); - - sb.append(" axiom"); - convertParams(prod.klabel(), true, sb); - sb.append("\\equals{"); - convert(prod.sort(), prod, sb); - sb.append(", R} ("); - convert(prod.klabel().get(), prod, sb); - sb.append("("); - convert(unit, sb); - sb.append("(),K:"); - convert(prod.sort(), prod, sb); - sb.append("),K:"); - convert(prod.sort(), prod, sb); - sb.append(") [unit{}()] // left unit\n"); - } - - private void genMapCeilAxioms(Production prod, Collection rules) { - Sort mapSort = prod.nonterminal(1).sort(); - scala.collection.Set mapProds = module.productionsForSort().apply(mapSort.head()); - Production concatProd = mapProds.find(p -> hasHookValue(p.att(), "MAP.concat")).get(); - Production elementProd = mapProds.find(p -> hasHookValue(p.att(), "MAP.element")).get(); - Seq nonterminals = elementProd.nonterminals(); - Sort sortParam = Sort(AddSortInjections.SORTPARAM_NAME, Sort("Q")); - - // rule - // #Ceil(MapItem(K1, K2, ..., Kn) Rest:Map) - // => - // {(@K1 in_keys(@Rest)) #Equals false} #And #Ceil(@K2) #And ... #And #Ceil(@Kn) - // Note: The {_ in_keys(_) #Equals false} condition implies - // #Ceil(@K1) and #Ceil(@Rest). - // [simplification] - - K restMapSet = KVariable("@Rest", Att.empty().add(Sort.class, mapSort)); - KLabel ceilMapLabel = KLabel(KLabels.ML_CEIL.name(), mapSort, sortParam); - KLabel andLabel = KLabel(KLabels.ML_AND.name(), sortParam); - - // arguments of MapItem and their #Ceils - List setArgs = new ArrayList<>(); - K setArgsCeil = KApply(KLabel(KLabels.ML_TRUE.name(), sortParam)); - for (int i = 0; i < nonterminals.length(); i++) { - Sort sort = nonterminals.apply(i).sort(); - KVariable setVar = KVariable("@K" + i, Att.empty().add(Sort.class, sort)); - setArgs.add(setVar); - if (i > 0) { - KLabel ceil = KLabel(KLabels.ML_CEIL.name(), sort, sortParam); - setArgsCeil = KApply(andLabel, setArgsCeil, KApply(ceil, setVar)); - } - } - Seq setArgsSeq = JavaConverters.iterableAsScalaIterable(setArgs).toSeq(); - - KLabel equalsLabel = KLabel(KLabels.ML_EQUALS.name(), Sorts.Bool(), sortParam); - Rule ceilMapRule = - Rule( - KRewrite( - KApply(ceilMapLabel, - KApply(concatProd.klabel().get(), - KApply(elementProd.klabel().get(), - setArgsSeq, - Att.empty() - ), - restMapSet - ) - ) - , - KApply(andLabel, - KApply(equalsLabel, - KApply(prod.klabel().get(), - setArgs.get(0), - restMapSet - ), - BooleanUtils.FALSE - ), - setArgsCeil - ) - ) - , BooleanUtils.TRUE - , BooleanUtils.TRUE - , Att.empty().add(Att.SIMPLIFICATION()) - ); - rules.add(ceilMapRule); - } - - static boolean hasHookValue(Att atts, String value) { - return atts.contains(Att.HOOK()) && - atts.get(Att.HOOK()).equals(value); - } - - private void genFunctionalAxiom(Production prod, StringBuilder sb) { - // exists y . f(...) = y - Production finalProd = prod; - functionalPattern(prod, () -> applyPattern(finalProd, "K", sb), sb); - sb.append(" [functional{}()] // functional\n"); - } - - private void genNoConfusionAxioms(Production prod, Set> noConfusion, - SetMultimap functionRulesMap, StringBuilder sb) { - // c(x1,x2,...) /\ c(y1,y2,...) -> c(x1/\y2,x2/\y2,...) - if (prod.arity() > 0) { - sb.append(" axiom"); - convertParams(prod.klabel(), false, sb); - sb.append("\\implies{"); - convert(prod.sort(), prod, sb); - sb.append("} (\\and{"); - convert(prod.sort(), prod, sb); - sb.append("} ("); - applyPattern(prod, "X", sb); - sb.append(", "); - applyPattern(prod, "Y", sb); - sb.append("), "); - convert(prod.klabel().get(), prod, sb); - sb.append("("); - String conn = ""; - for (int i = 0; i < prod.arity(); i++) { - sb.append(conn); - sb.append("\\and{"); - convert(prod.nonterminal(i).sort(), prod, sb); - sb.append("} (X").append(i).append(":"); - convert(prod.nonterminal(i).sort(), prod, sb); - sb.append(", Y").append(i).append(":"); - convert(prod.nonterminal(i).sort(), prod, sb); - sb.append(")"); - conn = ", "; - } - sb.append(")) [constructor{}()] // no confusion same constructor\n"); - } - for (Production prod2 : iterable(module.productionsForSort().apply(prod.sort().head()).toSeq().sorted(Production.ord()))) { - // !(cx(x1,x2,...) /\ cy(y1,y2,...)) - if (prod2.klabel().isEmpty() || noConfusion.contains(Tuple2.apply(prod, prod2)) || prod.equals(prod2) - || !isConstructor(prod2, functionRulesMap) || isBuiltinProduction(prod2)) { - // TODO (traiansf): add no confusion axioms for constructor vs inj. - continue; - } - noConfusion.add(Tuple2.apply(prod, prod2)); - noConfusion.add(Tuple2.apply(prod2, prod)); - sb.append(" axiom"); - convertParams(prod.klabel(), false, sb); - sb.append("\\not{"); - convert(prod.sort(), prod, sb); - sb.append("} (\\and{"); - convert(prod.sort(), prod, sb); - sb.append("} ("); - applyPattern(prod, "X", sb); - sb.append(", "); - applyPattern(prod2, "Y", sb); - sb.append(")) [constructor{}()] // no confusion different constructors\n"); + Seq setArgsSeq = JavaConverters.iterableAsScalaIterable(setArgs).toSeq(); + + KLabel equalsLabel = KLabel(KLabels.ML_EQUALS.name(), Sorts.Bool(), sortParam); + Rule ceilMapRule = + Rule( + KRewrite( + KApply( + ceilMapLabel, + KApply( + concatProd.klabel().get(), + KApply(elementProd.klabel().get(), setArgsSeq, Att.empty()), + restMapSet)), + KApply( + andLabel, + KApply( + equalsLabel, + KApply(prod.klabel().get(), setArgs.get(0), restMapSet), + BooleanUtils.FALSE), + setArgsCeil)), + BooleanUtils.TRUE, + BooleanUtils.TRUE, + Att.empty().add(Att.SIMPLIFICATION())); + rules.add(ceilMapRule); + } + + static boolean hasHookValue(Att atts, String value) { + return atts.contains(Att.HOOK()) && atts.get(Att.HOOK()).equals(value); + } + + private void genFunctionalAxiom(Production prod, StringBuilder sb) { + // exists y . f(...) = y + Production finalProd = prod; + functionalPattern(prod, () -> applyPattern(finalProd, "K", sb), sb); + sb.append(" [functional{}()] // functional\n"); + } + + private void genNoConfusionAxioms( + Production prod, + Set> noConfusion, + SetMultimap functionRulesMap, + StringBuilder sb) { + // c(x1,x2,...) /\ c(y1,y2,...) -> c(x1/\y2,x2/\y2,...) + if (prod.arity() > 0) { + sb.append(" axiom"); + convertParams(prod.klabel(), false, sb); + sb.append("\\implies{"); + convert(prod.sort(), prod, sb); + sb.append("} (\\and{"); + convert(prod.sort(), prod, sb); + sb.append("} ("); + applyPattern(prod, "X", sb); + sb.append(", "); + applyPattern(prod, "Y", sb); + sb.append("), "); + convert(prod.klabel().get(), prod, sb); + sb.append("("); + String conn = ""; + for (int i = 0; i < prod.arity(); i++) { + sb.append(conn); + sb.append("\\and{"); + convert(prod.nonterminal(i).sort(), prod, sb); + sb.append("} (X").append(i).append(":"); + convert(prod.nonterminal(i).sort(), prod, sb); + sb.append(", Y").append(i).append(":"); + convert(prod.nonterminal(i).sort(), prod, sb); + sb.append(")"); + conn = ", "; + } + sb.append(")) [constructor{}()] // no confusion same constructor\n"); + } + for (Production prod2 : + iterable( + module + .productionsForSort() + .apply(prod.sort().head()) + .toSeq() + .sorted(Production.ord()))) { + // !(cx(x1,x2,...) /\ cy(y1,y2,...)) + if (prod2.klabel().isEmpty() + || noConfusion.contains(Tuple2.apply(prod, prod2)) + || prod.equals(prod2) + || !isConstructor(prod2, functionRulesMap) + || isBuiltinProduction(prod2)) { + // TODO (traiansf): add no confusion axioms for constructor vs inj. + continue; + } + noConfusion.add(Tuple2.apply(prod, prod2)); + noConfusion.add(Tuple2.apply(prod2, prod)); + sb.append(" axiom"); + convertParams(prod.klabel(), false, sb); + sb.append("\\not{"); + convert(prod.sort(), prod, sb); + sb.append("} (\\and{"); + convert(prod.sort(), prod, sb); + sb.append("} ("); + applyPattern(prod, "X", sb); + sb.append(", "); + applyPattern(prod2, "Y", sb); + sb.append(")) [constructor{}()] // no confusion different constructors\n"); + } + } + + public static int getPriority(Att att) { + if (att.contains(Att.PRIORITY())) { + try { + return Integer.parseInt(att.get(Att.PRIORITY())); + } catch (NumberFormatException e) { + throw KEMException.compilerError( + "Invalid value for priority attribute: " + + att.get(Att.PRIORITY()) + + ". Must be an integer.", + e); + } + } else if (att.contains(Att.OWISE())) { + return 200; + } + return 50; + } + + private void genNoJunkAxiom(Sort sort, StringBuilder sb) { + StringBuilder sbTemp = new StringBuilder(); + sbTemp.append(" axiom{} "); + boolean hasToken = false; + int numTerms = 0; + sbTemp.append("\\or{"); + convert(sort, sbTemp); + sbTemp.append("} ("); + for (Production prod : + iterable( + mutable(module.productionsForSort()) + .getOrDefault(sort.head(), Set()) + .toSeq() + .sorted(Production.ord()))) { + if (isFunction(prod) || prod.isSubsort() || isBuiltinProduction(prod)) { + continue; + } + if (prod.klabel().isEmpty() + && !((prod.att().contains(Att.TOKEN()) && !hasToken) || prod.isSubsort())) { + continue; + } + numTerms++; + if (prod.att().contains(Att.TOKEN()) && !hasToken) { + convertTokenProd(sort, sbTemp); + hasToken = true; + } else if (prod.klabel().isDefined()) { + for (int i = 0; i < prod.arity(); i++) { + sbTemp.append("\\exists{"); + convert(sort, sbTemp); + sbTemp.append("} (X").append(i).append(":"); + convert(prod.nonterminal(i).sort(), prod, sbTemp); + sbTemp.append(", "); + } + convert(prod.klabel().get(), prod, sbTemp); + sbTemp.append("("); + String conn = ""; + for (int i = 0; i < prod.arity(); i++) { + sbTemp.append(conn).append("X").append(i).append(":"); + convert(prod.nonterminal(i).sort(), prod, sbTemp); + conn = ", "; } - } - - public static int getPriority(Att att) { - if (att.contains(Att.PRIORITY())) { - try { - return Integer.parseInt(att.get(Att.PRIORITY())); - } catch (NumberFormatException e) { - throw KEMException.compilerError("Invalid value for priority attribute: " + att.get(Att.PRIORITY()) + ". Must be an integer.", e); - } - } else if (att.contains(Att.OWISE())) { - return 200; + sbTemp.append(")"); + for (int i = 0; i < prod.arity(); i++) { + sbTemp.append(")"); } - return 50; + } + sbTemp.append(", "); } - - private void genNoJunkAxiom(Sort sort, StringBuilder sb) { - StringBuilder sbTemp = new StringBuilder(); - sbTemp.append(" axiom{} "); - boolean hasToken = false; - int numTerms = 0; - sbTemp.append("\\or{"); + for (Sort s : iterable(module.sortedAllSorts())) { + if (module.subsorts().lessThan(s, sort) && !sort.equals(Sorts.K())) { + numTerms++; + sbTemp.append("\\exists{"); convert(sort, sbTemp); - sbTemp.append("} ("); - for (Production prod : iterable(mutable(module.productionsForSort()).getOrDefault(sort.head(), Set()).toSeq().sorted(Production.ord()))) { - if (isFunction(prod) || prod.isSubsort() || isBuiltinProduction(prod)) { - continue; - } - if (prod.klabel().isEmpty() && !((prod.att().contains(Att.TOKEN()) && !hasToken) || prod.isSubsort())) { - continue; - } - numTerms++; - if (prod.att().contains(Att.TOKEN()) && !hasToken) { - convertTokenProd(sort, sbTemp); - hasToken = true; - } else if (prod.klabel().isDefined()) { - for (int i = 0; i < prod.arity(); i++) { - sbTemp.append("\\exists{"); - convert(sort, sbTemp); - sbTemp.append("} (X").append(i).append(":"); - convert(prod.nonterminal(i).sort(), prod, sbTemp); - sbTemp.append(", "); - } - convert(prod.klabel().get(), prod, sbTemp); - sbTemp.append("("); - String conn = ""; - for (int i = 0; i < prod.arity(); i++) { - sbTemp.append(conn).append("X").append(i).append(":"); - convert(prod.nonterminal(i).sort(), prod, sbTemp); - conn = ", "; - } - sbTemp.append(")"); - for (int i = 0; i < prod.arity(); i++) { - sbTemp.append(")"); - } - } - sbTemp.append(", "); - } - for (Sort s : iterable(module.sortedAllSorts())) { - if (module.subsorts().lessThan(s, sort) && !sort.equals(Sorts.K())) { - numTerms++; - sbTemp.append("\\exists{"); - convert(sort, sbTemp); - sbTemp.append("} (Val:"); - convert(s, sbTemp); - sbTemp.append(", inj{"); - convert(s, sbTemp); - sbTemp.append(", "); - convert(sort, sbTemp); - sbTemp.append("} (Val:"); - convert(s, sbTemp); - sbTemp.append("))"); - sbTemp.append(", "); - } - } - Att sortAtt = module.sortAttributesFor().get(sort.head()).getOrElse(() -> KORE.Att()); - if (!hasToken && sortAtt.contains(Att.TOKEN())) { - numTerms++; - convertTokenProd(sort, sbTemp); - sbTemp.append(", "); - hasToken = true; - } - sbTemp.append("\\bottom{"); + sbTemp.append("} (Val:"); + convert(s, sbTemp); + sbTemp.append(", inj{"); + convert(s, sbTemp); + sbTemp.append(", "); convert(sort, sbTemp); - sbTemp.append("}()) [constructor{}()] // no junk"); - if (hasToken && !METAVAR) { - sbTemp.append(" (TODO: fix bug with \\dv)"); + sbTemp.append("} (Val:"); + convert(s, sbTemp); + sbTemp.append("))"); + sbTemp.append(", "); + } + } + Att sortAtt = module.sortAttributesFor().get(sort.head()).getOrElse(() -> KORE.Att()); + if (!hasToken && sortAtt.contains(Att.TOKEN())) { + numTerms++; + convertTokenProd(sort, sbTemp); + sbTemp.append(", "); + hasToken = true; + } + sbTemp.append("\\bottom{"); + convert(sort, sbTemp); + sbTemp.append("}()) [constructor{}()] // no junk"); + if (hasToken && !METAVAR) { + sbTemp.append(" (TODO: fix bug with \\dv)"); + } + sbTemp.append("\n"); + + // If there are no terms, then we don't need to generate the axiom. + if (numTerms != 0) { + sb.append(sbTemp); + } + } + + private void genOverloadedAxiom(Production lesser, Production greater, StringBuilder sb) { + sb.append(" axiom{R} \\equals{"); + convert(greater.sort(), greater, sb); + sb.append(", R} ("); + convert(greater.klabel().get(), greater, sb); + sb.append("("); + String conn = ""; + for (int i = 0; i < greater.nonterminals().size(); i++) { + sb.append(conn); + if (greater.nonterminal(i).sort().equals(lesser.nonterminal(i).sort())) { + sb.append("K").append(i).append(":"); + convert(greater.nonterminal(i).sort(), greater, sb); + } else { + sb.append("inj{"); + convert(lesser.nonterminal(i).sort(), lesser, sb); + sb.append(", "); + convert(greater.nonterminal(i).sort(), greater, sb); + sb.append("} (K").append(i).append(":"); + convert(lesser.nonterminal(i).sort(), lesser, sb); + sb.append(")"); + } + conn = ","; + } + sb.append("), inj{"); + convert(lesser.sort(), lesser, sb); + sb.append(", "); + convert(greater.sort(), greater, sb); + sb.append("} ("); + convert(lesser.klabel().get(), lesser, sb); + sb.append("("); + conn = ""; + for (int i = 0; i < lesser.nonterminals().size(); i++) { + sb.append(conn); + sb.append("K").append(i).append(":"); + convert(lesser.nonterminal(i).sort(), lesser, sb); + conn = ","; + } + sb.append("))) [overload{}("); + convert(greater.klabel().get(), greater, sb); + sb.append("(), "); + convert(lesser.klabel().get(), lesser, sb); + sb.append("())] // overloaded production\n"); + } + + private boolean isRealHook(Att att) { + String hook = att.get(Att.HOOK()); + if (hook.startsWith("ARRAY.")) { + return false; + } + if (options.hookNamespaces.stream().anyMatch(ns -> hook.startsWith(ns + "."))) { + return true; + } + return Hooks.namespaces.stream().anyMatch(ns -> hook.startsWith(ns + ".")); + } + + private static boolean isBuiltinProduction(Production prod) { + return prod.klabel().nonEmpty() && ConstructorChecks.isBuiltinLabel(prod.klabel().get()); + } + + public String convertSpecificationModule( + Module definition, Module spec, SentenceType defaultSentenceType, StringBuilder sb) { + SentenceType sentenceType = getSentenceType(spec.att()).orElse(defaultSentenceType); + sb.setLength(0); // reset string writer + Sort topCellSort = Sorts.GeneratedTopCell(); + String topCellSortStr = getSortStr(topCellSort); + HashMap considerSource = new HashMap<>(); + considerSource.put(Att.SOURCE(), true); + convert( + considerSource, + Att.empty().add(Source.class, spec.att().get(Source.class)), + sb, + null, + null); + sb.append("\n"); + sb.append("module "); + convert(spec.name(), sb); + sb.append("\n\n// imports\n"); + sb.append("import "); + convert(definition.name(), sb); + sb.append(" []\n"); + sb.append("\n\n// claims\n"); + HashMap consideredAttributes = new HashMap<>(); + consideredAttributes.put(Att.PRIORITY(), true); + consideredAttributes.put(Att.LABEL(), true); + consideredAttributes.put(Att.GROUP(), true); + consideredAttributes.put(Att.SOURCE(), true); + consideredAttributes.put(Att.LOCATION(), true); + consideredAttributes.put(Att.UNIQUE_ID(), true); + + for (Sentence sentence : iterable(spec.sentencesExcept(definition))) { + if (sentence instanceof Claim + || (sentence instanceof Rule && sentence.att().contains(Att.SIMPLIFICATION()))) { + convertRule( + (RuleOrClaim) sentence, + 0, + false, + topCellSortStr, + consideredAttributes, + HashMultimap.create(), + new HashMap<>(), + ArrayListMultimap.create(), + sentenceType, + sb); + } + } + sb.append("endmodule "); + convert(consideredAttributes, spec.att().remove(Att.DIGEST()), sb, null, null); + sb.append("\n"); + return sb.toString(); + } + + private Optional getSentenceType(Att att) { + if (att.contains(Att.ONE_PATH())) { + return Optional.of(SentenceType.ONE_PATH); + } else if (att.contains(Att.ALL_PATH())) { + return Optional.of(SentenceType.ALL_PATH); + } + return Optional.empty(); + } + + private RuleInfo getRuleInfo(RuleOrClaim rule, boolean heatCoolEq, String topCellSortStr) { + boolean equation = false; + boolean owise = false; + boolean kore = rule.att().contains(Att.KORE()); + boolean ceil = false; + Production production = null; + Sort productionSort = null; + String productionSortStr = null; + List productionSorts = null; + KLabel productionLabel = null; + List leftChildren = null; + + K left = RewriteToTop.toLeft(rule.body()); + K leftPattern = left; + while (leftPattern instanceof KAs) { + leftPattern = ((KAs) leftPattern).pattern(); + } + if (leftPattern instanceof KApply) { + production = production((KApply) leftPattern, true); + productionSort = production.sort(); + productionSortStr = getSortStr(productionSort); + productionSorts = + stream(production.items()) + .filter(i -> i instanceof NonTerminal) + .map(i -> (NonTerminal) i) + .map(NonTerminal::sort) + .collect(Collectors.toList()); + productionLabel = production.klabel().get(); + if (productionLabel.name().equals("#Ceil") && rule.att().contains(Att.SIMPLIFICATION())) { + ceil = true; + } + if (isFunction(production) + || rule.att().contains(Att.SIMPLIFICATION()) + || rule.att().contains(Att.ANYWHERE()) && !kore) { + leftChildren = ((KApply) leftPattern).items(); + equation = true; + } else if ((rule.att().contains(Att.HEAT()) || rule.att().contains(Att.COOL())) + && heatCoolEq) { + equation = true; + productionSortStr = topCellSortStr; + } + owise = rule.att().contains(Att.OWISE()); + } + + return new RuleInfo( + equation, + owise, + kore, + ceil, + production, + productionSortStr, + productionSorts, + productionLabel, + leftChildren); + } + + private void convertRule( + RuleOrClaim rule, + int ruleIndex, + boolean heatCoolEq, + String topCellSortStr, + Map consideredAttributes, + SetMultimap functionRules, + Map priorityToPreviousGroup, + ListMultimap priorityToAlias, + SentenceType defaultSentenceType, + StringBuilder sb) { + SentenceType sentenceType = getSentenceType(rule.att()).orElse(defaultSentenceType); + // injections should already be present, but this is an ugly hack to get around the + // cache persistence issue that means that Sort attributes on k terms might not be present. + rule = addSortInjections.addInjections(rule); + Set existentials = getExistentials(rule); + ConstructorChecks constructorChecks = new ConstructorChecks(module); + K left = RewriteToTop.toLeft(rule.body()); + K requires = rule.requires(); + K right = RewriteToTop.toRight(rule.body()); + K ensures = rule.ensures(); + boolean constructorBased = constructorChecks.isConstructorBased(left); + RuleInfo ruleInfo = getRuleInfo(rule, heatCoolEq, topCellSortStr); + sb.append("// "); + sb.append(rule); + sb.append("\n"); + if (ruleInfo.isCeil && options.disableCeilSimplificationRules) { + return; + } + Set freeVariables = collectLHSFreeVariables(requires, left); + Map freeVarsMap = + freeVariables.stream().collect(Collectors.toMap(KVariable::name, Function.identity())); + if (ruleInfo.isEquation) { + assertNoExistentials(rule, existentials); + if (rule instanceof Claim) { + sb.append(" claim{R"); + if (kem != null) // TODO: remove once + // https://github.com/runtimeverification/haskell-backend/issues/3010 is + // implemented + kem.registerCompilerWarning( + KException.ExceptionType.FUTURE_ERROR, + "Functional claims not yet supported." + + " https://github.com/runtimeverification/haskell-backend/issues/3010", + rule); + } else { + sb.append(" axiom{R"); + } + Option sortParamsWrapper = rule.att().getOption(Att.SORT_PARAMS(), Sort.class); + Option> sortParams = + sortParamsWrapper.map( + s -> stream(s.params()).map(sort -> sort.name()).collect(Collectors.toSet())); + if (sortParams.nonEmpty()) { + for (Object sortParamName : sortParams.get()) sb.append("," + sortParamName); + } + sb.append("} "); + if (ruleInfo.isOwise) { + Set varNames = + freeVariables.stream().map(KVariable::name).collect(Collectors.toSet()); + sb.append("\\implies{R} (\n \\and{R} (\n \\not{R} (\n "); + for (Rule notMatching : + RefreshRules.refresh(functionRules.get(ruleInfo.productionLabel), varNames)) { + if (ignoreSideConditionsForOwise(notMatching)) { + continue; + } + sb.append("\\or{R} (\n"); + K notMatchingRequires = notMatching.requires(); + K notMatchingLeft = RewriteToTop.toLeft(notMatching.body()); + Set vars = collectLHSFreeVariables(notMatchingRequires, notMatchingLeft); + sb.append(" "); + for (KVariable var : vars) { + sb.append("\\exists{R} ("); + convert((K) var, sb); + sb.append(",\n "); + } + sb.append(" \\and{R} ("); + sb.append("\n "); + convertSideCondition(notMatchingRequires, sb); + sb.append(",\n "); + + assert notMatchingLeft instanceof KApply + : "expecting KApply but got " + notMatchingLeft.getClass(); + List notMatchingChildren = ((KApply) notMatchingLeft).items(); + assert notMatchingChildren.size() == ruleInfo.leftChildren.size() + : "assuming function with fixed arity"; + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append("\\and{R} ("); + sb.append("\n "); + sb.append("\\in{"); + Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); + convert(childSort, ruleInfo.production.params(), sb); + sb.append(", R} ("); + sb.append("\n "); + sb.append("X").append(childIdx).append(":"); + convert(childSort, ruleInfo.production.params(), sb); + sb.append(",\n "); + convert(notMatchingChildren.get(childIdx), sb); + sb.append("\n ),"); + } + sb.append("\n \\top{R} ()"); + sb.append("\n "); + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append(')'); + } + sb.append("\n )"); + for (KVariable ignored : vars) { + sb.append(")"); + } + sb.append(",\n "); } - sbTemp.append("\n"); - - // If there are no terms, then we don't need to generate the axiom. - if (numTerms != 0) { - sb.append(sbTemp); + sb.append("\\bottom{R}()"); + sb.append("\n "); + for (Rule notMatching : functionRules.get(ruleInfo.productionLabel)) { + if (ignoreSideConditionsForOwise(notMatching)) { + continue; + } + sb.append(")"); } - } + sb.append("\n ),\n \\and{R}(\n "); + convertSideCondition(requires, sb); + sb.append(",\n "); - private void genOverloadedAxiom(Production lesser, Production greater, StringBuilder sb) { - sb.append(" axiom{R} \\equals{"); - convert(greater.sort(), greater, sb); - sb.append(", R} ("); - convert(greater.klabel().get(), greater, sb); + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append("\\and{R} ("); + sb.append("\n "); + sb.append("\\in{"); + Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); + convert(childSort, ruleInfo.production.params(), sb); + sb.append(", R} ("); + sb.append("\n "); + sb.append("X").append(childIdx).append(":"); + convert(childSort, ruleInfo.production.params(), sb); + sb.append(",\n "); + convert(ruleInfo.leftChildren.get(childIdx), sb); + sb.append("\n ),"); + } + sb.append("\n \\top{R} ()"); + sb.append("\n "); + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append(')'); + } + + sb.append("\n )),\n \\equals{"); + sb.append(ruleInfo.productionSortStr); + sb.append(",R} (\n "); + convert(ruleInfo.productionLabel, sb); sb.append("("); String conn = ""; - for (int i = 0; i < greater.nonterminals().size(); i++) { - sb.append(conn); - if (greater.nonterminal(i).sort().equals(lesser.nonterminal(i).sort())) { - sb.append("K").append(i).append(":"); - convert(greater.nonterminal(i).sort(), greater, sb); - } else { - sb.append("inj{"); - convert(lesser.nonterminal(i).sort(), lesser, sb); - sb.append(", "); - convert(greater.nonterminal(i).sort(), greater, sb); - sb.append("} (K").append(i).append(":"); - convert(lesser.nonterminal(i).sort(), lesser, sb); - sb.append(")"); - } - conn = ","; + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append(conn).append("X").append(childIdx).append(":"); + Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); + convert(childSort, ruleInfo.production.params(), sb); + conn = ","; } - sb.append("), inj{"); - convert(lesser.sort(), lesser, sb); - sb.append(", "); - convert(greater.sort(), greater, sb); - sb.append("} ("); - convert(lesser.klabel().get(), lesser, sb); + sb.append(")"); + sb.append(",\n \\and{"); + sb.append(ruleInfo.productionSortStr); + sb.append("} (\n "); + convert(right, sb); + sb.append(",\n "); + convertSideCondition(ensures, ruleInfo.productionSortStr, sb); + sb.append(")))\n "); + convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); + sb.append("\n\n"); + } else if (rule.att().contains(Att.SIMPLIFICATION()) || rule instanceof Claim) { + sb.append("\\implies{R} (\n "); + convertSideCondition(requires, sb); + sb.append(",\n \\equals{"); + sb.append(ruleInfo.productionSortStr); + sb.append(",R} (\n "); + convert(left, sb); + sb.append(",\n \\and{"); + sb.append(ruleInfo.productionSortStr); + sb.append("} (\n "); + convert(right, sb); + sb.append(",\n "); + convertSideCondition(ensures, ruleInfo.productionSortStr, sb); + sb.append(")))\n "); + convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); + sb.append("\n\n"); + + } else { + sb.append("\\implies{R} (\n \\and{R}(\n "); + convertSideCondition(requires, sb); + sb.append(",\n "); + + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append("\\and{R} ("); + sb.append("\n "); + sb.append("\\in{"); + Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); + convert(childSort, ruleInfo.production.params(), sb); + sb.append(", R} ("); + sb.append("\n "); + sb.append("X").append(childIdx).append(":"); + convert(childSort, ruleInfo.production.params(), sb); + sb.append(",\n "); + convert(ruleInfo.leftChildren.get(childIdx), sb); + sb.append("\n ),"); + } + sb.append("\n \\top{R} ()"); + sb.append("\n "); + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append(')'); + } + sb.append("),\n \\equals{"); + sb.append(ruleInfo.productionSortStr); + sb.append(",R} (\n "); + convert(ruleInfo.productionLabel, sb); sb.append("("); - conn = ""; - for (int i = 0; i < lesser.nonterminals().size(); i++) { - sb.append(conn); - sb.append("K").append(i).append(":"); - convert(lesser.nonterminal(i).sort(), lesser, sb); - conn = ","; - } - sb.append("))) [overload{}("); - convert(greater.klabel().get(), greater, sb); - sb.append("(), "); - convert(lesser.klabel().get(), lesser, sb); - sb.append("())] // overloaded production\n"); - } - - private boolean isRealHook(Att att) { - String hook = att.get(Att.HOOK()); - if (hook.startsWith("ARRAY.")) { - return false; - } - if (options.hookNamespaces.stream().anyMatch(ns -> hook.startsWith(ns + "."))) { - return true; - } - return Hooks.namespaces.stream().anyMatch(ns -> hook.startsWith(ns + ".")); - } - - private static boolean isBuiltinProduction(Production prod) { - return prod.klabel().nonEmpty() && ConstructorChecks.isBuiltinLabel(prod.klabel().get()); - } - - public String convertSpecificationModule(Module definition, Module spec, SentenceType defaultSentenceType, StringBuilder sb) { - SentenceType sentenceType = getSentenceType(spec.att()).orElse(defaultSentenceType); - sb.setLength(0); // reset string writer - Sort topCellSort = Sorts.GeneratedTopCell(); - String topCellSortStr = getSortStr(topCellSort); - HashMap considerSource = new HashMap<>(); - considerSource.put(Att.SOURCE(), true); - convert(considerSource, Att.empty().add(Source.class, spec.att().get(Source.class)), sb, null, null); - sb.append("\n"); - sb.append("module "); - convert(spec.name(), sb); - sb.append("\n\n// imports\n"); - sb.append("import "); - convert(definition.name(), sb); - sb.append(" []\n"); - sb.append("\n\n// claims\n"); - HashMap consideredAttributes = new HashMap<>(); - consideredAttributes.put(Att.PRIORITY(), true); - consideredAttributes.put(Att.LABEL(), true); - consideredAttributes.put(Att.GROUP(), true); - consideredAttributes.put(Att.SOURCE(), true); - consideredAttributes.put(Att.LOCATION(), true); - consideredAttributes.put(Att.UNIQUE_ID(), true); - - for (Sentence sentence : iterable(spec.sentencesExcept(definition))) { - if (sentence instanceof Claim || (sentence instanceof Rule && sentence.att().contains(Att.SIMPLIFICATION()))) { - convertRule((RuleOrClaim) sentence, 0, false, topCellSortStr, - consideredAttributes, HashMultimap.create(), new HashMap<>(), ArrayListMultimap.create(), - sentenceType, sb); - } + String conn = ""; + for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { + sb.append(conn).append("X").append(childIdx).append(":"); + Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); + convert(childSort, ruleInfo.production.params(), sb); + conn = ","; } - sb.append("endmodule "); - convert(consideredAttributes, spec.att().remove(Att.DIGEST()), sb, null, null); - sb.append("\n"); - return sb.toString(); - } + sb.append(")"); + sb.append(",\n \\and{"); + sb.append(ruleInfo.productionSortStr); + sb.append("} (\n "); + convert(right, sb); + sb.append(",\n "); + convertSideCondition(ensures, ruleInfo.productionSortStr, sb); + sb.append(")))\n "); + convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); + sb.append("\n\n"); + } + } else if (ruleInfo.isKore) { + assertNoExistentials(rule, existentials); + if (rule instanceof Claim) { + sb.append(" claim{} "); + } else { + sb.append(" axiom{} "); + } + convert(left, sb); + sb.append("\n "); + convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); + sb.append("\n\n"); + } else if (!ExpandMacros.isMacro(rule)) { + // generate rule LHS + if (!(rule instanceof Claim)) { + // LHS for semantics rules + String ruleAliasName = String.format("rule%dLHS", ruleIndex); + int priority = getPriority(rule.att()); + List freeVars = new ArrayList<>(freeVariables); + Comparator compareByName = + (KVariable v1, KVariable v2) -> v1.name().compareTo(v2.name()); + java.util.Collections.sort(freeVars, compareByName); - private Optional getSentenceType(Att att) { - if (att.contains(Att.ONE_PATH())) { - return Optional.of(SentenceType.ONE_PATH); - } else if (att.contains(Att.ALL_PATH())) { - return Optional.of(SentenceType.ALL_PATH); - } - return Optional.empty(); - } - - private RuleInfo getRuleInfo(RuleOrClaim rule, boolean heatCoolEq, String topCellSortStr) { - boolean equation = false; - boolean owise = false; - boolean kore = rule.att().contains(Att.KORE()); - boolean ceil = false; - Production production = null; - Sort productionSort = null; - String productionSortStr = null; - List productionSorts = null; - KLabel productionLabel = null; - List leftChildren = null; - - K left = RewriteToTop.toLeft(rule.body()); - K leftPattern = left; - while (leftPattern instanceof KAs) { - leftPattern = ((KAs)leftPattern).pattern(); - } - if (leftPattern instanceof KApply) { - production = production((KApply) leftPattern, true); - productionSort = production.sort(); - productionSortStr = getSortStr(productionSort); - productionSorts = stream(production.items()) - .filter(i -> i instanceof NonTerminal) - .map(i -> (NonTerminal) i) - .map(NonTerminal::sort).collect(Collectors.toList()); - productionLabel = production.klabel().get(); - if (productionLabel.name().equals("#Ceil") && rule.att().contains(Att.SIMPLIFICATION())) { - ceil = true; - } - if (isFunction(production) || rule.att().contains(Att.SIMPLIFICATION()) || rule.att().contains(Att.ANYWHERE()) && !kore) { - leftChildren = ((KApply) leftPattern).items(); - equation = true; - } else if ((rule.att().contains(Att.HEAT()) || rule.att().contains(Att.COOL())) && heatCoolEq) { - equation = true; - productionSortStr = topCellSortStr; - } - owise = rule.att().contains(Att.OWISE()); + if (options.enableKoreAntileft) { + genAliasForSemanticsRuleLHS( + requires, + left, + ruleAliasName, + freeVars, + topCellSortStr, + priority, + priorityToAlias, + sb); + sb.append("\n"); } - return new RuleInfo(equation, owise, kore, ceil, production, - productionSortStr, productionSorts, productionLabel, leftChildren); - } - - private void convertRule(RuleOrClaim rule, int ruleIndex, boolean heatCoolEq, String topCellSortStr, - Map consideredAttributes, SetMultimap functionRules, - Map priorityToPreviousGroup, - ListMultimap priorityToAlias, - SentenceType defaultSentenceType, StringBuilder sb) { - SentenceType sentenceType = getSentenceType(rule.att()).orElse(defaultSentenceType); - // injections should already be present, but this is an ugly hack to get around the - // cache persistence issue that means that Sort attributes on k terms might not be present. - rule = addSortInjections.addInjections(rule); - Set existentials = getExistentials(rule); - ConstructorChecks constructorChecks = new ConstructorChecks(module); - K left = RewriteToTop.toLeft(rule.body()); - K requires = rule.requires(); - K right = RewriteToTop.toRight(rule.body()); - K ensures = rule.ensures(); - boolean constructorBased = constructorChecks.isConstructorBased(left); - RuleInfo ruleInfo = getRuleInfo(rule, heatCoolEq, topCellSortStr); - sb.append("// "); - sb.append(rule); - sb.append("\n"); - if (ruleInfo.isCeil && options.disableCeilSimplificationRules) { - return; - } - Set freeVariables = collectLHSFreeVariables(requires, left); - Map freeVarsMap = freeVariables - .stream().collect(Collectors.toMap(KVariable::name, Function.identity())); - if (ruleInfo.isEquation) { - assertNoExistentials(rule, existentials); - if (rule instanceof Claim) { - sb.append(" claim{R"); - if (kem != null) // TODO: remove once https://github.com/runtimeverification/haskell-backend/issues/3010 is implemented - kem.registerCompilerWarning(KException.ExceptionType.FUTURE_ERROR, "Functional claims not yet supported. https://github.com/runtimeverification/haskell-backend/issues/3010", rule); - } else { - sb.append(" axiom{R"); - } - Option sortParamsWrapper = rule.att().getOption(Att.SORT_PARAMS(), Sort.class); - Option> sortParams = sortParamsWrapper.map(s -> stream(s.params()).map(sort -> sort.name()).collect(Collectors.toSet())); - if (sortParams.nonEmpty()) { - for (Object sortParamName : sortParams.get()) - sb.append("," + sortParamName); - } - sb.append("} "); - if (ruleInfo.isOwise) { - Set varNames = freeVariables - .stream().map(KVariable::name).collect(Collectors.toSet()); - sb.append("\\implies{R} (\n \\and{R} (\n \\not{R} (\n "); - for (Rule notMatching : RefreshRules.refresh(functionRules.get(ruleInfo.productionLabel), varNames)) { - if (ignoreSideConditionsForOwise(notMatching)) { - continue; - } - sb.append("\\or{R} (\n"); - K notMatchingRequires = notMatching.requires(); - K notMatchingLeft = RewriteToTop.toLeft(notMatching.body()); - Set vars = collectLHSFreeVariables(notMatchingRequires, notMatchingLeft); - sb.append(" "); - for (KVariable var : vars) { - sb.append("\\exists{R} ("); - convert((K)var, sb); - sb.append(",\n "); - } - sb.append(" \\and{R} ("); - sb.append("\n "); - convertSideCondition(notMatchingRequires, sb); - sb.append(",\n "); - - assert notMatchingLeft instanceof KApply : "expecting KApply but got " + notMatchingLeft.getClass(); - List notMatchingChildren = ((KApply) notMatchingLeft).items(); - assert notMatchingChildren.size() == ruleInfo.leftChildren.size() : "assuming function with fixed arity"; - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append("\\and{R} ("); - sb.append("\n "); - sb.append("\\in{"); - Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); - convert(childSort, ruleInfo.production.params(), sb); - sb.append(", R} ("); - sb.append("\n "); - sb.append("X").append(childIdx).append(":"); - convert(childSort, ruleInfo.production.params(), sb); - sb.append(",\n "); - convert(notMatchingChildren.get(childIdx), sb); - sb.append("\n ),"); - } - sb.append("\n \\top{R} ()"); - sb.append("\n "); - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append(')'); - } - sb.append("\n )"); - for (KVariable ignored : vars) { - sb.append(")"); - } - sb.append(",\n "); - } - sb.append("\\bottom{R}()"); - sb.append("\n "); - for (Rule notMatching : functionRules.get(ruleInfo.productionLabel)) { - if (ignoreSideConditionsForOwise(notMatching)) { - continue; - } - sb.append(")"); - } - sb.append("\n ),\n \\and{R}(\n "); - convertSideCondition(requires, sb); - sb.append(",\n "); - - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append("\\and{R} ("); - sb.append("\n "); - sb.append("\\in{"); - Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); - convert(childSort, ruleInfo.production.params(), sb); - sb.append(", R} ("); - sb.append("\n "); - sb.append("X").append(childIdx).append(":"); - convert(childSort, ruleInfo.production.params(), sb); - sb.append(",\n "); - convert(ruleInfo.leftChildren.get(childIdx), sb); - sb.append("\n ),"); - } - sb.append("\n \\top{R} ()"); - sb.append("\n "); - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append(')'); - } + sb.append(" axiom{} "); + sb.append(String.format("\\rewrites{%s} (\n ", topCellSortStr)); - sb.append("\n )),\n \\equals{"); - sb.append(ruleInfo.productionSortStr); - sb.append(",R} (\n "); - convert(ruleInfo.productionLabel, sb); - sb.append("("); - String conn = ""; - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append(conn).append("X").append(childIdx).append(":"); - Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); - convert(childSort, ruleInfo.production.params(), sb); - conn = ","; - } - sb.append(")"); - sb.append(",\n \\and{"); - sb.append(ruleInfo.productionSortStr); - sb.append("} (\n "); - convert(right, sb); - sb.append(",\n "); - convertSideCondition(ensures, ruleInfo.productionSortStr, sb); - sb.append(")))\n "); - convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); - sb.append("\n\n"); - } else if (rule.att().contains(Att.SIMPLIFICATION()) || rule instanceof Claim) { - sb.append("\\implies{R} (\n "); - convertSideCondition(requires, sb); - sb.append(",\n \\equals{"); - sb.append(ruleInfo.productionSortStr); - sb.append(",R} (\n "); - convert(left, sb); - sb.append(",\n \\and{"); - sb.append(ruleInfo.productionSortStr); - sb.append("} (\n "); - convert(right, sb); - sb.append(",\n "); - convertSideCondition(ensures, ruleInfo.productionSortStr, sb); - sb.append(")))\n "); - convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); - sb.append("\n\n"); + if (options.enableKoreAntileft) { + genSemanticsRuleLHSWithAlias( + ruleAliasName, freeVars, topCellSortStr, priorityToPreviousGroup.get(priority), sb); + sb.append(",\n "); + } else { + genSemanticsRuleLHSNoAlias( + requires, left, freeVars, topCellSortStr, priorityToPreviousGroup.get(priority), sb); + sb.append(",\n "); + } + } else { + // LHS for claims + sb.append(" claim{} "); + sb.append(String.format("\\implies{%s} (\n ", topCellSortStr)); + sb.append(String.format(" \\and{%s} (\n ", topCellSortStr)); + convertSideCondition(requires, topCellSortStr, sb); + sb.append(", "); + convert(left, sb); + sb.append("), "); + } - } else { - sb.append("\\implies{R} (\n \\and{R}(\n "); - convertSideCondition(requires, sb); - sb.append(",\n "); - - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append("\\and{R} ("); - sb.append("\n "); - sb.append("\\in{"); - Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); - convert(childSort, ruleInfo.production.params(), sb); - sb.append(", R} ("); - sb.append("\n "); - sb.append("X").append(childIdx).append(":"); - convert(childSort, ruleInfo.production.params(), sb); - sb.append(",\n "); - convert(ruleInfo.leftChildren.get(childIdx), sb); - sb.append("\n ),"); - } - sb.append("\n \\top{R} ()"); - sb.append("\n "); - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append(')'); - } - sb.append("),\n \\equals{"); - sb.append(ruleInfo.productionSortStr); - sb.append(",R} (\n "); - convert(ruleInfo.productionLabel, sb); - sb.append("("); - String conn = ""; - for (int childIdx = 0; childIdx < ruleInfo.leftChildren.size(); childIdx++) { - sb.append(conn).append("X").append(childIdx).append(":"); - Sort childSort = ruleInfo.prodChildrenSorts.get(childIdx); - convert(childSort, ruleInfo.production.params(), sb); - conn = ","; - } - sb.append(")"); - sb.append(",\n \\and{"); - sb.append(ruleInfo.productionSortStr); - sb.append("} (\n "); - convert(right, sb); - sb.append(",\n "); - convertSideCondition(ensures, ruleInfo.productionSortStr, sb); - sb.append(")))\n "); - convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); - sb.append("\n\n"); - } - } else if (ruleInfo.isKore) { - assertNoExistentials(rule, existentials); - if (rule instanceof Claim) { - sb.append(" claim{} "); - } else { - sb.append(" axiom{} "); - } - convert(left, sb); - sb.append("\n "); - convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); - sb.append("\n\n"); - } else if (!ExpandMacros.isMacro(rule)) { - // generate rule LHS - if (!(rule instanceof Claim)) { - // LHS for semantics rules - String ruleAliasName = String.format("rule%dLHS", ruleIndex); - int priority = getPriority(rule.att()); - List freeVars = new ArrayList<>(freeVariables); - Comparator compareByName = (KVariable v1, KVariable v2) -> v1.name().compareTo(v2.name()); - java.util.Collections.sort(freeVars, compareByName); - - if (options.enableKoreAntileft) { - genAliasForSemanticsRuleLHS(requires, left, ruleAliasName, freeVars, topCellSortStr, - priority, priorityToAlias, sb); - sb.append("\n"); - } + // generate rule RHS + if (sentenceType == SentenceType.ALL_PATH) { + sb.append(String.format("%s{%s} (\n ", ALL_PATH_OP, topCellSortStr)); + } else if (sentenceType == SentenceType.ONE_PATH) { + sb.append(String.format("%s{%s} (\n ", ONE_PATH_OP, topCellSortStr)); + } + if (!existentials.isEmpty()) { + for (KVariable exists : existentials) { + sb.append(String.format(" \\exists{%s} (", topCellSortStr)); + convert((K) exists, sb); + sb.append(", "); + } + sb.append("\n "); + } + sb.append(String.format("\\and{%s} (\n ", topCellSortStr)); - sb.append(" axiom{} "); - sb.append(String.format("\\rewrites{%s} (\n ", topCellSortStr)); + if (options.enableKoreAntileft) { + convertSideCondition(ensures, topCellSortStr, sb); + sb.append(", "); + convert(right, sb); + } else { + convert(right, sb); + sb.append(", "); + convertSideCondition(ensures, topCellSortStr, sb); + } - if (options.enableKoreAntileft) { - genSemanticsRuleLHSWithAlias(ruleAliasName, freeVars, topCellSortStr, - priorityToPreviousGroup.get(priority), sb); - sb.append(",\n "); - } else { - genSemanticsRuleLHSNoAlias(requires, left, freeVars, topCellSortStr, priorityToPreviousGroup.get(priority), sb); - sb.append(",\n "); - } - } else { - // LHS for claims - sb.append(" claim{} "); - sb.append(String.format("\\implies{%s} (\n ", topCellSortStr)); - sb.append(String.format(" \\and{%s} (\n ", topCellSortStr)); - convertSideCondition(requires, topCellSortStr, sb); - sb.append(", "); - convert(left, sb); - sb.append("), "); - } - - // generate rule RHS - if (sentenceType == SentenceType.ALL_PATH) { - sb.append(String.format("%s{%s} (\n ", ALL_PATH_OP, topCellSortStr)); - } else if (sentenceType == SentenceType.ONE_PATH) { - sb.append(String.format("%s{%s} (\n ", ONE_PATH_OP, topCellSortStr)); - } - if (!existentials.isEmpty()) { - for (KVariable exists : existentials) { - sb.append(String.format(" \\exists{%s} (", topCellSortStr)); - convert((K)exists, sb); - sb.append(", "); - } - sb.append("\n "); - } - sb.append(String.format("\\and{%s} (\n ", topCellSortStr)); - - if (options.enableKoreAntileft) { - convertSideCondition(ensures, topCellSortStr, sb); - sb.append(", "); - convert(right, sb); - } else { - convert(right, sb); - sb.append(", "); - convertSideCondition(ensures, topCellSortStr, sb); - - } - - sb.append(')'); - for (KVariable ignored : existentials) { - sb.append(')'); - } - if (rule instanceof Claim) { - sb.append(')'); - } - sb.append(')'); - sb.append("\n "); - convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); - sb.append("\n\n"); - } else { - assertNoExistentials(rule, existentials); - sb.append(" axiom{R"); - Option sortParamsWrapper = rule.att().getOption(Att.SORT_PARAMS(), Sort.class); - Option> sortParams = sortParamsWrapper.map(s -> stream(s.params()).map(sort -> sort.name()).collect(Collectors.toSet())); - if (sortParams.nonEmpty()) { - for (Object sortParamName : sortParams.get()) - sb.append("," + sortParamName); - } - sb.append("} "); - sb.append("\\equals{"); - sb.append(ruleInfo.productionSortStr); - sb.append(",R} (\n "); - convert(left, sb); - sb.append(",\n "); - convert(right, sb); - sb.append(")\n "); - convert(consideredAttributes, rule.att().add(Att.PRIORITY(), Integer.toString(getPriority(rule.att()))), sb, freeVarsMap, rule); - sb.append("\n\n"); - } - } - - private boolean ignoreSideConditionsForOwise(Rule notMatching) { - return notMatching.att().contains(Att.OWISE()) - || notMatching.att().contains(Att.SIMPLIFICATION()) - || notMatching.att().contains(Att.NON_EXECUTABLE()); - } - - private void assertNoExistentials(Sentence sentence, Set existentials) { - if (!existentials.isEmpty()) { - throw KEMException.compilerError("Cannot encode equations with existential variables to KORE." + - "\n If this is desired, please use #Exists with regular variables." + - "\n Offending variables: " + existentials + - "\n context: " + sentence); - } - } - - private Set getExistentials(RuleOrClaim rule) { - Set res = new HashSet<>(); - VisitK visitor = new VisitK() { - @Override - public void apply(KVariable k) { - if (k.name().startsWith("?") || k.att().contains(Att.FRESH())) - res.add(k); - } + sb.append(')'); + for (KVariable ignored : existentials) { + sb.append(')'); + } + if (rule instanceof Claim) { + sb.append(')'); + } + sb.append(')'); + sb.append("\n "); + convert(consideredAttributes, rule.att(), sb, freeVarsMap, rule); + sb.append("\n\n"); + } else { + assertNoExistentials(rule, existentials); + sb.append(" axiom{R"); + Option sortParamsWrapper = rule.att().getOption(Att.SORT_PARAMS(), Sort.class); + Option> sortParams = + sortParamsWrapper.map( + s -> stream(s.params()).map(sort -> sort.name()).collect(Collectors.toSet())); + if (sortParams.nonEmpty()) { + for (Object sortParamName : sortParams.get()) sb.append("," + sortParamName); + } + sb.append("} "); + sb.append("\\equals{"); + sb.append(ruleInfo.productionSortStr); + sb.append(",R} (\n "); + convert(left, sb); + sb.append(",\n "); + convert(right, sb); + sb.append(")\n "); + convert( + consideredAttributes, + rule.att().add(Att.PRIORITY(), Integer.toString(getPriority(rule.att()))), + sb, + freeVarsMap, + rule); + sb.append("\n\n"); + } + } + + private boolean ignoreSideConditionsForOwise(Rule notMatching) { + return notMatching.att().contains(Att.OWISE()) + || notMatching.att().contains(Att.SIMPLIFICATION()) + || notMatching.att().contains(Att.NON_EXECUTABLE()); + } + + private void assertNoExistentials(Sentence sentence, Set existentials) { + if (!existentials.isEmpty()) { + throw KEMException.compilerError( + "Cannot encode equations with existential variables to KORE." + + "\n If this is desired, please use #Exists with regular variables." + + "\n Offending variables: " + + existentials + + "\n context: " + + sentence); + } + } + + private Set getExistentials(RuleOrClaim rule) { + Set res = new HashSet<>(); + VisitK visitor = + new VisitK() { + @Override + public void apply(KVariable k) { + if (k.name().startsWith("?") || k.att().contains(Att.FRESH())) res.add(k); + } }; - visitor.apply(rule.ensures()); - visitor.apply(RewriteToTop.toRight(rule.body())); - return res; - } - - private void genAliasForSemanticsRuleLHS(K requires, K left, - String ruleAliasName, List freeVars, String topCellSortStr, - Integer priority, ListMultimap priorityToAlias, - StringBuilder sb) { - sb.append(" alias "); - sb.append(ruleAliasName); - // We assume no sort variables. - sb.append("{}("); - String conn = ""; - for (KVariable var: freeVars) { - sb.append(conn); - convert(var.att().getOptional(Sort.class).orElse(Sorts.K()), sb); - conn = ","; - } - sb.append(") : "); - sb.append(topCellSortStr); - sb.append("\n where "); - genAliasDeclHead(ruleAliasName, freeVars, sb); - sb.append(") :=\n"); - sb.append(String.format(" \\and{%s} (\n ", topCellSortStr)); - convertSideCondition(requires, topCellSortStr, sb); + visitor.apply(rule.ensures()); + visitor.apply(RewriteToTop.toRight(rule.body())); + return res; + } + + private void genAliasForSemanticsRuleLHS( + K requires, + K left, + String ruleAliasName, + List freeVars, + String topCellSortStr, + Integer priority, + ListMultimap priorityToAlias, + StringBuilder sb) { + sb.append(" alias "); + sb.append(ruleAliasName); + // We assume no sort variables. + sb.append("{}("); + String conn = ""; + for (KVariable var : freeVars) { + sb.append(conn); + convert(var.att().getOptional(Sort.class).orElse(Sorts.K()), sb); + conn = ","; + } + sb.append(") : "); + sb.append(topCellSortStr); + sb.append("\n where "); + genAliasDeclHead(ruleAliasName, freeVars, sb); + sb.append(") :=\n"); + sb.append(String.format(" \\and{%s} (\n ", topCellSortStr)); + convertSideCondition(requires, topCellSortStr, sb); + sb.append(", "); + convert(left, sb); + sb.append(") []\n"); + + // build existential quantified pattern for alias + StringBuilder extStrBuilder = new StringBuilder(); + for (KVariable var : freeVars) { + extStrBuilder.append(String.format("\\exists{%s}(", topCellSortStr)); + convert((K) var, extStrBuilder); + extStrBuilder.append(","); + } + genAliasDeclHead(ruleAliasName, freeVars, extStrBuilder); + extStrBuilder.append(")"); + for (int i = 0; i < freeVars.size(); i++) { + extStrBuilder.append(")"); + } + priorityToAlias.put(priority, extStrBuilder.toString()); + } + + private void genAliasDeclHead(String aliasName, List freeVars, StringBuilder sb) { + sb.append(aliasName); + sb.append("{}("); + String conn = ""; + for (KVariable var : freeVars) { + sb.append(conn); + convert((K) var, sb); + conn = ","; + } + } + + private void genSemanticsRuleLHSWithAlias( + String ruleAliasName, + List freeVars, + String topCellSortStr, + String previousGroupName, + StringBuilder sb) { + if (!previousGroupName.equals("")) { + sb.append(String.format("\\and{%s}(\n ", topCellSortStr)); + sb.append(String.format("\\not{%s}(", topCellSortStr)); + sb.append(previousGroupName); + sb.append("{}()),\n "); + } + sb.append(ruleAliasName); + sb.append("{}("); + String conn = ""; + for (KVariable var : freeVars) { + sb.append(conn); + convert((K) var, sb); + conn = ","; + } + sb.append(")"); + if (!previousGroupName.equals("")) { + sb.append(")"); + } + } + + private void genSemanticsRuleLHSNoAlias( + K requires, + K left, + List freeVars, + String topCellSortStr, + String previousGroupName, + StringBuilder sb) { + sb.append(String.format(" \\and{%s} (\n ", topCellSortStr)); + convert(left, sb); + sb.append(",\n "); + convertSideCondition(requires, topCellSortStr, sb); + sb.append(")"); + } + + private void genPriorityGroups( + List priorityList, + Map priorityToPreviousGroup, + ListMultimap priorityToAlias, + String topCellSortStr, + StringBuilder sb) { + // skip generating alias for the last priority group + for (int index = 0; index < priorityList.size() - 1; index++) { + Integer priority = priorityList.get(index); + String priorityGroupName = String.format("priorityLE%d", priority); + sb.append(String.format(" alias %s{}() : %s", priorityGroupName, topCellSortStr)); + sb.append(String.format("\n where %s{}() := ", priorityGroupName)); + String previousGroupName = priorityToPreviousGroup.get(priority); + if (!previousGroupName.equals("")) { + sb.append(String.format("\\or{%s}(\n ", topCellSortStr)); + sb.append(previousGroupName); + sb.append("{}(), "); + } + // generate priority group body + List aliases = priorityToAlias.get(priority); + for (String ruleLHSAlias : aliases) { + sb.append(String.format("\\or{%s}(\n ", topCellSortStr)); + sb.append(ruleLHSAlias); sb.append(", "); - convert(left, sb); - sb.append(") []\n"); - - // build existential quantified pattern for alias - StringBuilder extStrBuilder = new StringBuilder(); - for (KVariable var: freeVars) { - extStrBuilder.append(String.format("\\exists{%s}(", topCellSortStr)); - convert((K)var, extStrBuilder); - extStrBuilder.append(","); - } - genAliasDeclHead(ruleAliasName, freeVars, extStrBuilder); - extStrBuilder.append(")"); - for (int i = 0; i < freeVars.size(); i++) { - extStrBuilder.append(")"); - } - priorityToAlias.put(priority, extStrBuilder.toString()); - } - - private void genAliasDeclHead(String aliasName, List freeVars, StringBuilder sb) { - sb.append(aliasName); - sb.append("{}("); - String conn = ""; - for (KVariable var: freeVars) { - sb.append(conn); - convert((K)var, sb); - conn = ","; - } - } - - private void genSemanticsRuleLHSWithAlias(String ruleAliasName, List freeVars, String topCellSortStr, - String previousGroupName, StringBuilder sb) { - if (!previousGroupName.equals("")) { - sb.append(String.format("\\and{%s}(\n ", topCellSortStr)); - sb.append(String.format("\\not{%s}(", topCellSortStr)); - sb.append(previousGroupName); - sb.append("{}()),\n "); - } - sb.append(ruleAliasName); - sb.append("{}("); - String conn = ""; - for (KVariable var: freeVars) { - sb.append(conn); - convert((K)var, sb); - conn = ","; - } + } + // bottom is the unit of "or" + sb.append(String.format("\\bottom{%s}()", topCellSortStr)); + // complete parenthesis + for (int i = 0; i < aliases.size(); i++) { sb.append(")"); - if (!previousGroupName.equals("")) { - sb.append(")"); - } - } - - private void genSemanticsRuleLHSNoAlias(K requires, K left, List freeVars, String topCellSortStr, - String previousGroupName, StringBuilder sb) { - sb.append(String.format(" \\and{%s} (\n ", topCellSortStr)); - convert(left, sb); - sb.append(",\n "); - convertSideCondition(requires, topCellSortStr, sb); + } + if (!previousGroupName.equals("")) { sb.append(")"); + } + sb.append(" []\n\n"); + } + } + + private void functionalPattern(Production prod, Runnable functionPattern, StringBuilder sb) { + sb.append(" axiom"); + convertParams(prod.klabel(), true, sb); + sb.append(" \\exists{R} (Val:"); + convert(prod.sort(), prod, sb); + sb.append(", \\equals{"); + convert(prod.sort(), prod, sb); + sb.append(", R} ("); + sb.append("Val:"); + convert(prod.sort(), prod, sb); + sb.append(", "); + functionPattern.run(); + sb.append("))"); + } + + private void applyPattern(Production prod, String varName, StringBuilder sb) { + convert(prod.klabel().get(), prod, sb); + sb.append("("); + String conn = ""; + for (int i = 0; i < prod.arity(); i++) { + sb.append(conn); + sb.append(varName).append(i).append(":"); + convert(prod.nonterminal(i).sort(), prod, sb); + conn = ", "; + } + sb.append(')'); + } + + private void convertTokenProd(Sort sort, StringBuilder sb) { + if (METAVAR) { + sb.append("\\exists{"); + convert(sort, sb); + sb.append("} (#Str:#String{}, \\dv{"); + convert(sort, sb); + sb.append("}(#Str:#String{}))"); + } else { + sb.append("\\top{"); + convert(sort, sb); + sb.append("}()"); + } + } + + private void convertParams(Option maybeKLabel, boolean hasR, StringBuilder sb) { + sb.append("{"); + String conn = ""; + if (hasR) { + sb.append("R"); + if (maybeKLabel.isDefined()) { + conn = ", "; + } } - - private void genPriorityGroups(List priorityList, - Map priorityToPreviousGroup, - ListMultimap priorityToAlias, - String topCellSortStr, StringBuilder sb) { - // skip generating alias for the last priority group - for (int index = 0; index < priorityList.size()-1; index++) { - Integer priority = priorityList.get(index); - String priorityGroupName = String.format("priorityLE%d", priority); - sb.append(String.format(" alias %s{}() : %s", priorityGroupName, topCellSortStr)); - sb.append(String.format("\n where %s{}() := ", priorityGroupName)); - String previousGroupName = priorityToPreviousGroup.get(priority); - if (!previousGroupName.equals("")) { - sb.append(String.format("\\or{%s}(\n ", topCellSortStr)); - sb.append(previousGroupName); - sb.append("{}(), "); - } - // generate priority group body - List aliases = priorityToAlias.get(priority); - for (String ruleLHSAlias : aliases) { - sb.append(String.format("\\or{%s}(\n ", topCellSortStr)); - sb.append(ruleLHSAlias); - sb.append(", "); - } - // bottom is the unit of "or" - sb.append(String.format("\\bottom{%s}()", topCellSortStr)); - // complete parenthesis - for (int i = 0; i < aliases.size(); i++) { - sb.append(")"); - } - if (!previousGroupName.equals("")) { - sb.append(")"); - } - sb.append(" []\n\n"); - } + if (maybeKLabel.isDefined()) { + for (Sort param : iterable(maybeKLabel.get().params())) { + sb.append(conn); + convert(param, Seq(param), sb); + conn = ", "; + } } - - private void functionalPattern(Production prod, Runnable functionPattern, StringBuilder sb) { - sb.append(" axiom"); - convertParams(prod.klabel(), true, sb); - sb.append(" \\exists{R} (Val:"); - convert(prod.sort(), prod, sb); - sb.append(", \\equals{"); - convert(prod.sort(), prod, sb); - sb.append(", R} ("); - sb.append("Val:"); - convert(prod.sort(), prod, sb); - sb.append(", "); - functionPattern.run(); - sb.append("))"); + sb.append("}"); + } + + private boolean isConstructor(Production prod, SetMultimap functionRules) { + Att att = addKoreAttributes(prod, functionRules, java.util.Collections.emptySet()); + return att.contains(Att.CONSTRUCTOR()); + } + + private boolean isFunctional(Production prod, SetMultimap functionRules) { + Att att = addKoreAttributes(prod, functionRules, java.util.Collections.emptySet()); + return att.contains(Att.FUNCTIONAL()); + } + + private boolean isGeneratedInKeysOp(Production prod) { + Option hook = prod.att().getOption(Att.HOOK()); + if (hook.isEmpty()) return false; + if (!hook.get().equals("MAP.in_keys")) return false; + return (!prod.klabel().isEmpty()); + } + + private Att addKoreAttributes( + Production prod, SetMultimap functionRules, Set overloads) { + boolean isFunctional = !isFunction(prod) || prod.att().contains(Att.TOTAL()); + boolean isConstructor = !isFunction(prod); + isConstructor &= !prod.att().contains(Att.ASSOC()); + isConstructor &= !prod.att().contains(Att.COMM()); + isConstructor &= !prod.att().contains(Att.IDEM()); + isConstructor &= !(prod.att().contains(Att.FUNCTION()) && prod.att().contains(Att.UNIT())); + + // Later we might set !isConstructor because there are anywhere rules, + // but if a symbol is a constructor at this point, then it is still + // injective. + boolean isInjective = isConstructor; + + boolean isMacro = false; + boolean isAnywhere = overloads.contains(prod); + if (prod.klabel().isDefined()) { + for (Rule r : functionRules.get(prod.klabel().get())) { + isMacro |= ExpandMacros.isMacro(r); + isAnywhere |= r.att().contains(Att.ANYWHERE()); + } } + isConstructor &= !isMacro; + isConstructor &= !isAnywhere; - private void applyPattern(Production prod, String varName, StringBuilder sb) { - convert(prod.klabel().get(), prod, sb); - sb.append("("); - String conn = ""; - for (int i = 0; i < prod.arity(); i++) { - sb.append(conn); - sb.append(varName).append(i).append(":"); - convert(prod.nonterminal(i).sort(), prod, sb); - conn = ", "; - } - sb.append(')'); + Att att = prod.att().remove(Att.CONSTRUCTOR()); + if (att.contains(Att.HOOK()) && !isRealHook(att)) { + att = att.remove(Att.HOOK()); } - - private void convertTokenProd(Sort sort, StringBuilder sb) { - if (METAVAR) { - sb.append("\\exists{"); - convert(sort, sb); - sb.append("} (#Str:#String{}, \\dv{"); - convert(sort, sb); - sb.append("}(#Str:#String{}))"); - } else { - sb.append("\\top{"); - convert(sort, sb); - sb.append("}()"); - } + if (isConstructor) { + att = att.add(Att.CONSTRUCTOR()); } - - private void convertParams(Option maybeKLabel, boolean hasR, StringBuilder sb) { - sb.append("{"); - String conn = ""; - if (hasR) { - sb.append("R"); - if (maybeKLabel.isDefined()) { - conn = ", "; - } - } - if (maybeKLabel.isDefined()) { - for (Sort param : iterable(maybeKLabel.get().params())) { - sb.append(conn); - convert(param, Seq(param), sb); - conn = ", "; - } - } - sb.append("}"); + if (isFunctional) { + att = att.add(Att.FUNCTIONAL()); } - - private boolean isConstructor(Production prod, SetMultimap functionRules) { - Att att = addKoreAttributes(prod, functionRules, java.util.Collections.emptySet()); - return att.contains(Att.CONSTRUCTOR()); + if (isAnywhere) { + att = att.add(Att.ANYWHERE()); } - - private boolean isFunctional(Production prod, SetMultimap functionRules) { - Att att = addKoreAttributes(prod, functionRules, java.util.Collections.emptySet()); - return att.contains(Att.FUNCTIONAL()); + if (isInjective) { + att = att.add(Att.INJECTIVE()); } - - private boolean isGeneratedInKeysOp(Production prod) { - Option hook = prod.att().getOption(Att.HOOK()); - if (hook.isEmpty()) return false; - if (!hook.get().equals("MAP.in_keys")) return false; - return (!prod.klabel().isEmpty()); + if (isMacro) { + att = att.add(Att.MACRO()); } + // update format attribute with structure expected by backend + String format = + att.getOptional(Att.FORMAT()).orElse(Formatter.defaultFormat(prod.items().size())); + int nt = 1; + boolean hasFormat = true; + boolean printName = + stream(prod.items()) + .noneMatch(pi -> pi instanceof NonTerminal && ((NonTerminal) pi).name().isEmpty()); + boolean printEllipses = false; - private Att addKoreAttributes(Production prod, SetMultimap functionRules, Set overloads) { - boolean isFunctional = !isFunction(prod) || prod.att().contains(Att.TOTAL()); - boolean isConstructor = !isFunction(prod); - isConstructor &= !prod.att().contains(Att.ASSOC()); - isConstructor &= !prod.att().contains(Att.COMM()); - isConstructor &= !prod.att().contains(Att.IDEM()); - isConstructor &= !(prod.att().contains(Att.FUNCTION()) && prod.att().contains(Att.UNIT())); - - // Later we might set !isConstructor because there are anywhere rules, - // but if a symbol is a constructor at this point, then it is still - // injective. - boolean isInjective = isConstructor; - - boolean isMacro = false; - boolean isAnywhere = overloads.contains(prod); - if (prod.klabel().isDefined()) { - for (Rule r : functionRules.get(prod.klabel().get())) { - isMacro |= ExpandMacros.isMacro(r); - isAnywhere |= r.att().contains(Att.ANYWHERE()); - } - } - isConstructor &= !isMacro; - isConstructor &= !isAnywhere; - - Att att = prod.att().remove(Att.CONSTRUCTOR()); - if (att.contains(Att.HOOK()) && !isRealHook(att)) { - att = att.remove(Att.HOOK()); - } - if (isConstructor) { - att = att.add(Att.CONSTRUCTOR()); - } - if (isFunctional) { - att = att.add(Att.FUNCTIONAL()); - } - if (isAnywhere) { - att = att.add(Att.ANYWHERE()); - } - if (isInjective) { - att = att.add(Att.INJECTIVE()); - } - if (isMacro) { - att = att.add(Att.MACRO()); - } - // update format attribute with structure expected by backend - String format = att.getOptional(Att.FORMAT()).orElse(Formatter.defaultFormat(prod.items().size())); - int nt = 1; - boolean hasFormat = true; - boolean printName = stream(prod.items()).noneMatch(pi -> pi instanceof NonTerminal && ((NonTerminal) pi).name().isEmpty()); - boolean printEllipses = false; - - for (int i = 0; i < prod.items().size(); i++) { - if (prod.items().apply(i) instanceof NonTerminal) { - String replacement; - if (printName && prod.isPrefixProduction()) { - replacement = ((NonTerminal) prod.items().apply(i)).name().get() + ": %" + (nt++); - printEllipses = true; - } else { - replacement = "%" + (nt++); - } - format = format.replaceAll("%" + (i+1) + "(?![0-9])", replacement); - } else if (prod.items().apply(i) instanceof Terminal) { - format = format.replaceAll("%" + (i+1) + "(?![0-9])", "%c" + ((Terminal)prod.items().apply(i)).value().replace("\\", "\\\\").replace("$", "\\$").replace("%", "%%") + "%r"); - } else { - hasFormat = false; + for (int i = 0; i < prod.items().size(); i++) { + if (prod.items().apply(i) instanceof NonTerminal) { + String replacement; + if (printName && prod.isPrefixProduction()) { + replacement = ((NonTerminal) prod.items().apply(i)).name().get() + ": %" + (nt++); + printEllipses = true; + } else { + replacement = "%" + (nt++); + } + format = format.replaceAll("%" + (i + 1) + "(?![0-9])", replacement); + } else if (prod.items().apply(i) instanceof Terminal) { + format = + format.replaceAll( + "%" + (i + 1) + "(?![0-9])", + "%c" + + ((Terminal) prod.items().apply(i)) + .value() + .replace("\\", "\\\\") + .replace("$", "\\$") + .replace("%", "%%") + + "%r"); + } else { + hasFormat = false; + } + } + if (printEllipses && format.contains("(")) { + int idxLParam = format.indexOf("(") + 1; + format = format.substring(0, idxLParam) + "... " + format.substring(idxLParam); + } + if (hasFormat) { + att = att.add(Att.FORMAT(), format); + if (att.contains(Att.COLOR())) { + boolean escape = false; + StringBuilder colors = new StringBuilder(); + String conn = ""; + for (int i = 0; i < format.length(); i++) { + if (escape && format.charAt(i) == 'c') { + colors.append(conn).append(att.get(Att.COLOR())); + conn = ","; } + escape = format.charAt(i) == '%'; } - if (printEllipses && format.contains("(")) { - int idxLParam = format.indexOf("(") + 1; - format = format.substring(0, idxLParam) + "... " + format.substring(idxLParam); + att = att.add(Att.COLORS(), colors.toString()); + } + StringBuilder sb = new StringBuilder(); + for (ProductionItem pi : iterable(prod.items())) { + if (pi instanceof NonTerminal) { + sb.append('0'); + } else { + sb.append('1'); } - if (hasFormat) { - att = att.add(Att.FORMAT(), format); - if (att.contains(Att.COLOR())) { - boolean escape = false; - StringBuilder colors = new StringBuilder(); - String conn = ""; - for (int i = 0; i < format.length(); i++) { - if (escape && format.charAt(i) == 'c') { - colors.append(conn).append(att.get(Att.COLOR())); - conn = ","; - } - escape = format.charAt(i) == '%'; - } - att = att.add(Att.COLORS(), colors.toString()); - } - StringBuilder sb = new StringBuilder(); - for (ProductionItem pi : iterable(prod.items())) { - if (pi instanceof NonTerminal) { - sb.append('0'); - } else { - sb.append('1'); - } - } - att = att.add(Att.TERMINALS(), sb.toString()); - if (prod.klabel().isDefined()) { - List lessThanK = new ArrayList<>(); - Option> lessThan = module.priorities().relations().get(Tag(prod.klabel().get().name())); - if (lessThan.isDefined()) { - for (Tag t : iterable(lessThan.get())) { - if (ConstructorChecks.isBuiltinLabel(KLabel(t.name()))) { - continue; - } - lessThanK.add(KApply(KLabel(t.name()))); - } - } - att = att.add(Att.PRIORITIES(), KList.class, KList(lessThanK)); - att = att.remove(Att.LEFT()); - att = att.remove(Att.RIGHT()); - att = att.add(Att.LEFT_INTERNAL(), KList.class, getAssoc(module.leftAssoc(), prod.klabel().get())); - att = att.add(Att.RIGHT_INTERNAL(), KList.class, getAssoc(module.rightAssoc(), prod.klabel().get())); + } + att = att.add(Att.TERMINALS(), sb.toString()); + if (prod.klabel().isDefined()) { + List lessThanK = new ArrayList<>(); + Option> lessThan = + module.priorities().relations().get(Tag(prod.klabel().get().name())); + if (lessThan.isDefined()) { + for (Tag t : iterable(lessThan.get())) { + if (ConstructorChecks.isBuiltinLabel(KLabel(t.name()))) { + continue; + } + lessThanK.add(KApply(KLabel(t.name()))); } - } else { - att = att.remove(Att.FORMAT()); } - // This attribute is a frontend attribute only and is removed from the kore - // Since it has no meaning outside the frontend - return att.remove(Att.ORIGINAL_PRD(), Production.class); - } - - private KList getAssoc(scala.collection.Set> assoc, KLabel klabel) { - return KList(stream(assoc).filter(t -> t._1().name().equals(klabel.name())).map(t -> KApply(KLabel(t._2().name()))).collect(Collectors.toList())); - } - - private boolean isFunction(Production prod) { - return prod.att().contains(Att.FUNCTION()); - } - - // Assume that there is no quantifiers - private Set collectLHSFreeVariables(K requires, K left) { - Set res = new HashSet<>(); - VisitK visitor = new VisitK() { - @Override - public void apply(KVariable k) { - res.add(k); - } + att = att.add(Att.PRIORITIES(), KList.class, KList(lessThanK)); + att = att.remove(Att.LEFT()); + att = att.remove(Att.RIGHT()); + att = + att.add( + Att.LEFT_INTERNAL(), + KList.class, + getAssoc(module.leftAssoc(), prod.klabel().get())); + att = + att.add( + Att.RIGHT_INTERNAL(), + KList.class, + getAssoc(module.rightAssoc(), prod.klabel().get())); + } + } else { + att = att.remove(Att.FORMAT()); + } + // This attribute is a frontend attribute only and is removed from the kore + // Since it has no meaning outside the frontend + return att.remove(Att.ORIGINAL_PRD(), Production.class); + } + + private KList getAssoc(scala.collection.Set> assoc, KLabel klabel) { + return KList( + stream(assoc) + .filter(t -> t._1().name().equals(klabel.name())) + .map(t -> KApply(KLabel(t._2().name()))) + .collect(Collectors.toList())); + } + + private boolean isFunction(Production prod) { + return prod.att().contains(Att.FUNCTION()); + } + + // Assume that there is no quantifiers + private Set collectLHSFreeVariables(K requires, K left) { + Set res = new HashSet<>(); + VisitK visitor = + new VisitK() { + @Override + public void apply(KVariable k) { + res.add(k); + } }; - visitor.apply(requires); - visitor.apply(left); - return res; + visitor.apply(requires); + visitor.apply(left); + return res; + } + + private void convertSideCondition(K k, StringBuilder sb) { + if (k.equals(BooleanUtils.TRUE)) { + sb.append("\\top{R}()"); + } else { + sb.append("\\equals{SortBool{},R}(\n "); + convert(k, sb); + sb.append(",\n \\dv{SortBool{}}(\"true\"))"); + } + } + + private void convertSideCondition(K k, String resultSortStr, StringBuilder sb) { + if (k.equals(BooleanUtils.TRUE)) { + sb.append(String.format("\\top{%s}()", resultSortStr)); + } else { + sb.append(String.format("\\equals{SortBool{},%s}(\n ", resultSortStr)); + convert(k, sb); + sb.append(",\n \\dv{SortBool{}}(\"true\"))"); + } + } + + private KLabel computePolyKLabel(KApply k) { + String labelName = k.klabel().name(); + if (mlBinders.contains( + labelName)) { // ML binders are not parametric in the variable so we remove it + List params = mutable(k.klabel().params()); + if (!params.isEmpty()) { + params.remove(0); + } + return KLabel(labelName, immutable(params)); + } else { + return k.klabel(); + } + } + + private void collectAttributes(Map attributes, Att att) { + for (Tuple2, ?> attribute : + iterable(att.withUserGroupsAsGroupAtt().att())) { + Att.Key name = attribute._1._1; + Object val = attribute._2; + String strVal = val.toString(); + if (strVal.equals("")) { + if (!attributes.containsKey(name)) { + attributes.put(name, false); + } + } else { + attributes.put(name, true); + } } - - private void convertSideCondition(K k, StringBuilder sb) { - if (k.equals(BooleanUtils.TRUE)) { - sb.append("\\top{R}()"); - } else { - sb.append("\\equals{SortBool{},R}(\n "); - convert(k, sb); - sb.append(",\n \\dv{SortBool{}}(\"true\"))"); + } + + private static final Production INJ_PROD = + Production( + KLabel(KLabels.INJ, Sort("S1"), Sort("S2")), + Sort("S2"), + Seq(NonTerminal(Sort("S1"))), + Att()); + + private Production production(KApply term) { + return production(term, false); + } + + private Production production(KApply term, boolean instantiatePolySorts) { + KLabel klabel = term.klabel(); + if (klabel.name().equals(KLabels.INJ)) + return instantiatePolySorts ? INJ_PROD.substitute(term.klabel().params()) : INJ_PROD; + Option> prods = module.productionsFor().get(klabel.head()); + if (!(prods.nonEmpty() && prods.get().size() == 1)) + throw KEMException.compilerError( + "Expected to find exactly one production for KLabel: " + + klabel + + " found: " + + prods.getOrElse(Collections::Set).size()); + return instantiatePolySorts + ? prods.get().head().substitute(term.klabel().params()) + : prods.get().head(); + } + + private static String convertBuiltinLabel(String klabel) { + return switch (klabel) { + case "#Bottom" -> "\\bottom"; + case "#Top" -> "\\top"; + case "#Or" -> "\\or"; + case "#And" -> "\\and"; + case "#Not" -> "\\not"; + case "#Floor" -> "\\floor"; + case "#Ceil" -> "\\ceil"; + case "#Equals" -> "\\equals"; + case "#Implies" -> "\\implies"; + case "#Exists" -> "\\exists"; + case "#Forall" -> "\\forall"; + case "#AG" -> "allPathGlobally"; + case "weakExistsFinally" -> ONE_PATH_OP; + case "weakAlwaysFinally" -> ALL_PATH_OP; + default -> throw KEMException.compilerError("Unsuppored kore connective in rule: " + klabel); + }; + } + + public static void convert(KLabel klabel, StringBuilder sb) { + convert(klabel, java.util.Collections.emptySet(), sb); + } + + private void convert(KLabel klabel, Seq params, StringBuilder sb) { + convert(klabel, mutable(params), sb); + } + + private static void convert(KLabel klabel, Collection params, StringBuilder sb) { + if (klabel.name().equals(KLabels.INJ)) { + sb.append(klabel.name()); + } else if (ConstructorChecks.isBuiltinLabel(klabel)) { + sb.append(convertBuiltinLabel(klabel.name())); + } else { + sb.append("Lbl"); + convert(klabel.name(), sb); + } + sb.append("{"); + String conn = ""; + for (Sort param : iterable(klabel.params())) { + sb.append(conn); + convert(param, params, sb); + conn = ", "; + } + sb.append("}"); + } + + private void convert(KLabel klabel, Production prod, StringBuilder sb) { + if (klabel.name().equals(KLabels.INJ)) { + sb.append(klabel.name()); + } else { + sb.append("Lbl"); + convert(klabel.name(), sb); + } + sb.append("{"); + String conn = ""; + for (Sort param : iterable(klabel.params())) { + sb.append(conn); + convert(param, prod, sb); + conn = ", "; + } + sb.append("}"); + } + + private void convert(Sort sort, Production prod, StringBuilder sb) { + convert(sort, prod.params(), sb); + } + + public static void convert(Sort sort, StringBuilder sb) { + convert(sort, java.util.Collections.emptySet(), sb); + } + + private void convert(SortHead sort, StringBuilder sb) { + List params = new ArrayList<>(); + for (int i = 0; i < sort.params(); i++) { + params.add(Sort("S" + i)); + } + convert(Sort(sort.name(), immutable(params)), params, sb); + } + + private void convert(Sort sort, Seq params, StringBuilder sb) { + convert(sort, mutable(params), sb); + } + + private static void convert(Sort sort, Collection params, StringBuilder sb) { + if (sort.name().equals(AddSortInjections.SORTPARAM_NAME)) { + String sortVar = sort.params().headOption().get().name(); + sb.append(sortVar); + return; + } + sb.append("Sort"); + convert(sort.name(), sb); + if (!params.contains(sort)) { + sb.append("{"); + String conn = ""; + for (Sort param : iterable(sort.params())) { + sb.append(conn); + convert(param, params, sb); + conn = ", "; + } + sb.append("}"); + } + } + + private String getSortStr(Sort sort) { + StringBuilder strBuilder = new StringBuilder(); + convert(sort, strBuilder); + return strBuilder.toString(); + } + + private void convert( + Map attributes, + Att att, + StringBuilder sb, + Map freeVarsMap, + HasLocation location) { + sb.append("["); + String conn = ""; + + // Emit user groups as group(_) to prevent conflicts between user groups and internals + att = att.withUserGroupsAsGroupAtt(); + + for (Tuple2, ?> attribute : + // Sort to stabilize error messages + stream(att.att()) + .sorted(Comparator.comparing(Tuple2::toString)) + .collect(Collectors.toList())) { + Att.Key key = attribute._1._1; + String strKey = key.key(); + String clsName = attribute._1._2; + Object val = attribute._2; + String strVal = val.toString(); + sb.append(conn); + if (clsName.equals(K.class.getName())) { + convert(strKey, sb); + sb.append("{}("); + convert((K) val, sb); + sb.append(")"); + } else if (clsName.equals(KList.class.getName())) { + convert(strKey, sb); + sb.append("{}("); + String conn2 = ""; + for (K item : ((KList) val).items()) { + sb.append(conn2); + convert(item, sb); + conn2 = ","; } - } - - private void convertSideCondition(K k, String resultSortStr, StringBuilder sb) { - if (k.equals(BooleanUtils.TRUE)) { - sb.append(String.format("\\top{%s}()", resultSortStr)); + sb.append(")"); + } else if (attributes.get(key) != null && attributes.get(key)) { + convert(strKey, sb); + sb.append("{}("); + if (isListOfVarsAttribute(key)) { + convertStringVarList(location, freeVarsMap, strVal, sb); } else { - sb.append(String.format("\\equals{SortBool{},%s}(\n ", resultSortStr)); - convert(k, sb); - sb.append(",\n \\dv{SortBool{}}(\"true\"))"); - } - } - - private KLabel computePolyKLabel(KApply k) { - String labelName = k.klabel().name(); - if (mlBinders.contains(labelName)) { // ML binders are not parametric in the variable so we remove it - List params = mutable(k.klabel().params()); - if (!params.isEmpty()) { - params.remove(0); + switch (strKey) { + case "unit", "element" -> { + Production prod = production(KApply(KLabel(strVal))); + convert(prod.klabel().get(), prod.params(), sb); + sb.append("()"); } - return KLabel(labelName, immutable(params)); - } else { - return k.klabel(); + default -> sb.append(StringUtil.enquoteKString(strVal)); + } } + sb.append(")"); + } else { + convert(strKey, sb); + sb.append("{}()"); + } + conn = ", "; + } + sb.append("]"); + } + + private void convertStringVarList( + HasLocation location, Map freeVarsMap, String strVal, StringBuilder sb) { + if (strVal.trim().isEmpty()) return; + Collection variables = + Arrays.stream(strVal.split(",")) + .map(String::trim) + .map( + s -> { + if (freeVarsMap.containsKey(s)) return freeVarsMap.get(s); + else + throw KEMException.criticalError("No free variable found for " + s, location); + }) + .collect(Collectors.toList()); + String conn = ""; + for (KVariable var : variables) { + sb.append(conn); + convert((K) var, sb); + conn = ","; + } + } + + private boolean isListOfVarsAttribute(Att.Key name) { + return name.equals(Att.CONCRETE()) || name.equals(Att.SYMBOLIC()); + } + + private static String[] asciiReadableEncodingKoreCalc() { + String[] koreEncoder = + Arrays.copyOf( + StringUtil.asciiReadableEncodingDefault, + StringUtil.asciiReadableEncodingDefault.length); + koreEncoder[0x26] = "And-"; + koreEncoder[0x3c] = "-LT-"; + koreEncoder[0x3e] = "-GT-"; + koreEncoder[0x40] = "-AT-"; + koreEncoder[0x5e] = "Xor-"; + return koreEncoder; + } + + private static final Pattern identChar = Pattern.compile("[A-Za-z0-9\\-]"); + public static String[] asciiReadableEncodingKore = asciiReadableEncodingKoreCalc(); + + private static void convert(String name, StringBuilder sb) { + switch (name) { + case "module", + "endmodule", + "sort", + "hooked-sort", + "symbol", + "hooked-symbol", + "alias", + "axiom" -> { + sb.append(name).append("'Kywd'"); + return; + } + default -> {} } + StringBuilder buffer = new StringBuilder(); + StringUtil.encodeStringToAlphanumeric(buffer, name, asciiReadableEncodingKore, identChar, "'"); + sb.append(buffer); + } - - private void collectAttributes(Map attributes, Att att) { - for (Tuple2, ?> attribute : iterable(att.withUserGroupsAsGroupAtt().att())) { - Att.Key name = attribute._1._1; - Object val = attribute._2; - String strVal = val.toString(); - if (strVal.equals("")) { - if (!attributes.containsKey(name)) { - attributes.put(name, false); - } - } else { - attributes.put(name, true); - } + public Set collectAnonymousVariables(K k) { + Set anonymousVariables = new HashSet<>(); + new VisitK() { + @Override + public void apply(KApply k) { + if (mlBinders.contains(k.klabel().name()) + && k.items().get(0).att().contains(Att.ANONYMOUS())) { + throw KEMException.internalError("Nested quantifier over anonymous variables."); } - } + for (K item : k.items()) { + apply(item); + } + } - private static final Production INJ_PROD = Production(KLabel(KLabels.INJ, Sort("S1"), Sort("S2")), Sort("S2"), Seq(NonTerminal(Sort("S1"))), Att()); - - - private Production production(KApply term) { - return production(term, false); - } - - private Production production(KApply term, boolean instantiatePolySorts) { - KLabel klabel = term.klabel(); - if (klabel.name().equals(KLabels.INJ)) - return instantiatePolySorts ? INJ_PROD.substitute(term.klabel().params()) : INJ_PROD; - Option> prods = module.productionsFor().get(klabel.head()); - if (!(prods.nonEmpty() && prods.get().size() == 1)) - throw KEMException.compilerError("Expected to find exactly one production for KLabel: " + klabel + " found: " + prods.getOrElse(Collections::Set).size()); - return instantiatePolySorts ? prods.get().head().substitute(term.klabel().params()) : prods.get().head(); - } - - private static String convertBuiltinLabel(String klabel) { - return switch (klabel) { - case "#Bottom" -> "\\bottom"; - case "#Top" -> "\\top"; - case "#Or" -> "\\or"; - case "#And" -> "\\and"; - case "#Not" -> "\\not"; - case "#Floor" -> "\\floor"; - case "#Ceil" -> "\\ceil"; - case "#Equals" -> "\\equals"; - case "#Implies" -> "\\implies"; - case "#Exists" -> "\\exists"; - case "#Forall" -> "\\forall"; - case "#AG" -> "allPathGlobally"; - case "weakExistsFinally" -> ONE_PATH_OP; - case "weakAlwaysFinally" -> ALL_PATH_OP; - default -> throw KEMException.compilerError("Unsuppored kore connective in rule: " + klabel); - }; - } + @Override + public void apply(KVariable k) { + if (k.att().contains(Att.ANONYMOUS())) { + anonymousVariables.add(k); + } + } + }.apply(k); + return anonymousVariables; + } + + public void convert(K k, StringBuilder sb) { + new VisitK() { + @Override + public void apply(KApply k) { + KLabel label = computePolyKLabel(k); + String conn = ""; + if (mlBinders.contains(k.klabel().name()) + && k.items().get(0).att().contains(Att.ANONYMOUS())) { + // Handle #Forall _ / #Exists _ + Set anonymousVariables = collectAnonymousVariables(k.items().get(1)); - public static void convert(KLabel klabel, StringBuilder sb) { - convert(klabel, java.util.Collections.emptySet(), sb); - } + // Quantify over all anonymous variables. + for (K variable : anonymousVariables) { + sb.append(conn); + convert(label, sb); + sb.append("("); + apply(variable); + conn = ","; + } - private void convert(KLabel klabel, Seq params, StringBuilder sb) { - convert(klabel, mutable(params), sb); - } + // We assume that mlBinder only has two children. + sb.append(conn); + apply(k.items().get(1)); - private static void convert(KLabel klabel, Collection params, StringBuilder sb) { - if (klabel.name().equals(KLabels.INJ)) { - sb.append(klabel.name()); - } else if (ConstructorChecks.isBuiltinLabel(klabel)) { - sb.append(convertBuiltinLabel(klabel.name())); + for (int i = 0; i < anonymousVariables.size(); i++) { + sb.append(")"); + } } else { - sb.append("Lbl"); - convert(klabel.name(), sb); - } - sb.append("{"); - String conn = ""; - for (Sort param : iterable(klabel.params())) { + convert(label, sb); + sb.append("("); + for (K item : k.items()) { sb.append(conn); - convert(param, params, sb); - conn = ", "; + apply(item); + conn = ","; + } + sb.append(")"); } - sb.append("}"); - } + } - private void convert(KLabel klabel, Production prod, StringBuilder sb) { - if (klabel.name().equals(KLabels.INJ)) { - sb.append(klabel.name()); + @Override + public void apply(KToken k) { + sb.append("\\dv{"); + convert(k.sort(), sb); + sb.append("}("); + if (module + .sortAttributesFor() + .get(k.sort().head()) + .getOrElse(Att::empty) + .getOptional(Att.HOOK()) + .orElse("") + .equals("STRING.String")) { + sb.append(StringUtil.escapeNonASCII(k.s())); + } else if (module + .sortAttributesFor() + .get(k.sort().head()) + .getOrElse(Att::empty) + .getOptional(Att.HOOK()) + .orElse("") + .equals("BYTES.Bytes")) { + sb.append(StringUtil.escapeNonASCII(k.s().substring(1))); // remove the leading `b` } else { - sb.append("Lbl"); - convert(klabel.name(), sb); - } - sb.append("{"); - String conn = ""; - for (Sort param : iterable(klabel.params())) { - sb.append(conn); - convert(param, prod, sb); - conn = ", "; + sb.append(StringUtil.enquoteKString(k.s())); } - sb.append("}"); - } - - private void convert(Sort sort, Production prod, StringBuilder sb) { - convert(sort, prod.params(), sb); - } - - public static void convert(Sort sort, StringBuilder sb) { - convert(sort, java.util.Collections.emptySet(), sb); - } - - private void convert(SortHead sort, StringBuilder sb) { - List params = new ArrayList<>(); - for (int i = 0; i < sort.params(); i++) { - params.add(Sort("S" + i)); + sb.append(")"); } - convert(Sort(sort.name(), immutable(params)), params, sb); - } - private void convert(Sort sort, Seq params, StringBuilder sb) { - convert(sort, mutable(params), sb); - } - - private static void convert(Sort sort, Collection params, StringBuilder sb) { - if (sort.name().equals(AddSortInjections.SORTPARAM_NAME)) { - String sortVar = sort.params().headOption().get().name(); - sb.append(sortVar); - return; - } - sb.append("Sort"); - convert(sort.name(), sb); - if (!params.contains(sort)) { - sb.append("{"); - String conn = ""; - for (Sort param : iterable(sort.params())) { - sb.append(conn); - convert(param, params, sb); - conn = ", "; + @Override + public void apply(KSequence k) { + for (int i = 0; i < k.items().size(); i++) { + K item = k.items().get(i); + boolean isList = item.att().get(Sort.class).equals(Sorts.K()); + if (i == k.items().size() - 1) { + if (isList) { + apply(item); + } else { + sb.append("kseq{}("); + apply(item); + sb.append(",dotk{}())"); } - sb.append("}"); - } - } - - private String getSortStr(Sort sort) { - StringBuilder strBuilder = new StringBuilder(); - convert(sort, strBuilder); - return strBuilder.toString(); - } - - private void convert(Map attributes, Att att, StringBuilder sb, Map freeVarsMap, HasLocation location) { - sb.append("["); - String conn = ""; - - // Emit user groups as group(_) to prevent conflicts between user groups and internals - att = att.withUserGroupsAsGroupAtt(); - - for (Tuple2, ?> attribute : - // Sort to stabilize error messages - stream(att.att()).sorted(Comparator.comparing(Tuple2::toString)).collect(Collectors.toList())) { - Att.Key key = attribute._1._1; - String strKey = key.key(); - String clsName = attribute._1._2; - Object val = attribute._2; - String strVal = val.toString(); - sb.append(conn); - if (clsName.equals(K.class.getName())) { - convert(strKey, sb); - sb.append("{}("); - convert((K) val, sb); - sb.append(")"); - } else if (clsName.equals(KList.class.getName())) { - convert(strKey, sb); - sb.append("{}("); - String conn2 = ""; - for (K item : ((KList)val).items()) { - sb.append(conn2); - convert(item, sb); - conn2 = ","; - } - sb.append(")"); - } else if (attributes.get(key) != null && attributes.get(key)) { - convert(strKey, sb); - sb.append("{}("); - if (isListOfVarsAttribute(key)) { - convertStringVarList(location, freeVarsMap, strVal, sb); - } else { - switch (strKey) { - case "unit", "element" -> { - Production prod = production(KApply(KLabel(strVal))); - convert(prod.klabel().get(), prod.params(), sb); - sb.append("()"); - } - default -> sb.append(StringUtil.enquoteKString(strVal)); - } - } - sb.append(")"); + } else { + if (item.att().get(Sort.class).equals(Sorts.K())) { + sb.append("append{}("); } else { - convert(strKey, sb); - sb.append("{}()"); + sb.append("kseq{}("); } - conn = ", "; - } - sb.append("]"); - } - - private void convertStringVarList(HasLocation location, Map freeVarsMap, String strVal, StringBuilder sb) { - if (strVal.trim().isEmpty()) return; - Collection variables = Arrays.stream(strVal.split(",")).map(String::trim) - .map(s -> { - if (freeVarsMap.containsKey(s)) return freeVarsMap.get(s); - else throw KEMException.criticalError("No free variable found for " + s, location); - }).collect(Collectors.toList()); - String conn = ""; - for (KVariable var : variables) { - sb.append(conn); - convert((K) var, sb); - conn = ","; - } - } - - private boolean isListOfVarsAttribute(Att.Key name) { - return name.equals(Att.CONCRETE()) || name.equals(Att.SYMBOLIC()); - } - - private static String[] asciiReadableEncodingKoreCalc() { - String[] koreEncoder = Arrays.copyOf(StringUtil.asciiReadableEncodingDefault, StringUtil.asciiReadableEncodingDefault.length); - koreEncoder[0x26] = "And-"; - koreEncoder[0x3c] = "-LT-"; - koreEncoder[0x3e] = "-GT-"; - koreEncoder[0x40] = "-AT-"; - koreEncoder[0x5e] = "Xor-"; - return koreEncoder; - } - - private static final Pattern identChar = Pattern.compile("[A-Za-z0-9\\-]"); - public static String[] asciiReadableEncodingKore = asciiReadableEncodingKoreCalc(); - - private static void convert(String name, StringBuilder sb) { - switch (name) { - case "module", "endmodule", "sort", "hooked-sort", "symbol", "hooked-symbol", "alias", "axiom" -> { - sb.append(name).append("'Kywd'"); - return; + apply(item); + sb.append(","); + } } - default -> { + if (k.items().size() == 0) { + sb.append("dotk{}()"); } + for (int i = 0; i < k.items().size() - 1; i++) { + sb.append(")"); } - StringBuilder buffer = new StringBuilder(); - StringUtil.encodeStringToAlphanumeric(buffer, name, asciiReadableEncodingKore, identChar, "'"); - sb.append(buffer); - } - - public Set collectAnonymousVariables(K k){ - Set anonymousVariables = new HashSet<>(); - new VisitK() { - @Override - public void apply(KApply k) { - if (mlBinders.contains(k.klabel().name()) && k.items().get(0).att().contains(Att.ANONYMOUS())){ - throw KEMException.internalError("Nested quantifier over anonymous variables."); - } - for (K item : k.items()) { - apply(item); - } - } - - @Override - public void apply(KVariable k) { - if (k.att().contains(Att.ANONYMOUS())) { - anonymousVariables.add(k); - } - } - - }.apply(k); - return anonymousVariables; - } - - public void convert(K k, StringBuilder sb) { - new VisitK() { - @Override - public void apply(KApply k) { - KLabel label = computePolyKLabel(k); - String conn = ""; - if (mlBinders.contains(k.klabel().name()) && k.items().get(0).att().contains(Att.ANONYMOUS())){ - // Handle #Forall _ / #Exists _ - Set anonymousVariables = collectAnonymousVariables(k.items().get(1)); - - // Quantify over all anonymous variables. - for (K variable : anonymousVariables) { - sb.append(conn); - convert(label, sb); - sb.append("("); - apply(variable); - conn = ","; - } - - // We assume that mlBinder only has two children. - sb.append(conn); - apply(k.items().get(1)); - - for (int i = 0; i < anonymousVariables.size(); i++) { - sb.append(")"); - } - } else { - convert(label, sb); - sb.append("("); - for (K item : k.items()) { - sb.append(conn); - apply(item); - conn = ","; - } - sb.append(")"); - } - } - - @Override - public void apply(KToken k) { - sb.append("\\dv{"); - convert(k.sort(), sb); - sb.append("}("); - if (module.sortAttributesFor().get(k.sort().head()).getOrElse(Att::empty).getOptional(Att.HOOK()).orElse("").equals("STRING.String")) { - sb.append(StringUtil.escapeNonASCII(k.s())); - } else if (module.sortAttributesFor().get(k.sort().head()).getOrElse(Att::empty).getOptional(Att.HOOK()).orElse("").equals("BYTES.Bytes")) { - sb.append(StringUtil.escapeNonASCII(k.s().substring(1))); // remove the leading `b` - } else { - sb.append(StringUtil.enquoteKString(k.s())); - } - sb.append(")"); - } - - @Override - public void apply(KSequence k) { - for (int i = 0; i < k.items().size(); i++) { - K item = k.items().get(i); - boolean isList = item.att().get(Sort.class).equals(Sorts.K()); - if (i == k.items().size() - 1) { - if (isList) { - apply(item); - } else { - sb.append("kseq{}("); - apply(item); - sb.append(",dotk{}())"); - } - } else { - if (item.att().get(Sort.class).equals(Sorts.K())) { - sb.append("append{}("); - } else { - sb.append("kseq{}("); - } - apply(item); - sb.append(","); - } - } - if (k.items().size() == 0) { - sb.append("dotk{}()"); - } - for (int i = 0; i < k.items().size() - 1; i++) { - sb.append(")"); - } - } + } - @Override - public void apply(KVariable k) { - boolean setVar = k.name().startsWith("@"); - if (setVar) { - sb.append('@'); - } - sb.append("Var"); - String name = setVar ? k.name().substring(1) : k.name(); - convert(name, sb); - sb.append(":"); - convert(k.att().getOptional(Sort.class).orElse(Sorts.K()), sb); - } + @Override + public void apply(KVariable k) { + boolean setVar = k.name().startsWith("@"); + if (setVar) { + sb.append('@'); + } + sb.append("Var"); + String name = setVar ? k.name().substring(1) : k.name(); + convert(name, sb); + sb.append(":"); + convert(k.att().getOptional(Sort.class).orElse(Sorts.K()), sb); + } - @Override - public void apply(KRewrite k) { - sb.append("\\rewrites{"); - convert(k.att().get(Sort.class), sb); - sb.append("}("); - apply(k.left()); - sb.append(","); - apply(k.right()); - sb.append(")"); - } + @Override + public void apply(KRewrite k) { + sb.append("\\rewrites{"); + convert(k.att().get(Sort.class), sb); + sb.append("}("); + apply(k.left()); + sb.append(","); + apply(k.right()); + sb.append(")"); + } - @Override - public void apply(KAs k) { - Sort sort = k.att().get(Sort.class); - sb.append("\\and{"); - convert(sort, sb); - sb.append("}("); - apply(k.pattern()); - sb.append(","); - apply(k.alias()); - sb.append(")"); - } + @Override + public void apply(KAs k) { + Sort sort = k.att().get(Sort.class); + sb.append("\\and{"); + convert(sort, sb); + sb.append("}("); + apply(k.pattern()); + sb.append(","); + apply(k.alias()); + sb.append(")"); + } - @Override - public void apply(InjectedKLabel k) { - throw KEMException.internalError("Cannot yet translate #klabel to kore", k); - } - }.apply(k); - } + @Override + public void apply(InjectedKLabel k) { + throw KEMException.internalError("Cannot yet translate #klabel to kore", k); + } + }.apply(k); + } } diff --git a/kernel/src/main/java/org/kframework/compile/AbstractBackend.java b/kernel/src/main/java/org/kframework/compile/AbstractBackend.java index 311de41c2b9..18e5f1dab88 100644 --- a/kernel/src/main/java/org/kframework/compile/AbstractBackend.java +++ b/kernel/src/main/java/org/kframework/compile/AbstractBackend.java @@ -1,24 +1,22 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.definition.Definition; -import scala.Function1; - -import javax.annotation.Nullable; import java.util.List; import java.util.function.Function; +import javax.annotation.Nullable; +import org.kframework.definition.Definition; +import scala.Function1; /** - * @author Denis Bogdanas - * Created on 09-Jan-20. + * @author Denis Bogdanas Created on 09-Jan-20. */ public abstract class AbstractBackend implements Backend { - @Override - public Function proofDefinitionNonCachedSteps( - @Nullable List extraConcreteRuleLabels) { - Function1 markExtraConcrete = - def -> MarkExtraConcreteRules.mark(def, extraConcreteRuleLabels); - return markExtraConcrete::apply; - } + @Override + public Function proofDefinitionNonCachedSteps( + @Nullable List extraConcreteRuleLabels) { + Function1 markExtraConcrete = + def -> MarkExtraConcreteRules.mark(def, extraConcreteRuleLabels); + return markExtraConcrete::apply; + } } diff --git a/kernel/src/main/java/org/kframework/compile/AddCoolLikeAtt.java b/kernel/src/main/java/org/kframework/compile/AddCoolLikeAtt.java index 983aff86842..cd2417ed296 100644 --- a/kernel/src/main/java/org/kframework/compile/AddCoolLikeAtt.java +++ b/kernel/src/main/java/org/kframework/compile/AddCoolLikeAtt.java @@ -7,74 +7,67 @@ import org.kframework.definition.Module; import org.kframework.definition.Rule; import org.kframework.definition.Sentence; +import org.kframework.kore.FoldK; import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KSequence; import org.kframework.kore.KVariable; -import org.kframework.kore.FoldK; public record AddCoolLikeAtt(Module mod) { - private Rule add(Rule rule) { - return new Rule( - rule.body(), - rule.requires(), - rule.ensures(), - transform(rule.body(), rule.att())); - } - - private Context add(Context context) { - return new Context( - context.body(), - context.requires(), - transform(context.body(), context.att())); - } + private Rule add(Rule rule) { + return new Rule( + rule.body(), rule.requires(), rule.ensures(), transform(rule.body(), rule.att())); + } - private ContextAlias add(ContextAlias context) { - return new ContextAlias( - context.body(), - context.requires(), - transform(context.body(), context.att())); - } + private Context add(Context context) { + return new Context( + context.body(), context.requires(), transform(context.body(), context.att())); + } - private Att transform(K body, Att att) { - if (new FoldK() { - @Override - public Boolean unit() { - return false; - } + private ContextAlias add(ContextAlias context) { + return new ContextAlias( + context.body(), context.requires(), transform(context.body(), context.att())); + } - @Override - public Boolean apply(KApply k) { - if (mod.attributesFor().get(k.klabel()).getOrElse(Att::empty).contains(Att.MAINCELL())) { - if (k.items().get(0) instanceof KSequence seq) { - if (seq.items().size() > 1 && seq.items().get(0) instanceof KVariable) { - return true; - } - } - } - return super.apply(k); - } + private Att transform(K body, Att att) { + if (new FoldK() { + @Override + public Boolean unit() { + return false; + } - @Override - public Boolean merge(Boolean a, Boolean b) { - return a || b; + @Override + public Boolean apply(KApply k) { + if (mod.attributesFor().get(k.klabel()).getOrElse(Att::empty).contains(Att.MAINCELL())) { + if (k.items().get(0) instanceof KSequence seq) { + if (seq.items().size() > 1 && seq.items().get(0) instanceof KVariable) { + return true; } - }.apply(RewriteToTop.toLeft(body))) { - return att.add(Att.COOL_LIKE()); + } } - return att; + return super.apply(k); + } + + @Override + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } + }.apply(RewriteToTop.toLeft(body))) { + return att.add(Att.COOL_LIKE()); } + return att; + } - public synchronized Sentence add(Sentence s) { - if (s instanceof Rule) { - return add((Rule) s); - } else if (s instanceof Context) { - return add((Context) s); - } else if (s instanceof ContextAlias) { - return add((ContextAlias) s); - } else { - return s; - } + public synchronized Sentence add(Sentence s) { + if (s instanceof Rule) { + return add((Rule) s); + } else if (s instanceof Context) { + return add((Context) s); + } else if (s instanceof ContextAlias) { + return add((ContextAlias) s); + } else { + return s; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/AddImplicitComputationCell.java b/kernel/src/main/java/org/kframework/compile/AddImplicitComputationCell.java index 78a23aea541..a7bc3873216 100644 --- a/kernel/src/main/java/org/kframework/compile/AddImplicitComputationCell.java +++ b/kernel/src/main/java/org/kframework/compile/AddImplicitComputationCell.java @@ -1,6 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.List; +import java.util.stream.Stream; import org.kframework.attributes.Att; import org.kframework.builtin.KLabels; import org.kframework.definition.*; @@ -10,102 +12,104 @@ import org.kframework.kore.KLabel; import org.kframework.kore.KRewrite; -import java.util.List; -import java.util.stream.Stream; - /** - * If a SemanticSentence (Rule or Context) has a body that is not wrapped in any cell, - * wrap it in a {@code } cell + * If a SemanticSentence (Rule or Context) has a body that is not wrapped in any cell, wrap it in a + * {@code } cell */ public record AddImplicitComputationCell(ConfigurationInfo cfg, LabelInfo labelInfo) { - public static Definition transformDefinition(Definition input) { - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(input.mainModule()); - LabelInfo labelInfo = new LabelInfoFromModule(input.mainModule()); - return DefinitionTransformer.fromSentenceTransformer( - new AddImplicitComputationCell(configInfo, labelInfo)::apply, - "concretizing configuration").apply(input); + public static Definition transformDefinition(Definition input) { + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(input.mainModule()); + LabelInfo labelInfo = new LabelInfoFromModule(input.mainModule()); + return DefinitionTransformer.fromSentenceTransformer( + new AddImplicitComputationCell(configInfo, labelInfo)::apply, + "concretizing configuration") + .apply(input); + } + + public static Module transformModule(Module mod) { + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); + LabelInfo labelInfo = new LabelInfoFromModule(mod); + return ModuleTransformer.fromSentenceTransformer( + new AddImplicitComputationCell(configInfo, labelInfo)::apply, + "concretizing configuration") + .apply(mod); + } + + public Sentence apply(Module m, Sentence s) { + if (skipSentence(s)) { + return s; } - public static Module transformModule(Module mod) { - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); - LabelInfo labelInfo = new LabelInfoFromModule(mod); - return ModuleTransformer.fromSentenceTransformer( - new AddImplicitComputationCell(configInfo, labelInfo)::apply, - "concretizing configuration").apply(mod); + if (s instanceof RuleOrClaim rule) { + return rule.newInstance( + apply(rule.body(), m, rule instanceof Claim), + rule.requires(), + rule.ensures(), + rule.att()); + } else if (s instanceof Context context) { + return new Context(apply(context.body(), m, false), context.requires(), context.att()); + } else { + return s; } - - public Sentence apply(Module m, Sentence s) { - if (skipSentence(s)) { - return s; - } - - if (s instanceof RuleOrClaim rule) { - return rule.newInstance(apply(rule.body(), m, rule instanceof Claim), rule.requires(), rule.ensures(), rule.att()); - } else if (s instanceof Context context) { - return new Context(apply(context.body(), m, false), context.requires(), context.att()); - } else { - return s; - } + } + + private boolean skipSentence(Sentence s) { + return ExpandMacros.isMacro(s) + || s.att().contains(Att.ANYWHERE()) + || s.att().contains(Att.SIMPLIFICATION()) + || s.att().contains(Att.KORE()); + } + + // If there are multiple cells mentioned in the split configuration, we don't + // apply the implicit cell, unless the configuration is a claim and the second + // cell mentioned is the automatically-added cell. + private boolean shouldConsider(List items, boolean isClaim) { + if (items.size() == 1) { + return true; + } else if (items.size() == 2 && isClaim) { + K second = items.get(1); + if (second instanceof KApply app) { + return app.klabel() == KLabels.GENERATED_COUNTER_CELL; + } } - private boolean skipSentence(Sentence s) { - return ExpandMacros.isMacro(s) - || s.att().contains(Att.ANYWHERE()) - || s.att().contains(Att.SIMPLIFICATION()) - || s.att().contains(Att.KORE()); - } + return false; + } - // If there are multiple cells mentioned in the split configuration, we don't - // apply the implicit cell, unless the configuration is a claim and the second - // cell mentioned is the automatically-added cell. - private boolean shouldConsider(List items, boolean isClaim) { - if (items.size() == 1) { - return true; - } else if (items.size() == 2 && isClaim) { - K second = items.get(1); - if(second instanceof KApply app) { - return app.klabel() == KLabels.GENERATED_COUNTER_CELL; - } - } - - return false; + private boolean canAddImplicitKCell(K item) { + if (isCell(item)) { + return false; } - private boolean canAddImplicitKCell(K item) { - if(isCell(item)) { - return false; - } - - if (item instanceof final KRewrite rew) { - return Stream.concat( - IncompleteCellUtils.flattenCells(rew.left()).stream(), - IncompleteCellUtils.flattenCells(rew.right()).stream()) - .noneMatch(this::isCell); - } - - return true; + if (item instanceof final KRewrite rew) { + return Stream.concat( + IncompleteCellUtils.flattenCells(rew.left()).stream(), + IncompleteCellUtils.flattenCells(rew.right()).stream()) + .noneMatch(this::isCell); } - private K apply(K term, Module m, boolean isClaim) { - if (m.isFunction(term)) return term; + return true; + } - List items = IncompleteCellUtils.flattenCells(term); - if (!shouldConsider(items, isClaim)) { - return term; - } + private K apply(K term, Module m, boolean isClaim) { + if (m.isFunction(term)) return term; - K item = items.get(0); - if (!canAddImplicitKCell(item)) { - return term; - } - - KLabel computation = cfg.getCellLabel(cfg.getComputationCell()); - return IncompleteCellUtils.make(computation, false, item, true); + List items = IncompleteCellUtils.flattenCells(term); + if (!shouldConsider(items, isClaim)) { + return term; } - private boolean isCell(K k) { - return k instanceof KApply - && cfg.isCell(labelInfo.getCodomain(((KApply) k).klabel())); + K item = items.get(0); + if (!canAddImplicitKCell(item)) { + return term; } + + KLabel computation = cfg.getCellLabel(cfg.getComputationCell()); + return IncompleteCellUtils.make(computation, false, item, true); + } + + private boolean isCell(K k) { + return k instanceof KApply && cfg.isCell(labelInfo.getCodomain(((KApply) k).klabel())); + } } diff --git a/kernel/src/main/java/org/kframework/compile/AddImplicitCounterCell.java b/kernel/src/main/java/org/kframework/compile/AddImplicitCounterCell.java index 8fc7fb045b8..e644e9e305e 100644 --- a/kernel/src/main/java/org/kframework/compile/AddImplicitCounterCell.java +++ b/kernel/src/main/java/org/kframework/compile/AddImplicitCounterCell.java @@ -2,51 +2,52 @@ package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.*; import org.kframework.builtin.KLabels; import org.kframework.definition.Claim; -import org.kframework.definition.Sentence; import org.kframework.definition.Module; +import org.kframework.definition.Sentence; import org.kframework.kore.*; -import java.util.*; - -import static org.kframework.kore.KORE.*; - /** - * If a claim doesn't mention the generated counter cell (for resolving fresh variables), - * then add an implicit ` _ => ?_ ` to the claim. + * If a claim doesn't mention the generated counter cell (for resolving fresh variables), then add + * an implicit ` _ => ?_ ` to the claim. */ public class AddImplicitCounterCell { - public AddImplicitCounterCell() {} + public AddImplicitCounterCell() {} - public Sentence apply(Module m, Sentence s) { - if(s instanceof Claim claim) { - return claim.newInstance(apply(claim.body(), m), claim.requires(), claim.ensures(), claim.att()); - } - return s; + public Sentence apply(Module m, Sentence s) { + if (s instanceof Claim claim) { + return claim.newInstance( + apply(claim.body(), m), claim.requires(), claim.ensures(), claim.att()); } - - // We shouldn't add the implicit cell to the claim if the user has already written - // it explicitly. - private boolean alreadyHasGeneratedCounter(List items) { - return items.stream() - .filter(cell -> cell instanceof KApply) - .anyMatch(cell -> ((KApply) cell).klabel().equals(KLabels.GENERATED_COUNTER_CELL)); - } - - private K apply(K term, Module m) { - List items = IncompleteCellUtils.flattenCells(term); - if(alreadyHasGeneratedCounter(items)) { - return term; - } - - KRewrite rew = KRewrite( - KApply(KLabel("#SemanticCastToInt"), ResolveAnonVar.ANON_VAR), - KApply(KLabel("#SemanticCastToInt"), ResolveAnonVar.FRESH_ANON_VAR)); - items.add(IncompleteCellUtils.make( - KLabels.GENERATED_COUNTER_CELL, false, Collections.singletonList(rew), false)); - return IncompleteCellUtils.makeBody(items); + return s; + } + + // We shouldn't add the implicit cell to the claim if the user has already written + // it explicitly. + private boolean alreadyHasGeneratedCounter(List items) { + return items.stream() + .filter(cell -> cell instanceof KApply) + .anyMatch(cell -> ((KApply) cell).klabel().equals(KLabels.GENERATED_COUNTER_CELL)); + } + + private K apply(K term, Module m) { + List items = IncompleteCellUtils.flattenCells(term); + if (alreadyHasGeneratedCounter(items)) { + return term; } + KRewrite rew = + KRewrite( + KApply(KLabel("#SemanticCastToInt"), ResolveAnonVar.ANON_VAR), + KApply(KLabel("#SemanticCastToInt"), ResolveAnonVar.FRESH_ANON_VAR)); + items.add( + IncompleteCellUtils.make( + KLabels.GENERATED_COUNTER_CELL, false, Collections.singletonList(rew), false)); + return IncompleteCellUtils.makeBody(items); + } } diff --git a/kernel/src/main/java/org/kframework/compile/AddParentCells.java b/kernel/src/main/java/org/kframework/compile/AddParentCells.java index 3fd42ce8d18..7430f3bfd3a 100644 --- a/kernel/src/main/java/org/kframework/compile/AddParentCells.java +++ b/kernel/src/main/java/org/kframework/compile/AddParentCells.java @@ -2,19 +2,30 @@ package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.builtin.KLabels; -import org.kframework.definition.Claim; import org.kframework.definition.Context; -import org.kframework.definition.Rule; import org.kframework.definition.RuleOrClaim; import org.kframework.definition.Sentence; import org.kframework.kore.K; -import org.kframework.kore.KAs; import org.kframework.kore.KApply; +import org.kframework.kore.KAs; import org.kframework.kore.KLabel; import org.kframework.kore.KRewrite; import org.kframework.kore.KSequence; @@ -22,299 +33,311 @@ import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeMap; -import java.util.function.BiFunction; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.kore.KORE.*; - /** - * Add omitted parent cells to a term written using configuration abstraction. - * It only completes the contents of existing cells, so an earlier pass should add - * a top cell around rule bodies if completion to the top is desired. - * Newly inserted cells have dots if and only if the parent cell they were added under did - * (dots are elimiinated in the {@link CloseCells} pass). + * Add omitted parent cells to a term written using configuration abstraction. It only completes the + * contents of existing cells, so an earlier pass should add a top cell around rule bodies if + * completion to the top is desired. Newly inserted cells have dots if and only if the parent cell + * they were added under did (dots are elimiinated in the {@link CloseCells} pass). */ public class AddParentCells { - private final ConcretizationInfo cfg; + private final ConcretizationInfo cfg; - public AddParentCells(ConfigurationInfo configInfo, LabelInfo labelInfo) { - cfg = new ConcretizationInfo(configInfo, labelInfo); - } + public AddParentCells(ConfigurationInfo configInfo, LabelInfo labelInfo) { + cfg = new ConcretizationInfo(configInfo, labelInfo); + } - Stream streamSideCells(K side) { - List cells = IncompleteCellUtils.flattenCells(side); - // TODO error handling - return cells.stream(); - } + Stream streamSideCells(K side) { + List cells = IncompleteCellUtils.flattenCells(side); + // TODO error handling + return cells.stream(); + } - protected List makeParents(KLabel parent, boolean ellipses, - List allChildren) { - // List rewrites -// rewrites.stream().map(r -> r.left()).flatMap(t -> if(t.)); + protected List makeParents(KLabel parent, boolean ellipses, List allChildren) { + // List rewrites + // rewrites.stream().map(r -> r.left()).flatMap(t -> if(t.)); - List children = allChildren.stream().filter(t -> !(t instanceof KRewrite)).collect(Collectors.toList()); - List rewrites = allChildren.stream().filter(t -> t instanceof KRewrite).map(t -> (KRewrite) t).collect(Collectors.toList()); + List children = + allChildren.stream().filter(t -> !(t instanceof KRewrite)).collect(Collectors.toList()); + List rewrites = + allChildren.stream() + .filter(t -> t instanceof KRewrite) + .map(t -> (KRewrite) t) + .collect(Collectors.toList()); - // see if all children can fit together - Set usedCells = Sets.newHashSet(); - BiFunction, Set, Boolean> useCells = (cells, used) -> { - for (K k : cells) { - Sort sort = cfg.getCellSort(k); - if (cfg.getMultiplicity(sort) != ConfigurationInfo.Multiplicity.STAR) { - if (used.contains(sort)) { - return false; - } else { - used.add(sort); - } - } + // see if all children can fit together + Set usedCells = Sets.newHashSet(); + BiFunction, Set, Boolean> useCells = + (cells, used) -> { + for (K k : cells) { + Sort sort = cfg.getCellSort(k); + if (cfg.getMultiplicity(sort) != ConfigurationInfo.Multiplicity.STAR) { + if (used.contains(sort)) { + return false; + } else { + used.add(sort); + } } - return true; + } + return true; }; - boolean allFitTogether = useCells.apply(children, usedCells); - if (allFitTogether) { - Function, List> flattenRewrite = f -> rewrites.stream().map(f).flatMap - (this::streamSideCells).collect(Collectors.toList()); + boolean allFitTogether = useCells.apply(children, usedCells); + if (allFitTogether) { + Function, List> flattenRewrite = + f -> rewrites.stream().map(f).flatMap(this::streamSideCells).collect(Collectors.toList()); - List leftChildren = flattenRewrite.apply(KRewrite::left); - Set usedLeft = Sets.newHashSet(usedCells); - boolean leftFit = useCells.apply(leftChildren, usedLeft); - List rightChildren = flattenRewrite.apply(KRewrite::right); - Set usedRight = Sets.newHashSet(usedCells); - boolean rightFit = useCells.apply(rightChildren, usedRight); - allFitTogether = leftFit && rightFit; - } - if (allFitTogether) { - return Lists.newArrayList(IncompleteCellUtils.make(parent, ellipses, allChildren, ellipses)); - } - - // Otherwise, see if they are forced to have separate parents... + List leftChildren = flattenRewrite.apply(KRewrite::left); + Set usedLeft = Sets.newHashSet(usedCells); + boolean leftFit = useCells.apply(leftChildren, usedLeft); + List rightChildren = flattenRewrite.apply(KRewrite::right); + Set usedRight = Sets.newHashSet(usedCells); + boolean rightFit = useCells.apply(rightChildren, usedRight); + allFitTogether = leftFit && rightFit; + } + if (allFitTogether) { + return Lists.newArrayList(IncompleteCellUtils.make(parent, ellipses, allChildren, ellipses)); + } - boolean forcedSeparate = true; - if (!children.isEmpty()) { - Sort label = cfg.getCellSort(children.get(0)); - if (cfg.getMultiplicity(label) == ConfigurationInfo.Multiplicity.STAR) { - forcedSeparate = false; - } else { - for (K child : children) { - Sort sort = cfg.getCellSort(child); - if (!sort.equals(label)) { - forcedSeparate = false; - break; - } - } - } - if (forcedSeparate) { - for (KRewrite rew : rewrites) { - if (!(streamSideCells(rew.left()).anyMatch(l -> cfg.getCellSort(l).equals(label)) - || streamSideCells(rew.left()).anyMatch(l -> cfg.getCellSort(l).equals(label)))) { - forcedSeparate = false; - break; - } - } - } - } - if (forcedSeparate) { - for (KRewrite rew1 : rewrites) { - for (KRewrite rew2 : rewrites) { - Set left1NonRepeatable = streamSideCells(rew1.left()).map(cfg::getCellSort) - .filter(l -> cfg.getMultiplicity(l) != ConfigurationInfo.Multiplicity.STAR) - .collect(Collectors.toSet()); - boolean lhsConflict = streamSideCells(rew2.left()).map(cfg::getCellSort) - .filter(left1NonRepeatable::contains).count() >= 1; + // Otherwise, see if they are forced to have separate parents... - Set right1NonRepeatable = streamSideCells(rew1.right()).map(cfg::getCellSort) - .filter(l -> cfg.getMultiplicity(l) != ConfigurationInfo.Multiplicity.STAR) - .collect(Collectors.toSet()); - boolean rhsConflict = streamSideCells(rew2.right()).map(cfg::getCellSort) - .filter(right1NonRepeatable::contains).count() >= 1; - if (!(lhsConflict || rhsConflict)) { - forcedSeparate = false; - break; - } - } - } + boolean forcedSeparate = true; + if (!children.isEmpty()) { + Sort label = cfg.getCellSort(children.get(0)); + if (cfg.getMultiplicity(label) == ConfigurationInfo.Multiplicity.STAR) { + forcedSeparate = false; + } else { + for (K child : children) { + Sort sort = cfg.getCellSort(child); + if (!sort.equals(label)) { + forcedSeparate = false; + break; + } } - if (forcedSeparate) { - return allChildren.stream() - .map(k -> IncompleteCellUtils.make(parent, ellipses, k, ellipses)) - .collect(Collectors.toList()); + } + if (forcedSeparate) { + for (KRewrite rew : rewrites) { + if (!(streamSideCells(rew.left()).anyMatch(l -> cfg.getCellSort(l).equals(label)) + || streamSideCells(rew.left()).anyMatch(l -> cfg.getCellSort(l).equals(label)))) { + forcedSeparate = false; + break; + } } + } + } + if (forcedSeparate) { + for (KRewrite rew1 : rewrites) { + for (KRewrite rew2 : rewrites) { + Set left1NonRepeatable = + streamSideCells(rew1.left()) + .map(cfg::getCellSort) + .filter(l -> cfg.getMultiplicity(l) != ConfigurationInfo.Multiplicity.STAR) + .collect(Collectors.toSet()); + boolean lhsConflict = + streamSideCells(rew2.left()) + .map(cfg::getCellSort) + .filter(left1NonRepeatable::contains) + .count() + >= 1; - // They were also not forced to be separate - throw KEMException.criticalError("Ambiguous completion: " + parent + "\n" + allChildren); + Set right1NonRepeatable = + streamSideCells(rew1.right()) + .map(cfg::getCellSort) + .filter(l -> cfg.getMultiplicity(l) != ConfigurationInfo.Multiplicity.STAR) + .collect(Collectors.toSet()); + boolean rhsConflict = + streamSideCells(rew2.right()) + .map(cfg::getCellSort) + .filter(right1NonRepeatable::contains) + .count() + >= 1; + if (!(lhsConflict || rhsConflict)) { + forcedSeparate = false; + break; + } + } + } } + if (forcedSeparate) { + return allChildren.stream() + .map(k -> IncompleteCellUtils.make(parent, ellipses, k, ellipses)) + .collect(Collectors.toList()); + } + + // They were also not forced to be separate + throw KEMException.criticalError("Ambiguous completion: " + parent + "\n" + allChildren); + } - boolean isCompletionItem(K k) { - return (k instanceof KApply || k instanceof KRewrite || k instanceof KVariable) - && getLevel(k).isPresent(); + boolean isCompletionItem(K k) { + return (k instanceof KApply || k instanceof KRewrite || k instanceof KVariable) + && getLevel(k).isPresent(); + } + + Optional getLevel(KApply k) { + int level = cfg.getLevel(k.klabel()); + if (level >= 0) { + return Optional.of(level); + } else { + return Optional.empty(); } + } - Optional getLevel(KApply k) { - int level = cfg.getLevel(k.klabel()); + Optional getLevel(K k) { + if (k instanceof KApply) { + return getLevel((KApply) k); + } else if (k instanceof KVariable) { + if (k.att().contains(Sort.class)) { + Sort sort = k.att().get(Sort.class); + int level = cfg.cfg().getLevel(sort); if (level >= 0) { - return Optional.of(level); - } else { - return Optional.empty(); + return Optional.of(level); } - } - - Optional getLevel(K k) { - if (k instanceof KApply) { - return getLevel((KApply) k); - } else if (k instanceof KVariable) { - if (k.att().contains(Sort.class)) { - Sort sort = k.att().get(Sort.class); - int level = cfg.cfg().getLevel(sort); - if (level >= 0) { - return Optional.of(level); - } - } - return Optional.empty(); - } else if (k instanceof KRewrite rew) { - List cells = IncompleteCellUtils.flattenCells(rew.left()); - cells.addAll(IncompleteCellUtils.flattenCells(rew.right())); - Optional level = Optional.empty(); - for (K item : cells) { - Optional level2 = getLevel(item); - if (item instanceof KVariable && !level2.isPresent()) { - continue; - } - if (!level.isPresent()) { - level = level2; - } else if (!level.equals(level2)) { - throw KEMException.criticalError("Can't mix cells at different levels under a rewrite"); - } - // else level is already correct - } - return level; - } else { - return Optional.empty(); + } + return Optional.empty(); + } else if (k instanceof KRewrite rew) { + List cells = IncompleteCellUtils.flattenCells(rew.left()); + cells.addAll(IncompleteCellUtils.flattenCells(rew.right())); + Optional level = Optional.empty(); + for (K item : cells) { + Optional level2 = getLevel(item); + if (item instanceof KVariable && !level2.isPresent()) { + continue; + } + if (!level.isPresent()) { + level = level2; + } else if (!level.equals(level2)) { + throw KEMException.criticalError("Can't mix cells at different levels under a rewrite"); } + // else level is already correct + } + return level; + } else { + return Optional.empty(); } + } - Optional getParent(K k) { - if (k instanceof final KApply app) { - if (KLabels.CELLS.equals(app.klabel())) { - List items = app.klist().items(); - if (items.isEmpty()) { - return Optional.empty(); - } - Optional parent = getParent(items.get(0)); - for (K item : items) { - if (!parent.equals(getParent(item))) { - throw KEMException.criticalError("Can't mix items with different parent cells under a rewrite," + - " found "+items.get(0)+" and "+item, k); - } - } - return parent; - } else if (cfg.isCell(app.klabel())) { - return Optional.of(cfg.getParent(app.klabel())); - } else { - return Optional.empty(); - } - } else if (k instanceof KVariable) { - Sort sort = k.att().get(Sort.class); - return Optional.of(cfg.getParent(sort)); - } else { - Optional leftParent = getParent(((KRewrite) k).left()); - Optional rightParent = getParent(((KRewrite) k).right()); - if (!leftParent.isPresent()) { - return rightParent; - } - if (!rightParent.isPresent()) { - return leftParent; - } - if (leftParent.equals(rightParent)) { - return leftParent; - } else { - throw KEMException.criticalError("All cells on the left and right of a rewrite must have the same parent: " + k); - } + Optional getParent(K k) { + if (k instanceof final KApply app) { + if (KLabels.CELLS.equals(app.klabel())) { + List items = app.klist().items(); + if (items.isEmpty()) { + return Optional.empty(); } + Optional parent = getParent(items.get(0)); + for (K item : items) { + if (!parent.equals(getParent(item))) { + throw KEMException.criticalError( + "Can't mix items with different parent cells under a rewrite," + + " found " + + items.get(0) + + " and " + + item, + k); + } + } + return parent; + } else if (cfg.isCell(app.klabel())) { + return Optional.of(cfg.getParent(app.klabel())); + } else { + return Optional.empty(); + } + } else if (k instanceof KVariable) { + Sort sort = k.att().get(Sort.class); + return Optional.of(cfg.getParent(sort)); + } else { + Optional leftParent = getParent(((KRewrite) k).left()); + Optional rightParent = getParent(((KRewrite) k).right()); + if (!leftParent.isPresent()) { + return rightParent; + } + if (!rightParent.isPresent()) { + return leftParent; + } + if (leftParent.equals(rightParent)) { + return leftParent; + } else { + throw KEMException.criticalError( + "All cells on the left and right of a rewrite must have the same parent: " + k); + } } + } - K concretizeCell(K k) { - if (!(k instanceof KApply app)) { - return k; + K concretizeCell(K k) { + if (!(k instanceof KApply app)) { + return k; + } else { + KLabel target = app.klabel(); + if (cfg.isLeafCell(target)) { + return k; + } + List children = Lists.newArrayList(); + List otherChildren = Lists.newArrayList(); + int ix = 0; + boolean ellipses = + IncompleteCellUtils.isOpenLeft(app) || IncompleteCellUtils.isOpenRight(app); + for (K item : IncompleteCellUtils.getChildren(app)) { + if (isCompletionItem(item)) { + children.add(item); } else { - KLabel target = app.klabel(); - if (cfg.isLeafCell(target)) { - return k; - } - List children = Lists.newArrayList(); - List otherChildren = Lists.newArrayList(); - int ix = 0; - boolean ellipses = IncompleteCellUtils.isOpenLeft(app) - || IncompleteCellUtils.isOpenRight(app); - for (K item : IncompleteCellUtils.getChildren(app)) { - if (isCompletionItem(item)) { - children.add(item); - } else { - otherChildren.add(item); - } - ++ix; - } - if (children.isEmpty()) { - return k; - } + otherChildren.add(item); + } + ++ix; + } + if (children.isEmpty()) { + return k; + } - int targetLevel = cfg.getLevel(target) + 1; - TreeMap> levelMap = new TreeMap<>(); - Multimap levels = Multimaps.newMultimap(levelMap, ArrayList::new); - for (K child : children) { - levels.put(getLevel(child).get(), child); - } - while (levelMap.lastKey() > targetLevel) { - Collection level = levels.removeAll(levelMap.lastKey()); - for (Map.Entry> e : level.stream().collect(Collectors.groupingBy(t -> getParent(t).get())).entrySet()) { - KLabel parent = e.getKey(); - List newCells = makeParents(parent, ellipses, e.getValue()); - levels.putAll(cfg.getLevel(parent), newCells); - } - } - otherChildren.addAll(levels.removeAll(levelMap.lastKey())); - return IncompleteCellUtils.make(target, ellipses, otherChildren, ellipses); + int targetLevel = cfg.getLevel(target) + 1; + TreeMap> levelMap = new TreeMap<>(); + Multimap levels = Multimaps.newMultimap(levelMap, ArrayList::new); + for (K child : children) { + levels.put(getLevel(child).get(), child); + } + while (levelMap.lastKey() > targetLevel) { + Collection level = levels.removeAll(levelMap.lastKey()); + for (Map.Entry> e : + level.stream().collect(Collectors.groupingBy(t -> getParent(t).get())).entrySet()) { + KLabel parent = e.getKey(); + List newCells = makeParents(parent, ellipses, e.getValue()); + levels.putAll(cfg.getLevel(parent), newCells); } + } + otherChildren.addAll(levels.removeAll(levelMap.lastKey())); + return IncompleteCellUtils.make(target, ellipses, otherChildren, ellipses); } + } - K concretize(K term) { - if (term instanceof KApply app) { - KApply newTerm = KApply(app.klabel(), KList(app.klist().stream() - .map(this::concretize).collect(Collectors.toList())), app.att()); - if (cfg.isParentCell(newTerm.klabel())) { - return concretizeCell(newTerm); - } else { - return newTerm; - } - } else if (term instanceof KRewrite rew) { - return KRewrite(concretize(rew.left()), concretize(rew.right())); - } else if (term instanceof KSequence) { - return KSequence(((KSequence) term).stream() - .map(this::concretize).collect(Collectors.toList())); - } else if (term instanceof KAs) { - return KAs(concretize(((KAs)term).pattern()), ((KAs)term).alias(), term.att()); - } else { - return term; - } + K concretize(K term) { + if (term instanceof KApply app) { + KApply newTerm = + KApply( + app.klabel(), + KList(app.klist().stream().map(this::concretize).collect(Collectors.toList())), + app.att()); + if (cfg.isParentCell(newTerm.klabel())) { + return concretizeCell(newTerm); + } else { + return newTerm; + } + } else if (term instanceof KRewrite rew) { + return KRewrite(concretize(rew.left()), concretize(rew.right())); + } else if (term instanceof KSequence) { + return KSequence( + ((KSequence) term).stream().map(this::concretize).collect(Collectors.toList())); + } else if (term instanceof KAs) { + return KAs(concretize(((KAs) term).pattern()), ((KAs) term).alias(), term.att()); + } else { + return term; } + } - public Sentence concretize(Sentence m) { - if (m instanceof RuleOrClaim r) { - return r.newInstance(concretize(r.body()), r.requires(), r.ensures(), r.att()); - } else if (m instanceof Context c) { - return new Context(concretize(c.body()), c.requires(), c.att()); - } else { - return m; - } + public Sentence concretize(Sentence m) { + if (m instanceof RuleOrClaim r) { + return r.newInstance(concretize(r.body()), r.requires(), r.ensures(), r.att()); + } else if (m instanceof Context c) { + return new Context(concretize(c.body()), c.requires(), c.att()); + } else { + return m; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/AddSortInjections.java b/kernel/src/main/java/org/kframework/compile/AddSortInjections.java index 588a9fc9ea7..013cf1f4bb6 100644 --- a/kernel/src/main/java/org/kframework/compile/AddSortInjections.java +++ b/kernel/src/main/java/org/kframework/compile/AddSortInjections.java @@ -1,6 +1,21 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.BiFunction; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.attributes.HasLocation; @@ -27,451 +42,507 @@ import scala.Option; import scala.Tuple2; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.BiFunction; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - public class AddSortInjections { - private final Module mod; - private final Map collectionFor; - private final ConfigurationInfoFromModule configurationInfo; - - private int freshSortParamCounter = 0; - private final Set sortParams = new HashSet<>(); - public static final String SORTPARAM_NAME = "#SortParam"; - private boolean isLHS = false; - - public AddSortInjections(Module mod) { - this.mod = mod; - this.collectionFor = ConvertDataStructureToLookup.collectionFor(mod); - this.configurationInfo = new ConfigurationInfoFromModule(mod); + private final Module mod; + private final Map collectionFor; + private final ConfigurationInfoFromModule configurationInfo; + + private int freshSortParamCounter = 0; + private final Set sortParams = new HashSet<>(); + public static final String SORTPARAM_NAME = "#SortParam"; + private boolean isLHS = false; + + public AddSortInjections(Module mod) { + this.mod = mod; + this.collectionFor = ConvertDataStructureToLookup.collectionFor(mod); + this.configurationInfo = new ConfigurationInfoFromModule(mod); + } + + public Sentence addInjections(Sentence s) { + if (s instanceof RuleOrClaim) { + return addInjections((RuleOrClaim) s); + } else { + return s; } - - public Sentence addInjections(Sentence s) { - if (s instanceof RuleOrClaim) { - return addInjections((RuleOrClaim) s); - } else { - return s; - } + } + + public RuleOrClaim addInjections(RuleOrClaim roc) { + initSortParams(); + K body = addTopSortInjections(roc.body()); + K requires = internalAddSortInjections(roc.requires(), Sorts.Bool()); + K ensures = internalAddSortInjections(roc.ensures(), Sorts.Bool()); + Att att = roc.att(); + if (!sortParams.isEmpty()) { + att = + att.add( + Att.SORT_PARAMS(), + Sort.class, + Sort("", sortParams.stream().map(s -> Sort(s)).collect(Collections.toList()))); } - - public RuleOrClaim addInjections(RuleOrClaim roc) { - initSortParams(); - K body = addTopSortInjections(roc.body()); - K requires = internalAddSortInjections(roc.requires(), Sorts.Bool()); - K ensures = internalAddSortInjections(roc.ensures(), Sorts.Bool()); - Att att = roc.att(); - if (!sortParams.isEmpty()) { - att = att.add(Att.SORT_PARAMS(), Sort.class, Sort("", sortParams.stream().map(s -> Sort(s)).collect(Collections.toList()))); - } - return roc.newInstance(body, requires, ensures, att); + return roc.newInstance(body, requires, ensures, att); + } + + public K addInjections(K term) { + Sort topSort = sort(term, Sorts.K()); + K result = addSortInjections(term, topSort); + return result; + } + + public K addSortInjections(K term, Sort topSort) { + initSortParams(); + return internalAddSortInjections(term, topSort); + } + + private boolean collectionIsMap(KLabel collectionLabel) { + return mod.attributesFor().apply(collectionLabel).contains(Att.COMM()) + && !mod.attributesFor().apply(collectionLabel).contains(Att.IDEM()) + && !mod.attributesFor().apply(collectionLabel).contains(Att.BAG()); + } + + private K addTopSortInjections(K body) { + if (new FoldK() { + @Override + public Boolean unit() { + return false; + } + + @Override + public Boolean apply(KRewrite k) { + return true; + } + + @Override + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } + }.apply(body)) { + body = KRewrite(RewriteToTop.toLeft(body), RewriteToTop.toRight(body)); } - - public K addInjections(K term) { - Sort topSort = sort(term, Sorts.K()); - K result = addSortInjections(term, topSort); - return result; - } - - public K addSortInjections(K term, Sort topSort) { - initSortParams(); - return internalAddSortInjections(term, topSort); + Sort sort = topSort(body); + return internalAddSortInjections(body, sort); + } + + private K internalAddSortInjections(K term, Sort expectedSort) { + Sort actualSort = sort(term, expectedSort); + if (actualSort == null) { + actualSort = expectedSort; } - - private boolean collectionIsMap(KLabel collectionLabel) { - return mod.attributesFor().apply(collectionLabel).contains(Att.COMM()) - && !mod.attributesFor().apply(collectionLabel).contains(Att.IDEM()) - && !mod.attributesFor().apply(collectionLabel).contains(Att.BAG()); - } - - private K addTopSortInjections(K body) { - if (new FoldK() { - @Override - public Boolean unit() { - return false; - } - - @Override - public Boolean apply(KRewrite k) { - return true; - } - - @Override - public Boolean merge(Boolean a, Boolean b) { - return a || b; + if (actualSort.equals(expectedSort)) { + return visitChildren(term, actualSort, expectedSort); + } else if (expectedSort.equals(Sorts.K())) { + if (actualSort.equals(Sorts.KItem())) { + return KSequence(visitChildren(term, actualSort, expectedSort)); + } else { + return KSequence( + KApply( + KLabel("inj", actualSort, Sorts.KItem()), + KList(visitChildren(term, actualSort, expectedSort)), + Att.empty().add(Sort.class, Sorts.KItem()))); + } + } else { + String hookAtt = + mod.sortAttributesFor() + .get(expectedSort.head()) + .getOrElse(() -> Att()) + .getOptional(Att.HOOK()) + .orElse(""); + if ((hookAtt.equals("MAP.Map") || hookAtt.equals("SET.Set") || hookAtt.equals("LIST.List")) + && term instanceof KApply) { + for (KLabel collectionLabel : collectionFor.keySet()) { + Optional wrapElement = + mod.attributesFor().apply(collectionLabel).getOptional(Att.WRAP_ELEMENT()); + if (wrapElement.isPresent()) { + KLabel wrappedLabel = KLabel(wrapElement.get()); + KLabel elementLabel = + KLabel(mod.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); + KApply k = (KApply) term; + if (configurationInfo.getCellSort(wrappedLabel).equals(actualSort)) { + if (collectionIsMap(collectionLabel)) { + // Map + K key; + if (k.klabel().equals(wrappedLabel)) { + key = k.klist().items().get(0); + } else { + key = + KApply( + KLabel(expectedSort.name() + "Key"), + KList(visitChildren(k, actualSort, expectedSort))); + } + Sort adjustedExpectedSort = expectedSort; + if (k.att().contains(Sort.class)) { + adjustedExpectedSort = k.att().get(Sort.class); + } + Production prod = production(k); + List children = new ArrayList<>(); + Production substituted = + substituteProd( + prod, + adjustedExpectedSort, + (i, fresh) -> sort(k.items().get(i), fresh.nonterminals().apply(i).sort()), + k); + Sort expectedKeySort = substituted.nonterminal(0).sort(); + Sort actualKeySort = sort(key, expectedKeySort); + return KApply( + elementLabel, + KList( + visitChildren(key, actualKeySort, expectedKeySort), + visitChildren(k, actualSort, expectedSort)), + Att.empty().add(Sort.class, expectedSort)); + } else { + return KApply( + elementLabel, + KList(visitChildren(k, actualSort, expectedSort)), + Att.empty().add(Sort.class, expectedSort)); + } } - }.apply(body)) { - body = KRewrite(RewriteToTop.toLeft(body), RewriteToTop.toRight(body)); + } } - Sort sort = topSort(body); - return internalAddSortInjections(body, sort); + } + return KApply( + KLabel("inj", actualSort, expectedSort), + KList(visitChildren(term, actualSort, expectedSort)), + Att.empty().add(Sort.class, expectedSort)); } - - private K internalAddSortInjections(K term, Sort expectedSort) { - Sort actualSort = sort(term, expectedSort); - if (actualSort == null) { - actualSort = expectedSort; + } + + private Context addInjections(Context context) { + return new Context( + internalAddSortInjections(context.body(), Sorts.K()), + internalAddSortInjections(context.requires(), Sorts.Bool()), + context.att()); + } + + private void initSortParams() { + freshSortParamCounter = 0; + sortParams.clear(); + } + + private K visitChildren(K term, Sort actualSort, Sort expectedSort) { + Att att = term.att().add(Sort.class, actualSort); + if (actualSort.name().equals(SORTPARAM_NAME)) { + sortParams.add(actualSort.params().head().name()); + } + if (term instanceof KApply kapp) { + if (kapp.klabel().name().equals("inj")) { + return term; + } + if (kapp.att().contains(Sort.class)) { + expectedSort = kapp.att().get(Sort.class); + } + Production prod = production(kapp); + List children = new ArrayList<>(); + Production substituted = + substituteProd( + prod, + expectedSort, + (i, fresh) -> sort(kapp.items().get(i), fresh.nonterminals().apply(i).sort()), + kapp); + for (int i = 0; i < kapp.items().size(); i++) { + if (kapp.items().size() != substituted.nonterminals().size()) { + throw KEMException.compilerError( + "Invalid sort predicate " + + kapp.klabel() + + " that depends directly or indirectly on the current configuration. " + + "Is it possible to replace the sort predicate with a regular function?", + kapp); } - if (actualSort.equals(expectedSort)) { - return visitChildren(term, actualSort, expectedSort); - } else if (expectedSort.equals(Sorts.K())) { - if (actualSort.equals(Sorts.KItem())) { - return KSequence(visitChildren(term, actualSort, expectedSort)); - } else { - return KSequence(KApply(KLabel("inj", actualSort, Sorts.KItem()), KList(visitChildren(term, actualSort, expectedSort)), Att.empty().add(Sort.class, Sorts.KItem()))); - } + Sort expectedSortOfChild = substituted.nonterminal(i).sort(); + K child = kapp.items().get(i); + children.add(internalAddSortInjections(child, expectedSortOfChild)); + } + return KApply(substituted.klabel().get(), KList(children), att); + } else if (term instanceof KRewrite rew) { + isLHS = true; + K lhs = internalAddSortInjections(rew.left(), actualSort); + isLHS = false; + return KRewrite(lhs, internalAddSortInjections(rew.right(), actualSort), att); + } else if (term instanceof KVariable) { + return KVariable(((KVariable) term).name(), att); + } else if (term instanceof KToken) { + return KToken(((KToken) term).s(), ((KToken) term).sort(), att); + } else if (term instanceof InjectedKLabel) { + return InjectedKLabel(((InjectedKLabel) term).klabel(), att); + } else if (term instanceof KSequence kseq) { + List children = new ArrayList<>(); + for (int i = 0; i < kseq.size(); i++) { + K child = kseq.items().get(i); + Sort childSort = sort(child, isLHS ? Sorts.KItem() : Sorts.K()); + if (childSort.equals(Sorts.K())) { + children.add(internalAddSortInjections(child, Sorts.K())); } else { - String hookAtt = mod.sortAttributesFor().get(expectedSort.head()).getOrElse(() -> Att()).getOptional(Att.HOOK()).orElse(""); - if ((hookAtt.equals("MAP.Map") || hookAtt.equals("SET.Set") || hookAtt.equals("LIST.List")) && term instanceof KApply) { - for (KLabel collectionLabel : collectionFor.keySet()) { - Optional wrapElement = mod.attributesFor().apply(collectionLabel).getOptional(Att.WRAP_ELEMENT()); - if (wrapElement.isPresent()) { - KLabel wrappedLabel = KLabel(wrapElement.get()); - KLabel elementLabel = KLabel(mod.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); - KApply k = (KApply)term; - if (configurationInfo.getCellSort(wrappedLabel).equals(actualSort)) { - if (collectionIsMap(collectionLabel)) { - // Map - K key; - if (k.klabel().equals(wrappedLabel)) { - key = k.klist().items().get(0); - } else { - key = KApply(KLabel(expectedSort.name() + "Key"), KList(visitChildren(k, actualSort, expectedSort))); - } - Sort adjustedExpectedSort = expectedSort; - if (k.att().contains(Sort.class)) { - adjustedExpectedSort = k.att().get(Sort.class); - } - Production prod = production(k); - List children = new ArrayList<>(); - Production substituted = substituteProd(prod, adjustedExpectedSort, (i, fresh) -> sort(k.items().get(i), fresh.nonterminals().apply(i).sort()), k); - Sort expectedKeySort = substituted.nonterminal(0).sort(); - Sort actualKeySort = sort(key, expectedKeySort); - return KApply(elementLabel, KList(visitChildren(key, actualKeySort, expectedKeySort), visitChildren(k, actualSort, expectedSort)), Att.empty().add(Sort.class, expectedSort)); - } else { - return KApply(elementLabel, KList(visitChildren(k, actualSort, expectedSort)), Att.empty().add(Sort.class, expectedSort)); - } - } - } - } - } - return KApply(KLabel("inj", actualSort, expectedSort), KList(visitChildren(term, actualSort, expectedSort)), Att.empty().add(Sort.class, expectedSort)); + children.add(internalAddSortInjections(child, Sorts.KItem())); } + } + return KSequence(children, att); + } else if (term instanceof KAs kas) { + return KAs(internalAddSortInjections(kas.pattern(), actualSort), kas.alias(), att); + } else { + throw KEMException.internalError("Invalid category of k found.", term); } - - private Context addInjections(Context context) { - return new Context(internalAddSortInjections(context.body(), Sorts.K()), internalAddSortInjections(context.requires(), Sorts.Bool()), context.att()); + } + + /** + * Generate the substituted production with its sort parameters added for a parametric production. + * + * @param prod The production to add sort parameters to. + * @param expectedSort the sort context where the term with the specified production appears. + * @param getSort a function taking the 0-based index of the child of this production and the + * substitutedFresh production and returning the sort of the child. + * @param loc The location to report upon an error. + * @return The production substituted with the least upper bounds of its sort parameters based on + * its children's sorts. + */ + public Production substituteProd( + Production prod, + Sort expectedSort, + BiFunction getSort, + HasLocation loc) { + Production substituted = prod; + List args = new ArrayList<>(); + List fresh = new ArrayList<>(); + for (int i = 0; i < prod.params().size(); i++) { + if (prod.params().apply(i).equals(prod.sort())) { + fresh.add(expectedSort); + } else { + fresh.add(freshSortParam()); + } } - - private void initSortParams() { - freshSortParamCounter = 0; - sortParams.clear(); - } - - private K visitChildren(K term, Sort actualSort, Sort expectedSort) { - Att att = term.att().add(Sort.class, actualSort); - if (actualSort.name().equals(SORTPARAM_NAME)) { - sortParams.add(actualSort.params().head().name()); - } - if (term instanceof KApply kapp) { - if (kapp.klabel().name().equals("inj")) { - return term; - } - if (kapp.att().contains(Sort.class)) { - expectedSort = kapp.att().get(Sort.class); - } - Production prod = production(kapp); - List children = new ArrayList<>(); - Production substituted = substituteProd(prod, expectedSort, (i, fresh) -> sort(kapp.items().get(i), fresh.nonterminals().apply(i).sort()), kapp); - for (int i = 0; i < kapp.items().size(); i++) { - if (kapp.items().size() != substituted.nonterminals().size()) { - throw KEMException.compilerError("Invalid sort predicate " + kapp.klabel() + - " that depends directly or indirectly on the current configuration. " + - "Is it possible to replace the sort predicate with a regular function?", kapp); - } - Sort expectedSortOfChild = substituted.nonterminal(i).sort(); - K child = kapp.items().get(i); - children.add(internalAddSortInjections(child, expectedSortOfChild)); - } - return KApply(substituted.klabel().get(), KList(children), att); - } else if (term instanceof KRewrite rew) { - isLHS = true; - K lhs = internalAddSortInjections(rew.left(), actualSort); - isLHS = false; - return KRewrite(lhs, internalAddSortInjections(rew.right(), actualSort), att); - } else if (term instanceof KVariable) { - return KVariable(((KVariable) term).name(), att); - } else if (term instanceof KToken) { - return KToken(((KToken) term).s(), ((KToken) term).sort(), att); - } else if (term instanceof InjectedKLabel) { - return InjectedKLabel(((InjectedKLabel) term).klabel(), att); - } else if (term instanceof KSequence kseq) { - List children = new ArrayList<>(); - for (int i = 0; i < kseq.size(); i++) { - K child = kseq.items().get(i); - Sort childSort = sort(child, isLHS ? Sorts.KItem() : Sorts.K()); - if (childSort.equals(Sorts.K())) { - children.add(internalAddSortInjections(child, Sorts.K())); - } else { - children.add(internalAddSortInjections(child, Sorts.KItem())); - } - } - return KSequence(children, att); - } else if (term instanceof KAs kas) { - return KAs(internalAddSortInjections(kas.pattern(), actualSort), kas.alias(), att); + Production substitutedFresh = prod.substitute(immutable(fresh)); + if (prod.params().nonEmpty()) { + Map> subst = new HashMap<>(); + for (int i = 0; i < prod.nonterminals().size(); i++) { + Sort declaredSort = prod.nonterminals().apply(i).sort(); + Sort actual = getSort.apply(i, substitutedFresh); + match(prod, declaredSort, actual, subst); + } + int i = 0; + matchExpected(prod, expectedSort, subst); + for (Sort param : iterable(prod.params())) { + if (subst.get(param) == null) { + args.add(fresh.get(i)); } else { - throw KEMException.internalError("Invalid category of k found.", term); + args.add(lub(subst.get(param), fresh.get(i), loc, mod)); } + i++; + } + substituted = prod.substitute(immutable(args)); } - - /** - * Generate the substituted production with its sort parameters added for a parametric production. - * @param prod The production to add sort parameters to. - * @param expectedSort the sort context where the term with the specified production appears. - * @param getSort a function taking the 0-based index of the child of this production and the substitutedFresh production and returning the sort of the child. - * @param loc The location to report upon an error. - * @return The production substituted with the least upper bounds of its sort parameters based on its children's sorts. - */ - public Production substituteProd(Production prod, Sort expectedSort, BiFunction getSort, HasLocation loc) { - Production substituted = prod; - List args = new ArrayList<>(); - List fresh = new ArrayList<>(); - for (int i = 0; i < prod.params().size(); i++) { - if (prod.params().apply(i).equals(prod.sort())) { - fresh.add(expectedSort); - } else { - fresh.add(freshSortParam()); - } - } - Production substitutedFresh = prod.substitute(immutable(fresh)); - if (prod.params().nonEmpty()) { - Map> subst = new HashMap<>(); - for (int i = 0; i < prod.nonterminals().size(); i++) { - Sort declaredSort = prod.nonterminals().apply(i).sort(); - Sort actual = getSort.apply(i, substitutedFresh); - match(prod, declaredSort, actual, subst); - } - int i = 0; - matchExpected(prod, expectedSort, subst); - for (Sort param : iterable(prod.params())) { - if (subst.get(param) == null) { - args.add(fresh.get(i)); - } else { - args.add(lub(subst.get(param), fresh.get(i), loc, mod)); - } - i++; - } - substituted = prod.substitute(immutable(args)); + return substituted; + } + + private void match( + Production prod, Sort declaredSort, Sort actualSort, Map> subst) { + if (prod.isSortVariable(declaredSort)) { + subst.computeIfAbsent(declaredSort, s -> new ArrayList<>()).add(actualSort); + return; + } + if (actualSort.params().size() == declaredSort.params().size() + && actualSort.head().equals(declaredSort.head())) { + for (int i = 0; i < declaredSort.head().params(); i++) { + match(prod, declaredSort.params().apply(i), actualSort.params().apply(i), subst); + } + } + for (Sort s : iterable(mod.allSorts())) { + if (mod.subsorts().lessThanEq(s, actualSort)) { + if (s.params().size() == declaredSort.params().size() + && s.head().equals(declaredSort.head())) { + for (int i = 0; i < declaredSort.head().params(); i++) { + match(prod, declaredSort.params().apply(i), s.params().apply(i), subst); + } } - return substituted; + } } - - private void match(Production prod, Sort declaredSort, Sort actualSort, Map> subst) { - if (prod.isSortVariable(declaredSort)) { - subst.computeIfAbsent(declaredSort, s -> new ArrayList<>()).add(actualSort); - return; + } + + private Set getPositions(Sort param, Production prod) { + return IntStream.range(0, prod.nonterminals().size()) + .mapToObj(i -> Tuple2.apply(prod.nonterminals().apply(i), i)) + .filter(t -> t._1().sort().equals(param)) + .map(t -> t._2()) + .collect(Collectors.toSet()); + } + + /** + * Compute the sort of a term in a context where there is no expected sort, i.e., at the top of a + * rule body. + */ + public Sort topSort(K term) { + return sort(term, freshSortParam()); + } + + /** Compute the sort of a term with a particular expected sort. */ + public Sort sort(K term, Sort expectedSort) { + if (term instanceof KApply kapp) { + if (kapp.klabel().name().equals("inj")) { + return kapp.klabel().params().apply(1); + } + if (kapp.klabel().name().startsWith("#SemanticCastTo")) { + return Outer.parseSort(kapp.klabel().name().substring("#SemanticCastTo".length())); + } + if (kapp.klabel().name().equals("#fun2")) { + return sort(kapp.items().get(0), expectedSort); + } + if (kapp.klabel().name().equals("#fun3")) { + return sort(kapp.items().get(1), expectedSort); + } + if (kapp.klabel().name().equals("#let")) { + return sort(kapp.items().get(2), expectedSort); + } + if (kapp.klabel().name().equals("_:=K_")) { + return Sorts.Bool(); + } + if (kapp.klabel().name().equals("_:/=K_")) { + return Sorts.Bool(); + } + if (kapp.att().contains(Sort.class)) { + expectedSort = kapp.att().get(Sort.class); + } + Production prod = production(kapp); + Production substituted = prod; + List args = new ArrayList<>(); + List fresh = new ArrayList<>(); + for (int i = 0; i < prod.params().size(); i++) { + if (prod.params().apply(i).equals(prod.sort())) { + fresh.add(expectedSort); + } else { + fresh.add(freshSortParam()); } - if (actualSort.params().size() == declaredSort.params().size() && actualSort.head().equals(declaredSort.head())) { - for (int i = 0; i < declaredSort.head().params(); i++) { - match(prod, declaredSort.params().apply(i), actualSort.params().apply(i), subst); - } + } + Production substitutedFresh = prod.substitute(immutable(fresh)); + if (prod.params().nonEmpty()) { + Map> subst = new HashMap<>(); + for (int i = 0; i < prod.nonterminals().size(); i++) { + Sort declaredSort = prod.nonterminals().apply(i).sort(); + Sort actual = sort(kapp.items().get(i), substitutedFresh.nonterminals().apply(i).sort()); + match(prod, declaredSort, actual, subst); } - for (Sort s : iterable(mod.allSorts())) { - if (mod.subsorts().lessThanEq(s, actualSort)) { - if (s.params().size() == declaredSort.params().size() && s.head().equals(declaredSort.head())) { - for (int i = 0; i < declaredSort.head().params(); i++) { - match(prod, declaredSort.params().apply(i), s.params().apply(i), subst); - } - } - } + int i = 0; + matchExpected(prod, expectedSort, subst); + for (Sort param : iterable(prod.params())) { + if (subst.get(param) == null) { + args.add(fresh.get(i)); + } else { + args.add(lub(subst.get(param), fresh.get(i), kapp, mod)); + } + i++; } + substituted = prod.substitute(immutable(args)); + } + return substituted.sort(); + } else if (term instanceof KRewrite rew) { + Sort leftSort = sort(rew.left(), expectedSort); + Sort rightSort = sort(rew.right(), expectedSort); + return lubSort(leftSort, rightSort, expectedSort, term, mod); + } else if (term instanceof KToken) { + return ((KToken) term).sort(); + } else if (term instanceof KVariable) { + return term.att().getOptional(Sort.class).orElse(Sorts.K()); + } else if (term instanceof KSequence) { + return Sorts.K(); + } else if (term instanceof InjectedKLabel) { + return Sorts.KItem(); + } else if (term instanceof KAs as) { + Sort patternSort = sort(as.pattern(), expectedSort); + Sort rightSort = sort(as.alias(), expectedSort); + return lubSort(patternSort, rightSort, expectedSort, term, mod); + } else { + throw KEMException.internalError("Invalid category of k found.", term); } - - private Set getPositions(Sort param, Production prod) { - return IntStream.range(0, prod.nonterminals().size()) - .mapToObj(i -> Tuple2.apply(prod.nonterminals().apply(i), i)) - .filter(t -> t._1().sort().equals(param)) - .map(t -> t._2()) - .collect(Collectors.toSet()); + } + + private void matchExpected(Production prod, Sort expectedSort, Map> subst) { + boolean found = false; + outer: + for (Sort param : iterable(prod.params())) { + if (!prod.sort().contains(param)) { + continue; + } + for (NonTerminal nt : iterable(prod.nonterminals())) { + if (nt.sort().contains(param)) { + continue outer; + } + } + found = true; } - - /** - * Compute the sort of a term in a context where there is no expected sort, i.e., at the top of a rule body. - */ - public Sort topSort(K term) { - return sort(term, freshSortParam()); + if (found) { + match(prod, prod.sort(), expectedSort, subst); } - - /** - * Compute the sort of a term with a particular expected sort. - */ - public Sort sort(K term, Sort expectedSort) { - if (term instanceof KApply kapp) { - if (kapp.klabel().name().equals("inj")) { - return kapp.klabel().params().apply(1); - } - if (kapp.klabel().name().startsWith("#SemanticCastTo")) { - return Outer.parseSort(kapp.klabel().name().substring("#SemanticCastTo".length())); - } - if (kapp.klabel().name().equals("#fun2")) { - return sort(kapp.items().get(0), expectedSort); - } - if (kapp.klabel().name().equals("#fun3")) { - return sort(kapp.items().get(1), expectedSort); - } - if (kapp.klabel().name().equals("#let")) { - return sort(kapp.items().get(2), expectedSort); - } - if (kapp.klabel().name().equals("_:=K_")) { - return Sorts.Bool(); - } - if (kapp.klabel().name().equals("_:/=K_")) { - return Sorts.Bool(); - } - if (kapp.att().contains(Sort.class)) { - expectedSort = kapp.att().get(Sort.class); - } - Production prod = production(kapp); - Production substituted = prod; - List args = new ArrayList<>(); - List fresh = new ArrayList<>(); - for (int i = 0; i < prod.params().size(); i++) { - if (prod.params().apply(i).equals(prod.sort())) { - fresh.add(expectedSort); - } else { - fresh.add(freshSortParam()); - } - } - Production substitutedFresh = prod.substitute(immutable(fresh)); - if (prod.params().nonEmpty()) { - Map> subst = new HashMap<>(); - for (int i = 0; i < prod.nonterminals().size(); i++) { - Sort declaredSort = prod.nonterminals().apply(i).sort(); - Sort actual = sort(kapp.items().get(i), substitutedFresh.nonterminals().apply(i).sort()); - match(prod, declaredSort, actual, subst); - } - int i = 0; - matchExpected(prod, expectedSort, subst); - for (Sort param : iterable(prod.params())) { - if (subst.get(param) == null) { - args.add(fresh.get(i)); - } else { - args.add(lub(subst.get(param), fresh.get(i), kapp, mod)); - } - i++; - } - substituted = prod.substitute(immutable(args)); - } - return substituted.sort(); - } else if (term instanceof KRewrite rew) { - Sort leftSort = sort(rew.left(), expectedSort); - Sort rightSort = sort(rew.right(), expectedSort); - return lubSort(leftSort, rightSort, expectedSort, term, mod); - } else if (term instanceof KToken) { - return ((KToken) term).sort(); - } else if (term instanceof KVariable) { - return term.att().getOptional(Sort.class).orElse(Sorts.K()); - } else if (term instanceof KSequence) { - return Sorts.K(); - } else if (term instanceof InjectedKLabel) { - return Sorts.KItem(); - } else if (term instanceof KAs as) { - Sort patternSort = sort(as.pattern(), expectedSort); - Sort rightSort = sort(as.alias(), expectedSort); - return lubSort(patternSort, rightSort, expectedSort, term, mod); - } else { - throw KEMException.internalError("Invalid category of k found.", term); - } + } + + public static Sort lubSort( + Sort leftSort, Sort rightSort, Sort expectedSort, HasLocation loc, Module mod) { + if (leftSort == null && rightSort == null) { + return expectedSort; + } else if (leftSort == null) { + return rightSort; + } else if (rightSort == null) { + return leftSort; } + return lub(Arrays.asList(leftSort, rightSort), expectedSort, loc, mod); + } - private void matchExpected(Production prod, Sort expectedSort, Map> subst) { - boolean found = false; - outer: - for (Sort param : iterable(prod.params())) { - if (!prod.sort().contains(param)) { - continue; - } - for (NonTerminal nt : iterable(prod.nonterminals())) { - if (nt.sort().contains(param)) { - continue outer; - } - } - found = true; - } - if (found) { - match(prod, prod.sort(), expectedSort, subst); - } + private Production production(KApply term) { + if (term.klabel() instanceof KVariable) { + throw KEMException.internalError("KORE does not yet support KLabel variables.", term); } - - public static Sort lubSort(Sort leftSort, Sort rightSort, Sort expectedSort, HasLocation loc, Module mod) { - if (leftSort == null && rightSort == null) { - return expectedSort; - } else if (leftSort == null) { - return rightSort; - } else if (rightSort == null) { - return leftSort; - } - return lub(Arrays.asList(leftSort, rightSort), expectedSort, loc, mod); + Option> prods = mod.productionsFor().get(term.klabel().head()); + if (prods.isEmpty()) { + throw KEMException.compilerError( + "Could not find productions for KApply with label " + + term.klabel() + + " in module " + + mod.name(), + term); } - - private Production production(KApply term) { - if (term.klabel() instanceof KVariable) { - throw KEMException.internalError("KORE does not yet support KLabel variables.", term); - } - Option> prods = mod.productionsFor().get(term.klabel().head()); - if (prods.isEmpty()) { - throw KEMException.compilerError("Could not find productions for KApply with label " - + term.klabel() + " in module " + mod.name(), term); - } - return prods.get().head(); + return prods.get().head(); + } + + private static Sort lub( + Collection entries, Sort expectedSort, HasLocation loc, Module mod) { + assert !entries.isEmpty(); + entries = new HashSet<>(entries); + Collection filteredEntries = + entries.stream() + .filter(s -> s != null && !s.name().equals(SORTPARAM_NAME)) + .collect(Collectors.toList()); + if (filteredEntries.isEmpty()) { // if all sorts are parameters, take the first + return entries.iterator().next(); } - private static Sort lub(Collection entries, Sort expectedSort, HasLocation loc, Module mod) { - assert !entries.isEmpty(); - entries = new HashSet<>(entries); - Collection filteredEntries = entries.stream().filter(s -> s != null && !s.name().equals(SORTPARAM_NAME)).collect(Collectors.toList()); - if (filteredEntries.isEmpty()) { // if all sorts are parameters, take the first - return entries.iterator().next(); - } - - Set nonParametric = - filteredEntries.stream().filter(s -> s.params().isEmpty()).collect(Collectors.toSet()); - Set bounds = mutable(mod.subsorts().upperBounds(immutable(nonParametric))); - // Anything less than KBott or greater than K is a syntactic sort from kast.md which should not be considered - bounds.removeIf(s -> mod.subsorts().lessThanEq(s, Sorts.KBott()) || mod.subsorts().greaterThan(s, Sorts.K())); - if (expectedSort != null && !expectedSort.name().equals(SORTPARAM_NAME)) { - bounds.removeIf(s -> !mod.subsorts().lessThanEq(s, expectedSort)); - } + Set nonParametric = + filteredEntries.stream().filter(s -> s.params().isEmpty()).collect(Collectors.toSet()); + Set bounds = mutable(mod.subsorts().upperBounds(immutable(nonParametric))); + // Anything less than KBott or greater than K is a syntactic sort from kast.md which should not + // be considered + bounds.removeIf( + s -> + mod.subsorts().lessThanEq(s, Sorts.KBott()) + || mod.subsorts().greaterThan(s, Sorts.K())); + if (expectedSort != null && !expectedSort.name().equals(SORTPARAM_NAME)) { + bounds.removeIf(s -> !mod.subsorts().lessThanEq(s, expectedSort)); + } - // For parametric sorts, each bound must bound at least one instantiation - Set parametric = - filteredEntries.stream().filter(s -> ! s.params().isEmpty()).collect(Collectors.toSet()); - bounds.removeIf(bound -> - parametric.stream().anyMatch(param -> + // For parametric sorts, each bound must bound at least one instantiation + Set parametric = + filteredEntries.stream().filter(s -> !s.params().isEmpty()).collect(Collectors.toSet()); + bounds.removeIf( + bound -> + parametric.stream() + .anyMatch( + param -> stream(mod.definedInstantiations().apply(param.head())) - .noneMatch(inst -> mod.subsorts().lessThanEq(inst, bound)))); + .noneMatch(inst -> mod.subsorts().lessThanEq(inst, bound)))); - Set lub = mod.subsorts().minimal(bounds); - if (lub.size() != 1) { - throw KEMException.internalError("Could not compute least upper bound for rewrite sort. Possible candidates: " + lub, loc); - } - return lub.iterator().next(); + Set lub = mod.subsorts().minimal(bounds); + if (lub.size() != 1) { + throw KEMException.internalError( + "Could not compute least upper bound for rewrite sort. Possible candidates: " + lub, loc); } + return lub.iterator().next(); + } - private Sort freshSortParam() { - return Sort(SORTPARAM_NAME, Sort("Q" + freshSortParamCounter++)); - } + private Sort freshSortParam() { + return Sort(SORTPARAM_NAME, Sort("Q" + freshSortParamCounter++)); + } } diff --git a/kernel/src/main/java/org/kframework/compile/AddTopCellToRules.java b/kernel/src/main/java/org/kframework/compile/AddTopCellToRules.java index 5b8aff5f585..d05e8f5ac74 100644 --- a/kernel/src/main/java/org/kframework/compile/AddTopCellToRules.java +++ b/kernel/src/main/java/org/kframework/compile/AddTopCellToRules.java @@ -1,9 +1,14 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.List; import org.kframework.attributes.Att; -import org.kframework.builtin.KLabels; import org.kframework.backend.kore.ConstructorChecks; +import org.kframework.builtin.KLabels; import org.kframework.definition.Context; import org.kframework.definition.Module; import org.kframework.definition.Production; @@ -15,119 +20,104 @@ import org.kframework.kore.KRewrite; import org.kframework.kore.Sort; -import java.util.ArrayList; -import java.util.List; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - /** - * This pass adds the implicit top and k cells to - * the bodies of rules and contexts. - * A K cell is added only if the body is a single item, - * which is not already a cell or a rewrite on cells. - * The top cell is added unless the body is already an - * instance of the top cell. - * Rules with the anywhere attribute are not modified. + * This pass adds the implicit top and k cells to the bodies of rules and contexts. A K cell is + * added only if the body is a single item, which is not already a cell or a rewrite on cells. The + * top cell is added unless the body is already an instance of the top cell. Rules with the anywhere + * attribute are not modified. */ // TODO: rules defining functions shouldn't be wrapped public record AddTopCellToRules(ConfigurationInfo cfg, LabelInfo labelInfo) { - public K addImplicitCells(K term, Module m) { - if (m.isFunction(term)) return term; - return addRootCell(term); - } - - private K addRootCell(K term) { - KLabel root; - root = KLabels.GENERATED_TOP_CELL; + public K addImplicitCells(K term, Module m) { + if (m.isFunction(term)) return term; + return addRootCell(term); + } - // KApply instance - if (term instanceof KApply) { - KLabel kLabel = ((KApply) term).klabel(); - if (ConstructorChecks.isBuiltinLabel(kLabel)) { - // builtin-labels (ML connectives) - Production prod = labelInfo.getProduction(kLabel.name()); - if(prod.params().nonEmpty()) { - for (Sort param : iterable(prod.params())) { - if (prod.sort().equals(param)) { - if (stream(prod.nonterminals()).anyMatch(nt -> nt.sort().equals(param))) { - // recursively call addRoot on the children whose type is the same as the return type - List oldChildren = ((KApply) term).klist().items(); - List newChildren = new ArrayList<>(); - for (int i = 0; i < oldChildren.size(); i++) { - if (prod.nonterminals().apply(i).sort().equals(param)) { - newChildren.add(addRootCell(oldChildren.get(i))); - } else { - newChildren.add(oldChildren.get(i)); - } + private K addRootCell(K term) { + KLabel root; + root = KLabels.GENERATED_TOP_CELL; - } - return KApply(kLabel, KList(newChildren)); - } else { - // only one group can contain 0 - return term; - } - } - } - // if 0 doesn't appear in the poly attribute - return term; - } else { - // connectives that don't have poly attribute - return term; - } - } else { - if (kLabel.equals(root)) { - return term; + // KApply instance + if (term instanceof KApply) { + KLabel kLabel = ((KApply) term).klabel(); + if (ConstructorChecks.isBuiltinLabel(kLabel)) { + // builtin-labels (ML connectives) + Production prod = labelInfo.getProduction(kLabel.name()); + if (prod.params().nonEmpty()) { + for (Sort param : iterable(prod.params())) { + if (prod.sort().equals(param)) { + if (stream(prod.nonterminals()).anyMatch(nt -> nt.sort().equals(param))) { + // recursively call addRoot on the children whose type is the same as the return + // type + List oldChildren = ((KApply) term).klist().items(); + List newChildren = new ArrayList<>(); + for (int i = 0; i < oldChildren.size(); i++) { + if (prod.nonterminals().apply(i).sort().equals(param)) { + newChildren.add(addRootCell(oldChildren.get(i))); + } else { + newChildren.add(oldChildren.get(i)); + } } + return KApply(kLabel, KList(newChildren)); + } else { + // only one group can contain 0 + return term; + } } + } + // if 0 doesn't appear in the poly attribute + return term; + } else { + // connectives that don't have poly attribute + return term; } - - // KRewrite instance - if (term instanceof KRewrite rew) { - K left = addRootCell(rew.left()); - if (left == rew.left()) { - return KRewrite(rew.left(), rew.right()); - } else { - return IncompleteCellUtils.make(root, true, term, true); - } + } else { + if (kLabel.equals(root)) { + return term; } + } + } - // default + // KRewrite instance + if (term instanceof KRewrite rew) { + K left = addRootCell(rew.left()); + if (left == rew.left()) { + return KRewrite(rew.left(), rew.right()); + } else { return IncompleteCellUtils.make(root, true, term, true); + } } - public RuleOrClaim addImplicitCells(RuleOrClaim rule, Module m) { - return rule.newInstance( - addImplicitCells(rule.body(), m), - rule.requires(), - rule.ensures(), - rule.att()); - } + // default + return IncompleteCellUtils.make(root, true, term, true); + } - public Context addImplicitCells(Context context, Module m) { - return new Context( - addImplicitCells(context.body(), m), - context.requires(), - context.att()); - } + public RuleOrClaim addImplicitCells(RuleOrClaim rule, Module m) { + return rule.newInstance( + addImplicitCells(rule.body(), m), rule.requires(), rule.ensures(), rule.att()); + } - public Sentence addImplicitCells(Sentence s, Module m) { - if (skipSentence(s)) { - return s; - } - if (s instanceof RuleOrClaim) { - return addImplicitCells((RuleOrClaim) s, m); - } else if (s instanceof Context) { - return addImplicitCells((Context) s, m); - } else { - return s; - } - } + public Context addImplicitCells(Context context, Module m) { + return new Context(addImplicitCells(context.body(), m), context.requires(), context.att()); + } - private boolean skipSentence(Sentence s) { - return ExpandMacros.isMacro(s) - || s.att().contains(Att.ANYWHERE()) - || s.att().contains(Att.SIMPLIFICATION()); + public Sentence addImplicitCells(Sentence s, Module m) { + if (skipSentence(s)) { + return s; + } + if (s instanceof RuleOrClaim) { + return addImplicitCells((RuleOrClaim) s, m); + } else if (s instanceof Context) { + return addImplicitCells((Context) s, m); + } else { + return s; } + } + + private boolean skipSentence(Sentence s) { + return ExpandMacros.isMacro(s) + || s.att().contains(Att.ANYWHERE()) + || s.att().contains(Att.SIMPLIFICATION()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/Backend.java b/kernel/src/main/java/org/kframework/compile/Backend.java index a5323023217..24b3d87aa1c 100644 --- a/kernel/src/main/java/org/kframework/compile/Backend.java +++ b/kernel/src/main/java/org/kframework/compile/Backend.java @@ -1,44 +1,44 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.List; +import java.util.Set; +import java.util.function.Function; +import javax.annotation.Nullable; import org.kframework.attributes.Att; import org.kframework.definition.Definition; import org.kframework.definition.Module; import org.kframework.definition.ModuleTransformer; import org.kframework.kompile.CompiledDefinition; -import javax.annotation.Nullable; -import java.util.List; -import java.util.Set; -import java.util.function.Function; - -/** - * Created by dwightguth on 9/1/15. - */ +/** Created by dwightguth on 9/1/15. */ public interface Backend { - class Holder { - public CompiledDefinition def; + class Holder { + public CompiledDefinition def; - public Holder(CompiledDefinition def) { - this.def = def; - } + public Holder(CompiledDefinition def) { + this.def = def; } + } - void accept(Holder def); + void accept(Holder def); - Function steps(); + Function steps(); - Function proofDefinitionNonCachedSteps(@Nullable List extraConcreteRuleLabels); + Function proofDefinitionNonCachedSteps( + @Nullable List extraConcreteRuleLabels); - Function specificationSteps(Definition def); + Function specificationSteps(Definition def); - Set excludedModuleTags(); + Set excludedModuleTags(); - default ModuleTransformer restoreDefinitionModulesTransformer(Definition kompiledDefinition) { - return ModuleTransformer.from(mod -> kompiledDefinition.getModule(mod.name()).isDefined() - ? kompiledDefinition.getModule(mod.name()).get() - : mod, - "restore definition modules to same state as in definition"); - } + default ModuleTransformer restoreDefinitionModulesTransformer(Definition kompiledDefinition) { + return ModuleTransformer.from( + mod -> + kompiledDefinition.getModule(mod.name()).isDefined() + ? kompiledDefinition.getModule(mod.name()).get() + : mod, + "restore definition modules to same state as in definition"); + } } diff --git a/kernel/src/main/java/org/kframework/compile/CloseCells.java b/kernel/src/main/java/org/kframework/compile/CloseCells.java index 0c433c5211a..fa3c21f67d6 100644 --- a/kernel/src/main/java/org/kframework/compile/CloseCells.java +++ b/kernel/src/main/java/org/kframework/compile/CloseCells.java @@ -1,7 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.definition.Context; @@ -10,281 +16,290 @@ import org.kframework.kore.*; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - /** * Remove any use of dots in cells, by replacing them with variables and appropriate connectives. * This expects parent cells to have been added by earlier passes, it will only add variables * - * The input to this pass is represents cells as described by {@link IncompleteCellUtils}. - * In the output cells no longer have dots. Leaf cells have a single argument which is - * the body, and parent cells are applied directly to the child cells and variables - * as arguments of the KApply (though not necessarily in the right order) as - * expected by {@link SortCells}. + *

The input to this pass is represents cells as described by {@link IncompleteCellUtils}. In the + * output cells no longer have dots. Leaf cells have a single argument which is the body, and parent + * cells are applied directly to the child cells and variables as arguments of the KApply (though + * not necessarily in the right order) as expected by {@link SortCells}. */ public class CloseCells { - private final ConcretizationInfo cfg; - private final SortInfo sortInfo; - private final LabelInfo labelInfo; + private final ConcretizationInfo cfg; + private final SortInfo sortInfo; + private final LabelInfo labelInfo; - public CloseCells(ConfigurationInfo cfg, SortInfo sortInfo, LabelInfo labelInfo) { - this.cfg = new ConcretizationInfo(cfg, labelInfo); - this.sortInfo = sortInfo; - this.labelInfo = labelInfo; - } + public CloseCells(ConfigurationInfo cfg, SortInfo sortInfo, LabelInfo labelInfo) { + this.cfg = new ConcretizationInfo(cfg, labelInfo); + this.sortInfo = sortInfo; + this.labelInfo = labelInfo; + } - public synchronized K close(K term) { - resetVars(); - gatherVars(term); - return transform(term); - } + public synchronized K close(K term) { + resetVars(); + gatherVars(term); + return transform(term); + } - private RuleOrClaim close(RuleOrClaim rule) { - resetVars(); - gatherVars(rule.body()); - gatherVars(rule.requires()); - gatherVars(rule.ensures()); - return rule.newInstance( - transform(rule.body()), - transform(rule.requires()), - transform(rule.ensures()), - rule.att()); - } + private RuleOrClaim close(RuleOrClaim rule) { + resetVars(); + gatherVars(rule.body()); + gatherVars(rule.requires()); + gatherVars(rule.ensures()); + return rule.newInstance( + transform(rule.body()), transform(rule.requires()), transform(rule.ensures()), rule.att()); + } - private Context close(Context context) { - resetVars(); - gatherVars(context.body()); - gatherVars(context.requires()); - return new Context( - transform(context.body()), - transform(context.requires()), - context.att()); - } + private Context close(Context context) { + resetVars(); + gatherVars(context.body()); + gatherVars(context.requires()); + return new Context(transform(context.body()), transform(context.requires()), context.att()); + } - public synchronized Sentence close(Sentence s) { - if (s instanceof RuleOrClaim) { - return close((RuleOrClaim) s); - } else if (s instanceof Context) { - return close((Context)s); - } else { - return s; - } + public synchronized Sentence close(Sentence s) { + if (s instanceof RuleOrClaim) { + return close((RuleOrClaim) s); + } else if (s instanceof Context) { + return close((Context) s); + } else { + return s; } + } - private int counter = 0; - private final Set vars = Sets.newHashSet(); - private KRewrite rhsOf = null; - - void resetVars() { - counter = 0; - vars.clear(); - rhsOf = null; - } + private int counter = 0; + private final Set vars = Sets.newHashSet(); + private KRewrite rhsOf = null; - KVariable newDotVariable(Sort s) { - KVariable newLabel; - do { - if (s == null) { - newLabel = KVariable("_DotVar" + (counter++), Att().add(Att.ANONYMOUS())); - } else { - newLabel = KVariable("_DotVar" + (counter++), Att().add(Att.ANONYMOUS()).add(Sort.class, s)); - } - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; - } + void resetVars() { + counter = 0; + vars.clear(); + rhsOf = null; + } - void gatherVars(K term) { - new VisitK() { - @Override - public void apply(KVariable v) { - vars.add(v); - } - }.apply(term); - } + KVariable newDotVariable(Sort s) { + KVariable newLabel; + do { + if (s == null) { + newLabel = KVariable("_DotVar" + (counter++), Att().add(Att.ANONYMOUS())); + } else { + newLabel = + KVariable("_DotVar" + (counter++), Att().add(Att.ANONYMOUS()).add(Sort.class, s)); + } + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } - K transform(K term) { - return new TransformK() { - @Override - public K apply(KApply k) { - return super.apply(closeCell(k)); - } + void gatherVars(K term) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + } + }.apply(term); + } - @Override - public K apply(KRewrite k) { - K l = apply(k.left()); - rhsOf = k; - K r = apply(k.right()); - rhsOf = null; - if (l != k.left() || r != k.right()) { - return KRewrite(l, r, k.att()); - } else { - return k; - } - } - }.apply(term); - } + K transform(K term) { + return new TransformK() { + @Override + public K apply(KApply k) { + return super.apply(closeCell(k)); + } - /** - * Close an individual cell. - */ - protected KApply closeCell(KApply cell) { - KLabel label = cell.klabel(); - if (!cfg.isCell(label)) { - return cell; + @Override + public K apply(KRewrite k) { + K l = apply(k.left()); + rhsOf = k; + K r = apply(k.right()); + rhsOf = null; + if (l != k.left() || r != k.right()) { + return KRewrite(l, r, k.att()); + } else { + return k; } + } + }.apply(term); + } - boolean openLeft = IncompleteCellUtils.isOpenLeft(cell); - boolean openRight = IncompleteCellUtils.isOpenRight(cell); - List contents = IncompleteCellUtils.getChildren(cell); - - if (cfg.isParentCell(label)) { - Set requiredLeft = new HashSet<>(); - Set requiredRight; - for (Sort child : cfg.getChildren(label)) { - if (cfg.getMultiplicity(child) == ConfigurationInfo.Multiplicity.ONE) { - requiredLeft.add(child); - } - } - requiredRight = new HashSet<>(requiredLeft); - for (K item : contents) { - if (item instanceof KRewrite rw) { - for (K leftItem : IncompleteCellUtils.flattenCells(rw.left())) { - filterRequired(requiredLeft, leftItem); - } - for (K rightItem : IncompleteCellUtils.flattenCells(rw.right())) { - filterRequired(requiredRight, rightItem); - } - } else { - filterRequired(requiredLeft, item); - filterRequired(requiredRight, item); - } - } + /** Close an individual cell. */ + protected KApply closeCell(KApply cell) { + KLabel label = cell.klabel(); + if (!cfg.isCell(label)) { + return cell; + } - if (!openLeft && !openRight) { - if (requiredLeft.isEmpty() && requiredRight.isEmpty()) { - return KApply(label, KList(contents)); - } else { - if (requiredLeft.equals(requiredRight)) { - throw KEMException.compilerError("Closed parent cell missing " + - "required children " + requiredLeft, cell); - } else { - throw KEMException.compilerError("Closed parent cell missing " + - "required children " + requiredLeft + " on left hand side and " + requiredRight + " on right hand side.", cell); - } - } - } + boolean openLeft = IncompleteCellUtils.isOpenLeft(cell); + boolean openRight = IncompleteCellUtils.isOpenRight(cell); + List contents = IncompleteCellUtils.getChildren(cell); - if (rhsOf == null) { - // close with variable - List newItems = new ArrayList<>(contents.size() + 1); - newItems.addAll(contents); - newItems.add(newDotVariable(null)); - return KApply(label, KList(newItems)); - } else { - // close by adding default cells - // since we know we are on the right hand side of a rewrite, we assume that - // the cell cannot contain a rewrite and therefore requiredLeft will always equal - // requiredRight. Hence we just pick one. - List newContents = new ArrayList<>(contents.size() + requiredLeft.size()); - newContents.addAll(contents); - for (Sort reqChild : requiredLeft) { - if (!cfg.cfg().isConstantInitializer(reqChild)) - throw KEMException.compilerError("Cannot close cell on right hand side because the initializer for " + reqChild.toString() + " requires configuration variables."); - newContents.add(cfg.getDefaultCell(reqChild)); - } - return (KApply(label, KList(newContents))); - } + if (cfg.isParentCell(label)) { + Set requiredLeft = new HashSet<>(); + Set requiredRight; + for (Sort child : cfg.getChildren(label)) { + if (cfg.getMultiplicity(child) == ConfigurationInfo.Multiplicity.ONE) { + requiredLeft.add(child); } - - // Is a leaf cell - if (contents.size() != 1) { - throw KEMException.criticalError("Leaf cells should contain exactly 1 body term," - + " but there are " + contents.size() + " in " + cell); + } + requiredRight = new HashSet<>(requiredLeft); + for (K item : contents) { + if (item instanceof KRewrite rw) { + for (K leftItem : IncompleteCellUtils.flattenCells(rw.left())) { + filterRequired(requiredLeft, leftItem); + } + for (K rightItem : IncompleteCellUtils.flattenCells(rw.right())) { + filterRequired(requiredRight, rightItem); + } + } else { + filterRequired(requiredLeft, item); + filterRequired(requiredRight, item); } + } - if (!openLeft && !openRight) { - return KApply(label, KList(contents.get(0))); - } - if (rhsOf != null) { - throw KEMException.criticalError("Leaf cells on right hand side of a rewrite" + - " may not be open, but " + cell + " is right of " + rhsOf.toString()); + if (!openLeft && !openRight) { + if (requiredLeft.isEmpty() && requiredRight.isEmpty()) { + return KApply(label, KList(contents)); + } else { + if (requiredLeft.equals(requiredRight)) { + throw KEMException.compilerError( + "Closed parent cell missing " + "required children " + requiredLeft, cell); + } else { + throw KEMException.compilerError( + "Closed parent cell missing " + + "required children " + + requiredLeft + + " on left hand side and " + + requiredRight + + " on right hand side.", + cell); + } } + } - K body = contents.get(0); - Sort cellType = cfg.leafCellType(label); - if (cellType.equals(Sorts.K())) { - // Need special handling to make a KSequence. - int bodyLength; - if (body instanceof KSequence) { - bodyLength = ((KSequence) body).items().size(); - } else { - bodyLength = 1; - } - List newItems = new ArrayList<>((openLeft ? 1 : 0) + bodyLength + (openRight ? 1 : 0)); - if (openLeft) { - newItems.add(newDotVariable(cellType)); - } - if (body instanceof KSequence) { - newItems.addAll(((KSequence) body).items()); - } else { - newItems.add(body); - } - if (openRight) { - newItems.add(newDotVariable(cellType)); - } - return KApply(label, KList(KSequence(newItems))); - } else { - KLabel closeOperator = sortInfo.getCloseOperator(cellType); - if (closeOperator == null) { - throw KEMException.criticalError("No operator registered for closing cells of sort " - + cellType + " when closing cell " + cell); - } - LabelInfo.AssocInfo info = labelInfo.getAssocInfo(closeOperator); - if (!info.isAssoc() && openLeft && openRight) { - throw KEMException.criticalError( - "Ambiguity closing a cell. Operator " + closeOperator - + " for sort " + cellType + " is not associative, " - + "but the cell has ellipses on both sides " + cell); - } - if (info.isComm() && (!openLeft || !openRight || info.isAssoc())) { - openLeft = false; - openRight = true; - } - KVariable leftVar = null; - if (openLeft) { - leftVar = newDotVariable(cellType); - } - if (openRight) { - body = KApply(closeOperator, KList(body, newDotVariable(cellType))); - } - if (openLeft) { - body = KApply(closeOperator, KList(leftVar, body)); - } - return KApply(label, KList(body)); + if (rhsOf == null) { + // close with variable + List newItems = new ArrayList<>(contents.size() + 1); + newItems.addAll(contents); + newItems.add(newDotVariable(null)); + return KApply(label, KList(newItems)); + } else { + // close by adding default cells + // since we know we are on the right hand side of a rewrite, we assume that + // the cell cannot contain a rewrite and therefore requiredLeft will always equal + // requiredRight. Hence we just pick one. + List newContents = new ArrayList<>(contents.size() + requiredLeft.size()); + newContents.addAll(contents); + for (Sort reqChild : requiredLeft) { + if (!cfg.cfg().isConstantInitializer(reqChild)) + throw KEMException.compilerError( + "Cannot close cell on right hand side because the initializer for " + + reqChild.toString() + + " requires configuration variables."); + newContents.add(cfg.getDefaultCell(reqChild)); } + return (KApply(label, KList(newContents))); + } + } + + // Is a leaf cell + if (contents.size() != 1) { + throw KEMException.criticalError( + "Leaf cells should contain exactly 1 body term," + + " but there are " + + contents.size() + + " in " + + cell); + } + + if (!openLeft && !openRight) { + return KApply(label, KList(contents.get(0))); + } + if (rhsOf != null) { + throw KEMException.criticalError( + "Leaf cells on right hand side of a rewrite" + + " may not be open, but " + + cell + + " is right of " + + rhsOf.toString()); } - private void filterRequired(Set required, K item) { - if (item instanceof KApply) { - required.remove(labelInfo.getCodomain(((KApply) item).klabel())); - } else if (item instanceof KVariable) { - if (item.att().contains(Sort.class)) { - Sort sort = item.att().get(Sort.class); - if (cfg.cfg().isCell(sort)) { - required.remove(sort); - } else { - required.clear(); - } - } else { - required.clear(); - } + K body = contents.get(0); + Sort cellType = cfg.leafCellType(label); + if (cellType.equals(Sorts.K())) { + // Need special handling to make a KSequence. + int bodyLength; + if (body instanceof KSequence) { + bodyLength = ((KSequence) body).items().size(); + } else { + bodyLength = 1; + } + List newItems = new ArrayList<>((openLeft ? 1 : 0) + bodyLength + (openRight ? 1 : 0)); + if (openLeft) { + newItems.add(newDotVariable(cellType)); + } + if (body instanceof KSequence) { + newItems.addAll(((KSequence) body).items()); + } else { + newItems.add(body); + } + if (openRight) { + newItems.add(newDotVariable(cellType)); + } + return KApply(label, KList(KSequence(newItems))); + } else { + KLabel closeOperator = sortInfo.getCloseOperator(cellType); + if (closeOperator == null) { + throw KEMException.criticalError( + "No operator registered for closing cells of sort " + + cellType + + " when closing cell " + + cell); + } + LabelInfo.AssocInfo info = labelInfo.getAssocInfo(closeOperator); + if (!info.isAssoc() && openLeft && openRight) { + throw KEMException.criticalError( + "Ambiguity closing a cell. Operator " + + closeOperator + + " for sort " + + cellType + + " is not associative, " + + "but the cell has ellipses on both sides " + + cell); + } + if (info.isComm() && (!openLeft || !openRight || info.isAssoc())) { + openLeft = false; + openRight = true; + } + KVariable leftVar = null; + if (openLeft) { + leftVar = newDotVariable(cellType); + } + if (openRight) { + body = KApply(closeOperator, KList(body, newDotVariable(cellType))); + } + if (openLeft) { + body = KApply(closeOperator, KList(leftVar, body)); + } + return KApply(label, KList(body)); + } + } + + private void filterRequired(Set required, K item) { + if (item instanceof KApply) { + required.remove(labelInfo.getCodomain(((KApply) item).klabel())); + } else if (item instanceof KVariable) { + if (item.att().contains(Sort.class)) { + Sort sort = item.att().get(Sort.class); + if (cfg.cfg().isCell(sort)) { + required.remove(sort); + } else { + required.clear(); } + } else { + required.clear(); + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/ComputeTransitiveFunctionDependencies.java b/kernel/src/main/java/org/kframework/compile/ComputeTransitiveFunctionDependencies.java index f11ee68875e..889eeefcdea 100644 --- a/kernel/src/main/java/org/kframework/compile/ComputeTransitiveFunctionDependencies.java +++ b/kernel/src/main/java/org/kframework/compile/ComputeTransitiveFunctionDependencies.java @@ -1,19 +1,10 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.attributes.Att; -import org.kframework.builtin.KLabels; -import org.kframework.definition.Module; -import org.kframework.definition.Rule; -import org.kframework.kore.K; -import org.kframework.kore.KLabel; -import org.kframework.kore.KApply; -import org.kframework.kore.VisitK; +import static org.kframework.Collections.*; import edu.uci.ics.jung.graph.DirectedGraph; import edu.uci.ics.jung.graph.DirectedSparseGraph; -import scala.Tuple2; - import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -21,90 +12,100 @@ import java.util.LinkedList; import java.util.Queue; import java.util.Set; - -import static org.kframework.Collections.*; +import org.kframework.attributes.Att; +import org.kframework.builtin.KLabels; +import org.kframework.definition.Module; +import org.kframework.definition.Rule; +import org.kframework.kore.K; +import org.kframework.kore.KApply; +import org.kframework.kore.KLabel; +import org.kframework.kore.VisitK; +import scala.Tuple2; public class ComputeTransitiveFunctionDependencies { - public ComputeTransitiveFunctionDependencies(Module module) { - dependencies = new DirectedSparseGraph<>(); + public ComputeTransitiveFunctionDependencies(Module module) { + dependencies = new DirectedSparseGraph<>(); - Set anywhereKLabels = new HashSet<>(); - stream(module.rules()).filter(r -> !ExpandMacros.isMacro(r)).forEach(r -> { - K left = RewriteToTop.toLeft(r.body()); - if (left instanceof KApply kapp) { + Set anywhereKLabels = new HashSet<>(); + stream(module.rules()) + .filter(r -> !ExpandMacros.isMacro(r)) + .forEach( + r -> { + K left = RewriteToTop.toLeft(r.body()); + if (left instanceof KApply kapp) { if (r.att().contains(Att.ANYWHERE())) { - if (kapp.klabel().name().equals(KLabels.INJ)) { - K k = kapp.items().get(0); - if (k instanceof KApply) { - anywhereKLabels.add(((KApply)k).klabel()); - } - } else { - anywhereKLabels.add(kapp.klabel()); + if (kapp.klabel().name().equals(KLabels.INJ)) { + K k = kapp.items().get(0); + if (k instanceof KApply) { + anywhereKLabels.add(((KApply) k).klabel()); } + } else { + anywhereKLabels.add(kapp.klabel()); + } } - } - }); + } + }); - class GetPredecessors extends VisitK { - private final KLabel current; + class GetPredecessors extends VisitK { + private final KLabel current; - private GetPredecessors(KLabel current) { - this.current = current; - } + private GetPredecessors(KLabel current) { + this.current = current; + } - @Override - public void apply(KApply k) { - if (k.klabel().name().equals(KLabels.INJ)) { - super.apply(k); - return; - } - if (module.attributesFor().getOrElse(k.klabel(), () -> Att.empty()).contains(Att.FUNCTION()) || anywhereKLabels.contains(k.klabel())) { - dependencies.addEdge(new Object(), current, k.klabel()); - } - super.apply(k); - } + @Override + public void apply(KApply k) { + if (k.klabel().name().equals(KLabels.INJ)) { + super.apply(k); + return; } - - for (Tuple2> entry : iterable(module.rulesFor())) { - for (Rule rule : iterable(entry._2())) { - if (module.attributesFor().getOrElse(entry._1(), () -> Att.empty()).contains(Att.FUNCTION())) { - GetPredecessors visitor = new GetPredecessors(entry._1()); - visitor.apply(rule.body()); - visitor.apply(rule.requires()); - } - } + if (module.attributesFor().getOrElse(k.klabel(), () -> Att.empty()).contains(Att.FUNCTION()) + || anywhereKLabels.contains(k.klabel())) { + dependencies.addEdge(new Object(), current, k.klabel()); } + super.apply(k); + } } - private static Set ancestors( - Collection startNodes, DirectedGraph graph) - { - Queue queue = new LinkedList(); - queue.addAll(startNodes); - Set visited = new LinkedHashSet(startNodes); - while(!queue.isEmpty()) - { - V v = queue.poll(); - Collection neighbors = graph.getPredecessors(v); - for (V n : neighbors) - { - if (!visited.contains(n)) - { - queue.offer(n); - visited.add(n); - } - } + for (Tuple2> entry : iterable(module.rulesFor())) { + for (Rule rule : iterable(entry._2())) { + if (module + .attributesFor() + .getOrElse(entry._1(), () -> Att.empty()) + .contains(Att.FUNCTION())) { + GetPredecessors visitor = new GetPredecessors(entry._1()); + visitor.apply(rule.body()); + visitor.apply(rule.requires()); } - return visited; + } } + } - public Set ancestors(KLabel label) { - return ancestors(Collections.singleton(label), dependencies); + private static Set ancestors( + Collection startNodes, DirectedGraph graph) { + Queue queue = new LinkedList(); + queue.addAll(startNodes); + Set visited = new LinkedHashSet(startNodes); + while (!queue.isEmpty()) { + V v = queue.poll(); + Collection neighbors = graph.getPredecessors(v); + for (V n : neighbors) { + if (!visited.contains(n)) { + queue.offer(n); + visited.add(n); + } + } } + return visited; + } - public Set ancestors(Set labels) { - return ancestors(labels, dependencies); - } + public Set ancestors(KLabel label) { + return ancestors(Collections.singleton(label), dependencies); + } + + public Set ancestors(Set labels) { + return ancestors(labels, dependencies); + } - private final DirectedGraph dependencies; + private final DirectedGraph dependencies; } diff --git a/kernel/src/main/java/org/kframework/compile/ConcretizationInfo.java b/kernel/src/main/java/org/kframework/compile/ConcretizationInfo.java index 696da3ca5c5..329efa91faf 100644 --- a/kernel/src/main/java/org/kframework/compile/ConcretizationInfo.java +++ b/kernel/src/main/java/org/kframework/compile/ConcretizationInfo.java @@ -1,6 +1,9 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.List; import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KLabel; @@ -8,93 +11,94 @@ import org.kframework.kore.Sort; import scala.Option; -import java.util.List; - -import static org.kframework.kore.KORE.*; - -/** - * Created by brandon on 3/31/15. - */ +/** Created by brandon on 3/31/15. */ public record ConcretizationInfo(ConfigurationInfo cfg, LabelInfo labels) { - public Sort getCellSort(K k) { - if (k instanceof KApply) { - return labels.getCodomain(((KApply) k).klabel()); - } else if (k instanceof KVariable) { - return k.att().get(Sort.class); - } else { - throw new AssertionError("expected KApply or KVariable, found " + k.getClass().getSimpleName()); - } - } - - public ConfigurationInfo.Multiplicity getMultiplicity(KLabel label) { - return cfg.getMultiplicity(labels.getCodomain(label)); - } - public ConfigurationInfo.Multiplicity getMultiplicity(Sort sort) { - return cfg.getMultiplicity(sort); - } - - public int getLevel(KLabel label) { - return cfg.getLevel(labels.getCodomain(label)); - } - - public KLabel getParent(KLabel klabel) { - return getParent(labels.getCodomain(klabel)); - } - - public KLabel getParent(Sort sort) { - return cfg.getCellLabel(cfg.getParent(sort)); - } - - public Sort getCellSort(KLabel cellLabel) { - Sort s = labels.getCodomain(cellLabel); - return cfg.isCell(s) ? s : null; - } - - /** If {@code label} is a label making a cell collection, return the - * Sort of the cells in that collection. - */ - public Sort getCellCollectionCell(KLabel label) { - Option result = cfg.getCellForConcat(label); - if (result.isEmpty()) { - result = cfg.getCellForUnit(label); - } - return result.isDefined() ? result.get() : null; - } - public KLabel getCellFragmentLabel(KLabel cellLabel) { - Sort s = labels.getCodomain(cellLabel); - return cfg.getCellFragmentLabel(s); - } - - public K getCellAbsentTerm(Sort cellSort) { - KLabel l = cfg.getCellAbsentLabel(cellSort); - return l == null ? null : KApply(l); - } - - public boolean isCellCollection(KLabel klabel) { - Sort s = labels.getCodomain(klabel); - return cfg.isCellCollection(s); - } - - public boolean isCell(KLabel klabel) { - Sort s = labels.getCodomain(klabel); - return cfg.isCell(s) && cfg.getCellLabel(s).equals(klabel); - } - public boolean isLeafCell(KLabel klabel) { - return cfg.isLeafCell(labels.getCodomain(klabel)); - } - public boolean isParentCell(KLabel klabel) { - return isCell(klabel) && cfg.isParentCell(labels.getCodomain(klabel)); - } - - public Sort leafCellType(KLabel label) { - return cfg.leafCellType(labels.getCodomain(label)); - } - public List getChildren(KLabel label) { - return cfg.getChildren(labels.getCodomain(label)); - } - - public K getDefaultCell(Sort sort) { - return cfg.getDefaultCell(sort); - } + public Sort getCellSort(K k) { + if (k instanceof KApply) { + return labels.getCodomain(((KApply) k).klabel()); + } else if (k instanceof KVariable) { + return k.att().get(Sort.class); + } else { + throw new AssertionError( + "expected KApply or KVariable, found " + k.getClass().getSimpleName()); + } + } + + public ConfigurationInfo.Multiplicity getMultiplicity(KLabel label) { + return cfg.getMultiplicity(labels.getCodomain(label)); + } + + public ConfigurationInfo.Multiplicity getMultiplicity(Sort sort) { + return cfg.getMultiplicity(sort); + } + + public int getLevel(KLabel label) { + return cfg.getLevel(labels.getCodomain(label)); + } + + public KLabel getParent(KLabel klabel) { + return getParent(labels.getCodomain(klabel)); + } + + public KLabel getParent(Sort sort) { + return cfg.getCellLabel(cfg.getParent(sort)); + } + + public Sort getCellSort(KLabel cellLabel) { + Sort s = labels.getCodomain(cellLabel); + return cfg.isCell(s) ? s : null; + } + + /** + * If {@code label} is a label making a cell collection, return the Sort of the cells in that + * collection. + */ + public Sort getCellCollectionCell(KLabel label) { + Option result = cfg.getCellForConcat(label); + if (result.isEmpty()) { + result = cfg.getCellForUnit(label); + } + return result.isDefined() ? result.get() : null; + } + + public KLabel getCellFragmentLabel(KLabel cellLabel) { + Sort s = labels.getCodomain(cellLabel); + return cfg.getCellFragmentLabel(s); + } + + public K getCellAbsentTerm(Sort cellSort) { + KLabel l = cfg.getCellAbsentLabel(cellSort); + return l == null ? null : KApply(l); + } + + public boolean isCellCollection(KLabel klabel) { + Sort s = labels.getCodomain(klabel); + return cfg.isCellCollection(s); + } + + public boolean isCell(KLabel klabel) { + Sort s = labels.getCodomain(klabel); + return cfg.isCell(s) && cfg.getCellLabel(s).equals(klabel); + } + + public boolean isLeafCell(KLabel klabel) { + return cfg.isLeafCell(labels.getCodomain(klabel)); + } + + public boolean isParentCell(KLabel klabel) { + return isCell(klabel) && cfg.isParentCell(labels.getCodomain(klabel)); + } + + public Sort leafCellType(KLabel label) { + return cfg.leafCellType(labels.getCodomain(label)); + } + + public List getChildren(KLabel label) { + return cfg.getChildren(labels.getCodomain(label)); + } + + public K getDefaultCell(Sort sort) { + return cfg.getDefaultCell(sort); + } } diff --git a/kernel/src/main/java/org/kframework/compile/ConcretizeCells.java b/kernel/src/main/java/org/kframework/compile/ConcretizeCells.java index 420154b3b65..a38dc4027c4 100644 --- a/kernel/src/main/java/org/kframework/compile/ConcretizeCells.java +++ b/kernel/src/main/java/org/kframework/compile/ConcretizeCells.java @@ -1,79 +1,72 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.compile.ConfigurationInfo; -import org.kframework.compile.ConfigurationInfoFromModule; -import org.kframework.compile.LabelInfo; -import org.kframework.compile.LabelInfoFromModule; import org.kframework.definition.*; import org.kframework.definition.Module; /** - * Apply the configuration concretization process. - * The implicit {@code } cell is added by another stage, AddImplicitComputationCell. - *

- * The input may freely use various configuration abstractions - * and Full K flexibilites. See {@link IncompleteCellUtils} for a - * description of the expected term structure. - * The output will represent cells in - * strict accordance with their declared fixed-arity productions. - *

- * This is a simple composition of the - * {@link AddTopCellToRules}, {@link AddParentCells}, - * {@link CloseCells}, and {@link SortCells} passes, - * see their documentation for details on the transformations. + * Apply the configuration concretization process. The implicit {@code } cell is added by another + * stage, AddImplicitComputationCell. + * + *

The input may freely use various configuration abstractions and Full K flexibilites. See + * {@link IncompleteCellUtils} for a description of the expected term structure. The output will + * represent cells in strict accordance with their declared fixed-arity productions. + * + *

This is a simple composition of the {@link AddTopCellToRules}, {@link AddParentCells}, {@link + * CloseCells}, and {@link SortCells} passes, see their documentation for details on the + * transformations. */ public class ConcretizeCells { - final ConfigurationInfo configurationInfo; - final LabelInfo labelInfo; - final SortInfo sortInfo; - final Module module; + final ConfigurationInfo configurationInfo; + final LabelInfo labelInfo; + final SortInfo sortInfo; + final Module module; - final AddParentCells addParentCells; - final CloseCells closeCells; - final SortCells sortCells; - private final AddTopCellToRules addRootCell; + final AddParentCells addParentCells; + final CloseCells closeCells; + final SortCells sortCells; + private final AddTopCellToRules addRootCell; - public static Definition transformDefinition(Definition input) { - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(input.mainModule()); - LabelInfo labelInfo = new LabelInfoFromModule(input.mainModule()); - SortInfo sortInfo = SortInfo.fromModule(input.mainModule()); - return DefinitionTransformer.fromSentenceTransformer( - new ConcretizeCells(configInfo, labelInfo, sortInfo, input.mainModule())::concretize, - "concretizing configuration" - ).apply(input); - } + public static Definition transformDefinition(Definition input) { + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(input.mainModule()); + LabelInfo labelInfo = new LabelInfoFromModule(input.mainModule()); + SortInfo sortInfo = SortInfo.fromModule(input.mainModule()); + return DefinitionTransformer.fromSentenceTransformer( + new ConcretizeCells(configInfo, labelInfo, sortInfo, input.mainModule())::concretize, + "concretizing configuration") + .apply(input); + } + public static Module transformModule(Module mod) { + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); + LabelInfo labelInfo = new LabelInfoFromModule(mod); + SortInfo sortInfo = SortInfo.fromModule(mod); + return ModuleTransformer.fromSentenceTransformer( + new ConcretizeCells(configInfo, labelInfo, sortInfo, mod)::concretize, + "concretizing configuration") + .apply(mod); + } - public static Module transformModule(Module mod) { - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); - LabelInfo labelInfo = new LabelInfoFromModule(mod); - SortInfo sortInfo = SortInfo.fromModule(mod); - return ModuleTransformer.fromSentenceTransformer( - new ConcretizeCells(configInfo, labelInfo, sortInfo, mod)::concretize, - "concretizing configuration").apply(mod); - } + public ConcretizeCells( + ConfigurationInfo configurationInfo, LabelInfo labelInfo, SortInfo sortInfo, Module module) { + this.configurationInfo = configurationInfo; + this.labelInfo = labelInfo; + this.sortInfo = sortInfo; + this.module = module; + addRootCell = new AddTopCellToRules(configurationInfo, labelInfo); + addParentCells = new AddParentCells(configurationInfo, labelInfo); + closeCells = new CloseCells(configurationInfo, sortInfo, labelInfo); + sortCells = new SortCells(configurationInfo, labelInfo, module); + } + public Sentence concretize(Module m, Sentence s) { + s = addRootCell.addImplicitCells(s, m); + s = addParentCells.concretize(s); + s = closeCells.close(s); - public ConcretizeCells(ConfigurationInfo configurationInfo, LabelInfo labelInfo, SortInfo sortInfo, Module module) { - this.configurationInfo = configurationInfo; - this.labelInfo = labelInfo; - this.sortInfo = sortInfo; - this.module = module; - addRootCell = new AddTopCellToRules(configurationInfo, labelInfo); - addParentCells = new AddParentCells(configurationInfo, labelInfo); - closeCells = new CloseCells(configurationInfo, sortInfo, labelInfo); - sortCells = new SortCells(configurationInfo, labelInfo, module); - } - - public Sentence concretize(Module m, Sentence s) { - s = addRootCell.addImplicitCells(s, m); - s = addParentCells.concretize(s); - s = closeCells.close(s); - - s = sortCells.preprocess(s); - s = sortCells.sortCells(s); - s = sortCells.postprocess(s); - return s; - } + s = sortCells.preprocess(s); + s = sortCells.sortCells(s); + s = sortCells.postprocess(s); + return s; + } } diff --git a/kernel/src/main/java/org/kframework/compile/ConstantFolding.java b/kernel/src/main/java/org/kframework/compile/ConstantFolding.java index c0efd55e332..0387eae4d08 100644 --- a/kernel/src/main/java/org/kframework/compile/ConstantFolding.java +++ b/kernel/src/main/java/org/kframework/compile/ConstantFolding.java @@ -1,6 +1,17 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.commons.lang3.StringUtils; import org.kframework.attributes.Att; import org.kframework.builtin.Hooks; @@ -11,28 +22,15 @@ import org.kframework.kore.KApply; import org.kframework.kore.KToken; import org.kframework.kore.Sort; -import org.kframework.kore.TransformK; -import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.StringUtil; import org.kframework.mpfr.BigFloat; import org.kframework.mpfr.BinaryMathContext; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.math.BigInteger; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; -import static org.kframework.definition.Constructors.*; +import org.kframework.utils.StringUtil; +import org.kframework.utils.errorsystem.KEMException; public class ConstantFolding { - private static final List hookNamespaces = Arrays.asList(Hooks.BOOL, Hooks.FLOAT, Hooks.INT, Hooks.STRING); + private static final List hookNamespaces = + Arrays.asList(Hooks.BOOL, Hooks.FLOAT, Hooks.INT, Hooks.STRING); private K loc; @@ -42,7 +40,11 @@ void setLoc(K loc) { public Sentence fold(Module module, Sentence sentence) { if (sentence instanceof Rule r) { - return Rule(fold(module, r.body(), true), fold(module, r.requires(), false), fold(module, r.ensures(), false), r.att()); + return Rule( + fold(module, r.body(), true), + fold(module, r.requires(), false), + fold(module, r.ensures(), false), + r.att()); } return sentence; } @@ -72,9 +74,19 @@ public K apply(KApply k) { } try { loc = k; - return doFolding(hook, args, module.productionsFor().apply(k.klabel().head()).head().substitute(k.klabel().params()).sort(), module); + return doFolding( + hook, + args, + module + .productionsFor() + .apply(k.klabel().head()) + .head() + .substitute(k.klabel().params()) + .sort(), + module); } catch (NoSuchMethodException e) { - throw KEMException.internalError("Missing constant-folding implementation for hook " + hook, e); + throw KEMException.internalError( + "Missing constant-folding implementation for hook " + hook, e); } } } @@ -104,42 +116,48 @@ private Object unwrap(String token, String hook) { } private K wrap(Object result, Sort sort, Module module) { - String resultHookName = module.sortAttributesFor().apply(sort.head()).getOptional(Att.HOOK()).orElse(""); - boolean hasStringHook = resultHookName.equals("STRING.String") || resultHookName.equals("BYTES.Bytes"); + String resultHookName = + module.sortAttributesFor().apply(sort.head()).getOptional(Att.HOOK()).orElse(""); + boolean hasStringHook = + resultHookName.equals("STRING.String") || resultHookName.equals("BYTES.Bytes"); if (result instanceof Boolean) { return KToken(result.toString(), sort); } else if (result instanceof FloatBuiltin) { - return KToken(((FloatBuiltin)result).value(), sort); + return KToken(((FloatBuiltin) result).value(), sort); } else if (result instanceof BigInteger) { return KToken(result.toString(), sort); } else if (result instanceof String && hasStringHook) { - return KToken(StringUtil.enquoteKString((String)result), sort); + return KToken(StringUtil.enquoteKString((String) result), sort); } else { return KToken(result.toString(), sort); } } - private K doFolding(String hook, List args, Sort resultSort, Module module) throws NoSuchMethodException { + private K doFolding(String hook, List args, Sort resultSort, Module module) + throws NoSuchMethodException { String renamedHook = hook.replace('.', '_'); List> paramTypes = new ArrayList<>(); List unwrappedArgs = new ArrayList<>(); for (K arg : args) { - KToken tok = (KToken)arg; + KToken tok = (KToken) arg; Sort sort = tok.sort(); - String argHook = module.sortAttributesFor().apply(sort.head()).getOptional(Att.HOOK()).orElse(""); + String argHook = + module.sortAttributesFor().apply(sort.head()).getOptional(Att.HOOK()).orElse(""); paramTypes.add(classOf(argHook)); unwrappedArgs.add(unwrap(tok.s(), argHook)); } try { - Method m = ConstantFolding.class.getDeclaredMethod(renamedHook, paramTypes.toArray(new Class[args.size()])); + Method m = + ConstantFolding.class.getDeclaredMethod( + renamedHook, paramTypes.toArray(new Class[args.size()])); Object result = m.invoke(this, unwrappedArgs.toArray(new Object[args.size()])); return wrap(result, resultSort, module); } catch (IllegalAccessException e) { throw KEMException.internalError("Error invoking constant folding function", e); } catch (InvocationTargetException e) { if (e.getCause() instanceof KEMException) { - throw (KEMException)e.getCause(); + throw (KEMException) e.getCause(); } else { throw KEMException.internalError("Error invoking constant folding function", e); } @@ -147,7 +165,7 @@ private K doFolding(String hook, List args, Sort resultSort, Module module) t } boolean BOOL_not(boolean a) { - return ! a; + return !a; } boolean BOOL_and(boolean a, boolean b) { @@ -171,7 +189,7 @@ boolean BOOL_orElse(boolean a, boolean b) { } boolean BOOL_implies(boolean a, boolean b) { - return ! a || b; + return !a || b; } boolean BOOL_eq(boolean a, boolean b) { @@ -193,28 +211,35 @@ BigInteger STRING_length(String a) { String STRING_chr(BigInteger a) { // unicode code points range from 0x0 to 0x10ffff if (a.compareTo(BigInteger.ZERO) < 0 || a.compareTo(BigInteger.valueOf(0x10ffff)) > 0) { - throw KEMException.compilerError("Argument to hook STRING.chr out of range. Expected a number between 0 and 1114111.", loc); + throw KEMException.compilerError( + "Argument to hook STRING.chr out of range. Expected a number between 0 and 1114111.", + loc); } - int[] codePoint = new int[] { a.intValue() }; + int[] codePoint = new int[] {a.intValue()}; return new String(codePoint, 0, 1); } BigInteger STRING_ord(String a) { if (a.codePointCount(0, a.length()) != 1) { - throw KEMException.compilerError("Argument to hook STRING.ord out of range. Expected a single character."); + throw KEMException.compilerError( + "Argument to hook STRING.ord out of range. Expected a single character."); } return BigInteger.valueOf(a.codePointAt(0)); } private void throwIfNotInt(BigInteger i, String hook) { - if (i.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 || i.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { - throw KEMException.compilerError("Argument to hook " + hook + " out of range. Expected a 32-bit signed integer.", loc); + if (i.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0 + || i.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { + throw KEMException.compilerError( + "Argument to hook " + hook + " out of range. Expected a 32-bit signed integer.", loc); } } private void throwIfNotUnsignedInt(BigInteger i, String hook) { - if (i.compareTo(BigInteger.ZERO) < 0 || i.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { - throw KEMException.compilerError("Argument to hook " + hook + " out of range. Expected a 32-bit unsigned integer.", loc); + if (i.compareTo(BigInteger.ZERO) < 0 + || i.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) { + throw KEMException.compilerError( + "Argument to hook " + hook + " out of range. Expected a 32-bit unsigned integer.", loc); } } @@ -222,9 +247,14 @@ String STRING_substr(String s, BigInteger start, BigInteger end) { throwIfNotUnsignedInt(start, "STRING.substr"); throwIfNotUnsignedInt(end, "STRING.substr"); try { - return s.substring(s.offsetByCodePoints(0, start.intValue()), s.offsetByCodePoints(0, end.intValue())); + return s.substring( + s.offsetByCodePoints(0, start.intValue()), s.offsetByCodePoints(0, end.intValue())); } catch (IndexOutOfBoundsException e) { - throw KEMException.compilerError("Argument to hook STRING.substr out of range. Expected two indices >= 0 and <= the length of the string.", e, loc); + throw KEMException.compilerError( + "Argument to hook STRING.substr out of range. Expected two indices >= 0 and <= the length" + + " of the string.", + e, + loc); } } @@ -232,10 +262,14 @@ BigInteger STRING_find(String haystack, String needle, BigInteger idx) { throwIfNotUnsignedInt(idx, "STRING.find"); try { int offset = haystack.offsetByCodePoints(0, idx.intValue()); - int foundOffset = haystack.indexOf(needle, offset); + int foundOffset = haystack.indexOf(needle, offset); return BigInteger.valueOf((foundOffset == -1 ? -1 : haystack.codePointCount(0, foundOffset))); - } catch(IndexOutOfBoundsException e) { - throw KEMException.compilerError("Argument to hook STRING.find out of range. Expected an index >= 0 and <= the length of the string to search.", e, loc); + } catch (IndexOutOfBoundsException e) { + throw KEMException.compilerError( + "Argument to hook STRING.find out of range. Expected an index >= 0 and <= the length of" + + " the string to search.", + e, + loc); } } @@ -245,8 +279,12 @@ BigInteger STRING_rfind(String haystack, String needle, BigInteger idx) { int offset = haystack.offsetByCodePoints(0, idx.intValue()); int foundOffset = haystack.lastIndexOf(needle, offset); return BigInteger.valueOf((foundOffset == -1 ? -1 : haystack.codePointCount(0, foundOffset))); - } catch(IndexOutOfBoundsException e) { - throw KEMException.compilerError("Argument to hook STRING.rfind out of range. Expected an index >= 0 and <= the length of the string to search.", e, loc); + } catch (IndexOutOfBoundsException e) { + throw KEMException.compilerError( + "Argument to hook STRING.rfind out of range. Expected an index >= 0 and <= the length of" + + " the string to search.", + e, + loc); } } @@ -256,8 +294,12 @@ BigInteger STRING_findChar(String haystack, String needles, BigInteger idx) { int offset = haystack.offsetByCodePoints(0, idx.intValue()); int foundOffset = StringUtil.indexOfAny(haystack, needles, offset); return BigInteger.valueOf((foundOffset == -1 ? -1 : haystack.codePointCount(0, foundOffset))); - } catch(IndexOutOfBoundsException e) { - throw KEMException.compilerError("Argument to hook STRING.findChar out of range. Expected an index >= 0 and <= the length of the string to search.", e, loc); + } catch (IndexOutOfBoundsException e) { + throw KEMException.compilerError( + "Argument to hook STRING.findChar out of range. Expected an index >= 0 and <= the length" + + " of the string to search.", + e, + loc); } } @@ -267,8 +309,12 @@ BigInteger STRING_rfindChar(String haystack, String needles, BigInteger idx) { int offset = haystack.offsetByCodePoints(0, idx.intValue()); int foundOffset = StringUtil.lastIndexOfAny(haystack, needles, offset); return BigInteger.valueOf((foundOffset == -1 ? -1 : haystack.codePointCount(0, foundOffset))); - } catch(IndexOutOfBoundsException e) { - throw KEMException.compilerError("Argument to hook STRING.rfindChar out of range. Expected an index >= 0 and <= the length of the string to search.", e, loc); + } catch (IndexOutOfBoundsException e) { + throw KEMException.compilerError( + "Argument to hook STRING.rfindChar out of range. Expected an index >= 0 and <= the length" + + " of the string to search.", + e, + loc); } } @@ -284,7 +330,10 @@ FloatBuiltin STRING_string2float(String s) { try { return FloatBuiltin.of(s); } catch (NumberFormatException e) { - throw KEMException.compilerError("Argument to hook STRING.string2float invalid. Expected a valid floating point nuwber.", e, loc); + throw KEMException.compilerError( + "Argument to hook STRING.string2float invalid. Expected a valid floating point nuwber.", + e, + loc); } } @@ -292,7 +341,8 @@ BigInteger STRING_string2int(String s) { try { return new BigInteger(s, 10); } catch (NumberFormatException e) { - throw KEMException.compilerError("Argument to hook STRING.string2int invalid. Expected a valid integer.", e, loc); + throw KEMException.compilerError( + "Argument to hook STRING.string2int invalid. Expected a valid integer.", e, loc); } } @@ -302,18 +352,27 @@ String STRING_int2string(BigInteger i) { BigInteger STRING_string2base(String s, BigInteger base) { if (base.compareTo(BigInteger.valueOf(2)) < 0 || base.compareTo(BigInteger.valueOf(36)) > 0) { - throw KEMException.compilerError("Argument to hook STRING.string2base out of range. Expected a number between 2 and 36.", loc); + throw KEMException.compilerError( + "Argument to hook STRING.string2base out of range. Expected a number between 2 and 36.", + loc); } try { return new BigInteger(s, base.intValue()); } catch (NumberFormatException e) { - throw KEMException.compilerError("Argument to hook STRING.string2base invalid. Expected a valid integer in base " + base.intValue() + ".", e, loc); + throw KEMException.compilerError( + "Argument to hook STRING.string2base invalid. Expected a valid integer in base " + + base.intValue() + + ".", + e, + loc); } } String STRING_base2string(BigInteger i, BigInteger base) { if (base.compareTo(BigInteger.valueOf(2)) < 0 || base.compareTo(BigInteger.valueOf(36)) > 0) { - throw KEMException.compilerError("Argument to hook STRING.string2base out of range. Expected a number between 2 and 36.", loc); + throw KEMException.compilerError( + "Argument to hook STRING.string2base out of range. Expected a number between 2 and 36.", + loc); } return i.toString(base.intValue()); } @@ -379,8 +438,12 @@ BigInteger INT_pow(BigInteger a, BigInteger b) { BigInteger INT_powmod(BigInteger a, BigInteger b, BigInteger c) { try { return a.modPow(b, c); - } catch(ArithmeticException e) { - throw KEMException.compilerError("Argument to hook INT.powmod is invalid. Modulus must be positive and negative exponents are only allowed when value and modulus are relatively prime.", e, loc); + } catch (ArithmeticException e) { + throw KEMException.compilerError( + "Argument to hook INT.powmod is invalid. Modulus must be positive and negative exponents" + + " are only allowed when value and modulus are relatively prime.", + e, + loc); } } @@ -464,7 +527,8 @@ BigInteger INT_abs(BigInteger a) { BigInteger INT_log2(BigInteger a) { if (a.compareTo(BigInteger.ZERO) <= 0) { - throw KEMException.compilerError("Argument to hook INT.log2 out of range. Expected a positive integer.", loc); + throw KEMException.compilerError( + "Argument to hook INT.log2 out of range. Expected a positive integer.", loc); } int log2 = 0; while (a.compareTo(BigInteger.ONE) > 0) { @@ -477,7 +541,12 @@ BigInteger INT_log2(BigInteger a) { BigInteger INT_bitRange(BigInteger i, BigInteger index, BigInteger length) { throwIfNotUnsignedInt(index, "INT.bitRange"); throwIfNotUnsignedInt(length, "INT.bitRange"); - return i.and(BigInteger.ONE.shiftLeft(length.intValue()).subtract(BigInteger.ONE).shiftLeft(index.intValue())).shiftRight(index.intValue()); + return i.and( + BigInteger.ONE + .shiftLeft(length.intValue()) + .subtract(BigInteger.ONE) + .shiftLeft(index.intValue())) + .shiftRight(index.intValue()); } BigInteger INT_signExtendBitRange(BigInteger i, BigInteger index, BigInteger length) { @@ -549,38 +618,45 @@ FloatBuiltin FLOAT_neg(FloatBuiltin f) { private void throwIfNotMatched(FloatBuiltin a, FloatBuiltin b, String hook) { if (!a.getMathContext().equals(b.getMathContext())) { - throw KEMException.compilerError("Arguments to hook " + hook + " do not match in exponent bits and precision.", loc); + throw KEMException.compilerError( + "Arguments to hook " + hook + " do not match in exponent bits and precision.", loc); } } FloatBuiltin FLOAT_pow(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.pow"); - return FloatBuiltin.of(a.bigFloatValue().pow(b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().pow(b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_mul(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.mul"); - return FloatBuiltin.of(a.bigFloatValue().multiply(b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().multiply(b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_div(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.div"); - return FloatBuiltin.of(a.bigFloatValue().divide(b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().divide(b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_rem(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.rem"); - return FloatBuiltin.of(a.bigFloatValue().remainder(b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().remainder(b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_add(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.add"); - return FloatBuiltin.of(a.bigFloatValue().add(b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().add(b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_sub(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.sub"); - return FloatBuiltin.of(a.bigFloatValue().subtract(b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().subtract(b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_root(FloatBuiltin a, BigInteger b) { @@ -596,17 +672,26 @@ FloatBuiltin FLOAT_round(FloatBuiltin a, BigInteger prec, BigInteger exp) { throwIfNotUnsignedInt(prec, "FLOAT.round"); throwIfNotUnsignedInt(exp, "FLOAT.round"); if (prec.intValue() < 2 || exp.intValue() < 2) { - throw KEMException.compilerError("Arguments to hook FLOAT.round are too small. Precision and exponent bits must both be at least 2.", loc); + throw KEMException.compilerError( + "Arguments to hook FLOAT.round are too small. Precision and exponent bits must both be at" + + " least 2.", + loc); } - return FloatBuiltin.of(a.bigFloatValue().round(new BinaryMathContext(prec.intValue(), exp.intValue())), exp.intValue()); + return FloatBuiltin.of( + a.bigFloatValue().round(new BinaryMathContext(prec.intValue(), exp.intValue())), + exp.intValue()); } FloatBuiltin FLOAT_floor(FloatBuiltin a) { - return FloatBuiltin.of(a.bigFloatValue().rint(a.getMathContext().withRoundingMode(RoundingMode.FLOOR)), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().rint(a.getMathContext().withRoundingMode(RoundingMode.FLOOR)), + a.exponent()); } FloatBuiltin FLOAT_ceil(FloatBuiltin a) { - return FloatBuiltin.of(a.bigFloatValue().rint(a.getMathContext().withRoundingMode(RoundingMode.CEILING)), a.exponent()); + return FloatBuiltin.of( + a.bigFloatValue().rint(a.getMathContext().withRoundingMode(RoundingMode.CEILING)), + a.exponent()); } FloatBuiltin FLOAT_exp(FloatBuiltin a) { @@ -643,24 +728,30 @@ FloatBuiltin FLOAT_atan(FloatBuiltin a) { FloatBuiltin FLOAT_atan2(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.atan2"); - return FloatBuiltin.of(BigFloat.atan2(a.bigFloatValue(), b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + BigFloat.atan2(a.bigFloatValue(), b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_max(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.max"); - return FloatBuiltin.of(BigFloat.max(a.bigFloatValue(), b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + BigFloat.max(a.bigFloatValue(), b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_min(FloatBuiltin a, FloatBuiltin b) { throwIfNotMatched(a, b, "FLOAT.min"); - return FloatBuiltin.of(BigFloat.min(a.bigFloatValue(), b.bigFloatValue(), a.getMathContext()), a.exponent()); + return FloatBuiltin.of( + BigFloat.min(a.bigFloatValue(), b.bigFloatValue(), a.getMathContext()), a.exponent()); } FloatBuiltin FLOAT_maxValue(BigInteger prec, BigInteger exp) { throwIfNotUnsignedInt(prec, "FLOAT.maxValue"); throwIfNotUnsignedInt(exp, "FLOAT.maxValue"); if (prec.intValue() < 2 || exp.intValue() < 2) { - throw KEMException.compilerError("Arguments to hook FLOAT.maxValue are too small. Precision and exponent bits must both be at least 2.", loc); + throw KEMException.compilerError( + "Arguments to hook FLOAT.maxValue are too small. Precision and exponent bits must both be" + + " at least 2.", + loc); } BinaryMathContext mc = new BinaryMathContext(prec.intValue(), exp.intValue()); return FloatBuiltin.of(BigFloat.maxValue(mc.precision, mc.maxExponent), exp.intValue()); @@ -670,7 +761,10 @@ FloatBuiltin FLOAT_minValue(BigInteger prec, BigInteger exp) { throwIfNotUnsignedInt(prec, "FLOAT.minValue"); throwIfNotUnsignedInt(exp, "FLOAT.minValue"); if (prec.intValue() < 2 || exp.intValue() < 2) { - throw KEMException.compilerError("Arguments to hook FLOAT.minValue are too small. Precision and exponent bits must both be at least 2.", loc); + throw KEMException.compilerError( + "Arguments to hook FLOAT.minValue are too small. Precision and exponent bits must both be" + + " at least 2.", + loc); } BinaryMathContext mc = new BinaryMathContext(prec.intValue(), exp.intValue()); return FloatBuiltin.of(BigFloat.minValue(mc.precision, mc.minExponent), exp.intValue()); @@ -704,7 +798,10 @@ FloatBuiltin FLOAT_int2float(BigInteger a, BigInteger prec, BigInteger exp) { throwIfNotUnsignedInt(prec, "FLOAT.int2float"); throwIfNotUnsignedInt(exp, "FLOAT.int2float"); if (prec.intValue() < 2 || exp.intValue() < 2) { - throw KEMException.compilerError("Arguments to hook FLOAT.int2float are too small. Precision and exponent bits must both be at least 2.", loc); + throw KEMException.compilerError( + "Arguments to hook FLOAT.int2float are too small. Precision and exponent bits must both" + + " be at least 2.", + loc); } BinaryMathContext mc = new BinaryMathContext(prec.intValue(), exp.intValue()); return FloatBuiltin.of(new BigFloat(a, mc), exp.intValue()); @@ -714,7 +811,8 @@ BigInteger FLOAT_float2int(FloatBuiltin a) { try { return a.bigFloatValue().rint(a.getMathContext()).toBigIntegerExact(); } catch (ArithmeticException e) { - throw KEMException.compilerError("Argument to hook FLOAT.float2int cannot be rounded to an integer.", e, loc); + throw KEMException.compilerError( + "Argument to hook FLOAT.float2int cannot be rounded to an integer.", e, loc); } } } diff --git a/kernel/src/main/java/org/kframework/compile/ConvertDataStructureToLookup.java b/kernel/src/main/java/org/kframework/compile/ConvertDataStructureToLookup.java index e07f5ec062a..cc769ec2a4d 100644 --- a/kernel/src/main/java/org/kframework/compile/ConvertDataStructureToLookup.java +++ b/kernel/src/main/java/org/kframework/compile/ConvertDataStructureToLookup.java @@ -1,9 +1,24 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.HashMultiset; import com.google.common.collect.Lists; import com.google.common.collect.Multiset; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.TopologicalSort; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; @@ -22,616 +37,668 @@ import org.kframework.kore.KVariable; import org.kframework.kore.TransformK; import org.kframework.kore.VisitK; -import org.kframework.compile.RewriteToTop; import org.kframework.utils.errorsystem.KEMException; import scala.Tuple2; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - /** - * Convert all operations involving associativity to use the standard data types - * List,Set,Map,Bag. This algorithm is currently incomplete and may not correctly - * handle all cases. However, it should be capable of handling most cases - * that were handleable in the old KIL framework, including multiplicity * cells, - * although there may be some incorrect behaviors because it has not been thoroughly - * tested and there are several known issues that will cause some patterns to behave - * incorrectly. - * In some cases it may also be more inefficient than the old framework because - * it will sometimes choose a backtracking choice operation instead of a set or map - * lookup. + * Convert all operations involving associativity to use the standard data types List,Set,Map,Bag. + * This algorithm is currently incomplete and may not correctly handle all cases. However, it should + * be capable of handling most cases that were handleable in the old KIL framework, including + * multiplicity * cells, although there may be some incorrect behaviors because it has not been + * thoroughly tested and there are several known issues that will cause some patterns to behave + * incorrectly. In some cases it may also be more inefficient than the old framework because it will + * sometimes choose a backtracking choice operation instead of a set or map lookup. * - * In addition to standard maps, a filtered map is also available. A filtered - * map is meant to be used for cases in which structural equality is too strong - * for checking key equality. - * The proposed solution internally encodes a map with entries {@code K |-> V} - * as a "filtered" map whose entries are of the form {@code FK |-> (K, V)}. - * The implementation of the standard map operations (including computing FK) - * is left to the user. For example, - * {@code $RV_MATCH/c-semantics/semantics/cpp14/language/common/map.k} - * defines a filtered map having {@code CPPType} as a key, but filtered - * through the {@code stripType} function. - * This option is selected by using {@code #filterMapChoice} as argument for - * the {@code choice} attribute. Then the {@code filterElement} attribute - * is used to specify the actual map constructor (which takes as arguments - * the filtered key and the pair), while the {@code element} attribute - * specifies the production that will be used to match or construct an - * entry in terms of an unfiltered key and the value. - * Currently for construction this production must be a function, which - * the user must define to rewrite into a filtered entry. - * The compiler translates matching using this production, so in the - * end construction and matching will be transparent to the user and - * allow syntax identical to an ordinary map. + *

In addition to standard maps, a filtered map is also available. A filtered map is meant to be + * used for cases in which structural equality is too strong for checking key equality. The proposed + * solution internally encodes a map with entries {@code K |-> V} as a "filtered" map whose entries + * are of the form {@code FK |-> (K, V)}. The implementation of the standard map operations + * (including computing FK) is left to the user. For example, {@code + * $RV_MATCH/c-semantics/semantics/cpp14/language/common/map.k} defines a filtered map having {@code + * CPPType} as a key, but filtered through the {@code stripType} function. This option is selected + * by using {@code #filterMapChoice} as argument for the {@code choice} attribute. Then the {@code + * filterElement} attribute is used to specify the actual map constructor (which takes as arguments + * the filtered key and the pair), while the {@code element} attribute specifies the production that + * will be used to match or construct an entry in terms of an unfiltered key and the value. + * Currently for construction this production must be a function, which the user must define to + * rewrite into a filtered entry. The compiler translates matching using this production, so in the + * end construction and matching will be transparent to the user and allow syntax identical to an + * ordinary map. */ public class ConvertDataStructureToLookup { - - private final Set state = new HashSet<>(); - private final Multiset vars = HashMultiset.create(); - - void reset() { - state.clear(); - vars.clear(); - counter = 0; - } - - private final Module m; - private final Map collectionFor; - private final boolean matchOnConsList; - - public ConvertDataStructureToLookup(Module m, boolean matchOnConsList) { - this.m = m; - collectionFor = collectionFor(m); - this.matchOnConsList = matchOnConsList; - } - - public ConvertDataStructureToLookup(ConvertDataStructureToLookup copy) { - this.m = copy.m; - this.collectionFor = copy.collectionFor; - this.matchOnConsList = copy.matchOnConsList; + private final Set state = new HashSet<>(); + private final Multiset vars = HashMultiset.create(); + + void reset() { + state.clear(); + vars.clear(); + counter = 0; + } + + private final Module m; + private final Map collectionFor; + private final boolean matchOnConsList; + + public ConvertDataStructureToLookup(Module m, boolean matchOnConsList) { + this.m = m; + collectionFor = collectionFor(m); + this.matchOnConsList = matchOnConsList; + } + + public ConvertDataStructureToLookup(ConvertDataStructureToLookup copy) { + this.m = copy.m; + this.collectionFor = copy.collectionFor; + this.matchOnConsList = copy.matchOnConsList; + } + + public static Map collectionFor(Module m) { + return stream(m.productions()) + .filter(p -> p.att().contains(Att.ASSOC()) && p.att().contains(Att.ELEMENT())) + .flatMap( + p -> { + Set> set = new HashSet<>(); + set.add(Tuple2.apply(p.klabel().get(), p.klabel().get())); + if (p.att().contains(Att.UNIT())) { + set.add(Tuple2.apply(KLabel(p.att().get(Att.UNIT())), p.klabel().get())); + } + if (p.att().contains(Att.ELEMENT())) { + set.add(Tuple2.apply(KLabel(p.att().get(Att.ELEMENT())), p.klabel().get())); + } + if (p.att().contains(Att.FILTER_ELEMENT())) { + set.add(Tuple2.apply(KLabel(p.att().get(Att.FILTER_ELEMENT())), p.klabel().get())); + } + if (p.att().contains(Att.WRAP_ELEMENT())) { + set.add(Tuple2.apply(KLabel(p.att().get(Att.WRAP_ELEMENT())), p.klabel().get())); + } + return set.stream(); + }) + .distinct() + .collect(Collectors.toMap(Tuple2::_1, Tuple2::_2)); + } + + public static Set filteredMapConstructors(Module m) { + return stream(m.productions()) + .filter(p -> p.att().contains(Att.ASSOC()) && p.att().contains(Att.FILTER_ELEMENT())) + .map(p -> p.klabel().get()) + .distinct() + .collect(Collectors.toSet()); + } + + private Rule convert(Rule rule) { + reset(); + gatherVars(rule.body(), vars); + gatherVars(rule.requires(), vars); + gatherVars(rule.ensures(), vars); + K body = transform(rule.body()); + return Rule(body, addSideCondition(rule.requires()), rule.ensures(), rule.att()); + } + + private Context convert(Context context) { + reset(); + gatherVars(context.body(), vars); + gatherVars(context.requires(), vars); + K body = transform(context.body()); + return new Context(body, addSideCondition(context.requires()), context.att()); + } + + /** Collects all the variables in {@code term} into {@code vars}. */ + void gatherVars(K term, Multiset vars) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + super.apply(v); + } + }.apply(term); + } + + /** + * Adds lookups to the side condition in sorted order in which they must be performed. Lookups are + * sorted based on dependencies between each other, but non-lookup operations appear in no + * particular order with respect to the lookups. + * + * @param requires Previous side condition, if any. + * @return Side condition generated by this compiler pass + previous side condition. + */ + K addSideCondition(K requires) { + Optional sideCondition = getSortedLookups().reduce(BooleanUtils::and); + if (!sideCondition.isPresent()) { + return requires; + } else if (requires.equals(BooleanUtils.TRUE) && sideCondition.isPresent()) { + return sideCondition.get(); + } else { + // we order lookups before the requires clause so that the fresh constant + // matching side condition remains last. This is necessary in order to + // ensure that fresh constants in rule RHSs are consecutive + return BooleanUtils.and(sideCondition.get(), requires); } - - public static Map collectionFor(Module m) { - return stream(m.productions()) - .filter(p -> p.att().contains(Att.ASSOC()) && p.att().contains(Att.ELEMENT())) - .flatMap(p -> { - Set> set = new HashSet<>(); - set.add(Tuple2.apply(p.klabel().get(), p.klabel().get())); - if (p.att().contains(Att.UNIT())) { - set.add(Tuple2.apply(KLabel(p.att().get(Att.UNIT())), p.klabel().get())); - } - if (p.att().contains(Att.ELEMENT())) { - set.add(Tuple2.apply(KLabel(p.att().get(Att.ELEMENT())), p.klabel().get())); - } - if (p.att().contains(Att.FILTER_ELEMENT())) { - set.add(Tuple2.apply(KLabel(p.att().get(Att.FILTER_ELEMENT())), p.klabel().get())); - } - if (p.att().contains(Att.WRAP_ELEMENT())) { - set.add(Tuple2.apply(KLabel(p.att().get(Att.WRAP_ELEMENT())), p.klabel().get())); - } - return set.stream(); - }).distinct().collect(Collectors.toMap(Tuple2::_1, Tuple2::_2)); - } - - public static Set filteredMapConstructors(Module m) { - return stream(m.productions()) - .filter(p -> p.att().contains(Att.ASSOC()) && p.att().contains(Att.FILTER_ELEMENT())) - .map(p -> p.klabel().get()) - .distinct() - .collect(Collectors.toSet()); - } - - private Rule convert(Rule rule) { - reset(); - gatherVars(rule.body(), vars); - gatherVars(rule.requires(), vars); - gatherVars(rule.ensures(), vars); - K body = transform(rule.body()); - return Rule( - body, - addSideCondition(rule.requires()), - rule.ensures(), - rule.att()); - } - - private Context convert(Context context) { - reset(); - gatherVars(context.body(), vars); - gatherVars(context.requires(), vars); - K body = transform(context.body()); - return new Context( - body, - addSideCondition(context.requires()), - context.att()); - } - - - /** - * Collects all the variables in {@code term} into {@code vars}. - */ - void gatherVars(K term, Multiset vars) { - new VisitK() { - @Override - public void apply(KVariable v) { - vars.add(v); - super.apply(v); + } + + /** + * Sorts lookups based on their dependencies with each other. Non-lookups (i.e. everything except + * #match, #setChoice, and #mapChoice) are in no particular order in this ordering, since they can + * always be inferred later to occur at the final step after all other variables are bound. + * + * @return + */ + private Stream getSortedLookups() { + List> edges = new ArrayList<>(); + for (KApply k1 : state) { + Multiset rhsVars = HashMultiset.create(); + if (k1.klabel().name().equals("Set:in")) { + continue; + } + gatherVars(k1.klist().items().get(1), rhsVars); + for (KApply k2 : state) { + Multiset lhsVars = HashMultiset.create(); + if (k2.klabel().name().equals("Set:in")) { + continue; + } + gatherVars(k2.klist().items().get(0), lhsVars); + for (KVariable var : rhsVars) { + if (lhsVars.contains(var)) { + if (k1 != k2) { + edges.add(Tuple2.apply(k2, k1)); + break; } - }.apply(term); - } - - /** - * Adds lookups to the side condition in sorted order in which they must be performed. - * Lookups are sorted based on dependencies between each other, - * but non-lookup operations appear in no particular order with respect to the lookups. - * @param requires Previous side condition, if any. - * @return Side condition generated by this compiler pass + previous side condition. - */ - K addSideCondition(K requires) { - Optional sideCondition = getSortedLookups().reduce(BooleanUtils::and); - if (!sideCondition.isPresent()) { - return requires; - } else if (requires.equals(BooleanUtils.TRUE) && sideCondition.isPresent()) { - return sideCondition.get(); - } else { - // we order lookups before the requires clause so that the fresh constant - // matching side condition remains last. This is necessary in order to - // ensure that fresh constants in rule RHSs are consecutive - return BooleanUtils.and(sideCondition.get(), requires); + } } + } } - - /** - * Sorts lookups based on their dependencies with each other. Non-lookups (i.e. - * everything except #match, #setChoice, and #mapChoice) are in no particular - * order in this ordering, since they can always be inferred later to occur - * at the final step after all other variables are bound. - * @return - */ - private Stream getSortedLookups() { - List> edges = new ArrayList<>(); - for (KApply k1 : state) { - Multiset rhsVars = HashMultiset.create(); - if (k1.klabel().name().equals("Set:in")) { - continue; + List topologicalSorted = mutable(TopologicalSort.tsort(immutable(edges)).toList()); + return state.stream() + .sorted((k1, k2) -> (topologicalSorted.indexOf(k1) - topologicalSorted.indexOf(k2))); + } + + private int counter = 0; + + KVariable newDotVariable() { + KVariable newLabel; + do { + newLabel = KVariable("_Gen" + (counter++)); + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } + + /** + * For the cell bag sorts with multiplicity *, add the single-element wrapper around individual + * cells. + */ + private K infer(K term) { + return new TransformK() { + @Override + public K apply(KApply k) { + for (KLabel collectionLabel : collectionFor.keySet()) { + Optional wrapElement = + m.attributesFor().apply(collectionLabel).getOptional(Att.WRAP_ELEMENT()); + if (wrapElement.isPresent()) { + KLabel wrappedLabel = KLabel(wrapElement.get()); + KLabel elementLabel = + KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); + if (k.klabel().equals(elementLabel)) { + return k; } - gatherVars(k1.klist().items().get(1), rhsVars); - for (KApply k2 : state) { - Multiset lhsVars = HashMultiset.create(); - if (k2.klabel().name().equals("Set:in")) { - continue; - } - gatherVars(k2.klist().items().get(0), lhsVars); - for (KVariable var : rhsVars) { - if (lhsVars.contains(var)) { - if (k1 != k2) { - edges.add(Tuple2.apply(k2, k1)); - break; - } - } - } + if (k.klabel().equals(wrappedLabel)) { + if (collectionIsMap(collectionLabel)) { + // Map + return KApply(elementLabel, super.apply(k.klist().items().get(0)), super.apply(k)); + } else { + return KApply(elementLabel, super.apply(k)); + } } + } } - List topologicalSorted = mutable(TopologicalSort.tsort(immutable(edges)).toList()); - return state.stream().sorted((k1, k2) -> (topologicalSorted.indexOf(k1) - topologicalSorted.indexOf(k2))); - } - - private int counter = 0; - KVariable newDotVariable() { - KVariable newLabel; - do { - newLabel = KVariable("_Gen" + (counter++)); - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; + return super.apply(k); + } + }.apply(term); + } + + public boolean collectionIsMap(KLabel collectionLabel) { + return m.attributesFor().apply(collectionLabel).contains(Att.COMM()) + && !m.attributesFor().apply(collectionLabel).contains(Att.IDEM()) + && !m.attributesFor().apply(collectionLabel).contains(Att.BAG()); + } + + private boolean isThread = false; + + private K transform(K body) { + if (body instanceof KRewrite + && ((KRewrite) body).left() instanceof KApply + && collectionFor.containsKey(((KApply) ((KRewrite) body).left()).klabel())) { + // this is a rule intended to implement one of the collection operations; do not transform it. + return body; } + // maintain the list of variables in the term so that we can deduce that a particular variable + // is unconstrained + Multiset varConstraints = HashMultiset.create(); + gatherVars(RewriteToTop.toLeft(body), varConstraints); + return new TransformK() { + public K apply(KApply k) { + if (KLabels.KSEQ.equals(k.klabel())) return super.apply(k); + if (k.klabel().name().equals("#Thread")) { + K global = apply(k.klist().items().get(0)); + K id = apply(k.klist().items().get(1)); + isThread = true; + K thread = apply(k.klist().items().get(2)); + isThread = false; + K otherThreads = apply(k.klist().items().get(3)); + return KApply(k.klabel(), global, id, thread, otherThreads); + } - /** - * For the cell bag sorts with multiplicity *, add the single-element wrapper around individual cells. - */ - private K infer(K term) { - return new TransformK() { - @Override - public K apply(KApply k) { - for (KLabel collectionLabel : collectionFor.keySet()) { - Optional wrapElement = m.attributesFor().apply(collectionLabel).getOptional(Att.WRAP_ELEMENT()); - if (wrapElement.isPresent()) { - KLabel wrappedLabel = KLabel(wrapElement.get()); - KLabel elementLabel = KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); - if (k.klabel().equals(elementLabel)) { - return k; - } - if (k.klabel().equals(wrappedLabel)) { - if (collectionIsMap(collectionLabel)) { - // Map - return KApply(elementLabel, super.apply(k.klist().items().get(0)), super.apply(k)); - } else { - return KApply(elementLabel, super.apply(k)); - } - } - } - } - return super.apply(k); + if (collectionFor.containsKey(k.klabel())) { + if (isThread) { + isThread = false; + K res = super.apply(k); + isThread = true; + return res; + } else { + KLabel collectionLabel = collectionFor.get(k.klabel()); + Att att = m.attributesFor().apply(collectionLabel); + // assumed assoc + KApply left = (KApply) RewriteToTop.toLeft(k); + List components = Assoc.flatten(collectionLabel, Collections.singletonList(left), m); + if (att.contains(Att.COMM())) { + if (att.contains(Att.IDEM())) { + // Set + return convertSet(k, collectionLabel, components); + } else { + if (att.contains(Att.BAG())) + // Bag + // TODO(dwightguth): handle bags + return super.apply(k); + else + // Map + return convertMap(k, collectionLabel, components, varConstraints); + } + } else { + // List + return convertList(k, collectionLabel, components); } - }.apply(term); - } - - public boolean collectionIsMap(KLabel collectionLabel) { - return m.attributesFor().apply(collectionLabel).contains(Att.COMM()) - && !m.attributesFor().apply(collectionLabel).contains(Att.IDEM()) - && !m.attributesFor().apply(collectionLabel).contains(Att.BAG()); - } - - private boolean isThread = false; - - private K transform(K body) { - if (body instanceof KRewrite && ((KRewrite) body).left() instanceof KApply && collectionFor.containsKey(((KApply) ((KRewrite) body).left()).klabel())) { - // this is a rule intended to implement one of the collection operations; do not transform it. - return body; + } + } else { + return super.apply(k); } - //maintain the list of variables in the term so that we can deduce that a particular variable is unconstrained - Multiset varConstraints = HashMultiset.create(); - gatherVars(RewriteToTop.toLeft(body), varConstraints); - return new TransformK() { - public K apply(KApply k) { - if (KLabels.KSEQ.equals(k.klabel())) - return super.apply(k); - if (k.klabel().name().equals("#Thread")) { - K global = apply(k.klist().items().get(0)); - K id = apply(k.klist().items().get(1)); - isThread = true; - K thread = apply(k.klist().items().get(2)); - isThread = false; - K otherThreads = apply(k.klist().items().get(3)); - return KApply(k.klabel(), global, id, thread, otherThreads); - } - - if (collectionFor.containsKey(k.klabel())) { - if (isThread) { - isThread = false; - K res = super.apply(k); - isThread = true; - return res; - } else { - KLabel collectionLabel = collectionFor.get(k.klabel()); - Att att = m.attributesFor().apply(collectionLabel); - //assumed assoc - KApply left = (KApply) RewriteToTop.toLeft(k); - List components = Assoc.flatten(collectionLabel, Collections.singletonList(left), m); - if (att.contains(Att.COMM())) { - if (att.contains(Att.IDEM())) { - // Set - return convertSet(k, collectionLabel, components); - } else { - if (att.contains(Att.BAG())) - // Bag - // TODO(dwightguth): handle bags - return super.apply(k); - else - // Map - return convertMap(k, collectionLabel, components, varConstraints); - } - } else { - // List - return convertList(k, collectionLabel, components); - } - } - } else { - return super.apply(k); + } + + /** + * Convert a list pattern, requiring that there is at most one list variable component. + * Individual items may appear before and after the frame variable, which can be translated + * into efficient operatations at the beginning and end of the list. + */ + private K convertList(KApply k, KLabel collectionLabel, List components) { + if (rhsOf == null) { + // left hand side + KVariable frame = null; + List elementsLeft = new ArrayList(); + List elementsRight = new ArrayList(); + KLabel elementLabel = KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); + boolean isRight = false; // true for components later than the frame variable. + // build the components of the list from the flattened KApply. + for (K component : components) { + if (component instanceof KVariable) { + if (frame != null) { + throw KEMException.internalError( + "Unsupported associative matching on List. Found variables " + + component + + " and " + + frame, + k); + } + frame = (KVariable) component; + isRight = true; + } else if (component instanceof KApply kapp) { + boolean needsWrapper = false; + if (kapp.klabel().equals(elementLabel) + || (needsWrapper = kapp.klabel().equals(getWrapElement(collectionLabel)))) { + if (kapp.klist().size() != 1 && !needsWrapper) { + throw KEMException.internalError( + "Unexpected arity of list element: " + kapp.klist().size(), kapp); } + K stack = lhsOf; + // setting lhsOf prevents inner lists from being translated to rewrites, + lhsOf = kapp; + + // overloading means the following two apply functions are actually different + // methods + (isRight ? elementsRight : elementsLeft) + .add( + needsWrapper + ? super.apply(kapp) + : super.apply(kapp.klist().items().get(0))); + + lhsOf = stack; + } else { + throw KEMException.internalError( + "Unexpected term in list, not a list element.", kapp); + } } - - /** - * Convert a list pattern, requiring that there is at most one list variable component. - * Individual items may appear before and after the frame variable, which can be - * translated into efficient operatations at the beginning and end of the list. - */ - private K convertList(KApply k, KLabel collectionLabel, List components) { - if (rhsOf == null) { - //left hand side - KVariable frame = null; - List elementsLeft = new ArrayList(); - List elementsRight = new ArrayList(); - KLabel elementLabel = KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); - boolean isRight = false; // true for components later than the frame variable. - //build the components of the list from the flattened KApply. - for (K component : components) { - if (component instanceof KVariable) { - if (frame != null) { - throw KEMException.internalError("Unsupported associative matching on List. Found variables " + component + " and " + frame, k); - } - frame = (KVariable) component; - isRight = true; - } else if (component instanceof KApply kapp) { - boolean needsWrapper = false; - if (kapp.klabel().equals(elementLabel) - || (needsWrapper = kapp.klabel().equals(getWrapElement(collectionLabel)))) { - if (kapp.klist().size() != 1 && !needsWrapper) { - throw KEMException.internalError("Unexpected arity of list element: " + kapp.klist().size(), kapp); - } - K stack = lhsOf; - // setting lhsOf prevents inner lists from being translated to rewrites, - lhsOf = kapp; - - // overloading means the following two apply functions are actually different methods - (isRight ? elementsRight : elementsLeft).add(needsWrapper ? super.apply(kapp) : super.apply(kapp.klist().items().get(0))); - - lhsOf = stack; - } else { - throw KEMException.internalError("Unexpected term in list, not a list element.", kapp); - } - } - } - K list; - if (elementsRight.size() == 0 && matchOnConsList) { - K tail; - if (frame == null) { - tail = KApply(KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT()))); - } else { - tail = frame; - } - list = Lists.reverse(elementsLeft).stream().map(e -> (K)KApply(elementLabel, e)).reduce(tail, (res, el) -> KApply(collectionLabel, el, res)); - } else { - list = newDotVariable(); - // Ctx[ListItem(5) Frame ListItem(X) ListItem(foo(Y))] => Ctx [L] - // requires Frame := range(L, 1, 2) - // andBool 5 := L[0] - // andBool X := L[-2] - // andBool foo(Y) := L[-1] - if (frame != null) { - state.add(KApply(KLabel("#match"), frame, KApply(KLabel("List:range"), list, - KToken(Integer.toString(elementsLeft.size()), Sorts.Int()), - KToken(Integer.toString(elementsRight.size()), Sorts.Int())))); - } else { - KLabel unit = KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT())); - // Ctx[.List] => Ctx[L] requires L ==K range(L, 0, 0) - state.add(KApply(KLabel("_==K_"), KApply(unit), KApply(KLabel("List:range"), list, - KToken(Integer.toString(elementsLeft.size()), Sorts.Int()), - KToken(Integer.toString(elementsRight.size()), Sorts.Int())))); - } - for (int i = 0; i < elementsLeft.size(); i++) { - K element = elementsLeft.get(i); - state.add(KApply(KLabel("#match"), element, KApply(KLabel("List:get"), list, KToken(Integer.toString(i), Sorts.Int())))); - } - for (int i = 0; i < elementsRight.size(); i++) { - K element = elementsRight.get(i); - state.add(KApply(KLabel("#match"), element, KApply(KLabel("List:get"), list, KToken(Integer.toString(i - elementsRight.size()), Sorts.Int())))); - } - } - if (lhsOf == null) { - if (!hasRewrite(k)) { - return list; - } - // An outermost list may contain nested rewrites, so the term - // is translated into a rewrite from compiled match into the original right-hand side. - return KRewrite(list, infer(RewriteToTop.toRight(k))); - } else { - return list; - } - } else { - return infer(super.apply(k)); - } + } + K list; + if (elementsRight.size() == 0 && matchOnConsList) { + K tail; + if (frame == null) { + tail = KApply(KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT()))); + } else { + tail = frame; } - - - /** - * Convert a map pattern, requiring that there is at most one map variable component. - * Map keys must either be a variable, or bound elsewhere in the rule. - * Map value patterns become additional matching constraints on lookups in the map. - */ - private K convertMap(KApply k, KLabel collectionLabel, List components, Multiset varConstraints) { - if (rhsOf == null) { - //left hand side - KVariable frame = null; - Map elements = new LinkedHashMap<>(); - //build the components of the map from the flattened KApply. - for (K component : components) { - if (component instanceof KVariable) { - if (frame != null) { - throw KEMException.internalError("Unsupported associative matching on Map. Found variables " + component + " and " + frame, k); - } - frame = (KVariable) component; - } else if (component instanceof KApply kapp) { - - boolean needsWrapper = false; - if (kapp.klabel().equals(KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT()))) - || (needsWrapper = kapp.klabel().equals(getWrapElement(collectionLabel)))) { - if (kapp.klist().size() != 2 && !needsWrapper) { - throw KEMException.internalError("Unexpected arity of map element: " + kapp.klist().size(), kapp); - } - K stack = lhsOf; - // setting lhsOf prevents inner lists from being translated to rewrites, - lhsOf = kapp; - - elements.put(super.apply(kapp.klist().items().get(0)), - needsWrapper ? super.apply(kapp) : super.apply(kapp.klist().items().get(1))); - - lhsOf = stack; - } else { - throw KEMException.internalError("Unexpected term in map, not a map element.", kapp); - } - } - } - KVariable map = newDotVariable(); - // K1,Ctx[K1 |-> K2 K3] => K1,Ctx[M] requires K3 := M[K1<-undef] andBool K1 := choice(M) andBool K2 := M[K1] - KLabel remove = KLabel(m.attributesFor().apply(collectionLabel).getOptional(Att.REMOVE()).orElse("_[_<-undef]")); - if (frame != null) { - state.add(KApply(KLabel("#match"), frame, elements.keySet().stream().reduce(map, (a1, a2) -> KApply(remove, a1, a2)))); - } else { - KLabel unit = KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT())); - state.add(KApply(KLabel("_==K_"), KApply(unit), elements.keySet().stream().reduce(map, (a1, a2) -> KApply(remove, a1, a2)))); - } - for (Map.Entry element : elements.entrySet()) { - // TODO(dwightguth): choose better between lookup and choice. - if (element.getKey() instanceof KVariable && varConstraints.count(element.getKey()) == 1) { - state.add(KApply(KLabel("#mapChoice"), element.getKey(), map)); - } - state.add(KApply(KLabel("#match"), element.getValue(), KApply(KLabel("Map:lookup"), map, element.getKey()))); - } - if (lhsOf == null) { - if (!hasRewrite(k)) { - return map; - } - // An outermost map may contain nested rewrites, so the term - // is translated into a rewrite from compiled match into the original right-hand side. - return KRewrite(map, infer(RewriteToTop.toRight(k))); - } else { - return map; - } - } else { - return infer(super.apply(k)); - } + list = + Lists.reverse(elementsLeft).stream() + .map(e -> (K) KApply(elementLabel, e)) + .reduce(tail, (res, el) -> KApply(collectionLabel, el, res)); + } else { + list = newDotVariable(); + // Ctx[ListItem(5) Frame ListItem(X) ListItem(foo(Y))] => Ctx [L] + // requires Frame := range(L, 1, 2) + // andBool 5 := L[0] + // andBool X := L[-2] + // andBool foo(Y) := L[-1] + if (frame != null) { + state.add( + KApply( + KLabel("#match"), + frame, + KApply( + KLabel("List:range"), + list, + KToken(Integer.toString(elementsLeft.size()), Sorts.Int()), + KToken(Integer.toString(elementsRight.size()), Sorts.Int())))); + } else { + KLabel unit = KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT())); + // Ctx[.List] => Ctx[L] requires L ==K range(L, 0, 0) + state.add( + KApply( + KLabel("_==K_"), + KApply(unit), + KApply( + KLabel("List:range"), + list, + KToken(Integer.toString(elementsLeft.size()), Sorts.Int()), + KToken(Integer.toString(elementsRight.size()), Sorts.Int())))); } - - private KLabel getWrapElement(KLabel collectionLabel) { - return KLabel(m.attributesFor().apply(collectionLabel).get(Att.WRAP_ELEMENT())); + for (int i = 0; i < elementsLeft.size(); i++) { + K element = elementsLeft.get(i); + state.add( + KApply( + KLabel("#match"), + element, + KApply(KLabel("List:get"), list, KToken(Integer.toString(i), Sorts.Int())))); } - - - /** - * Convert a set pattern, requiring that there is at most one set variable component. - * Set elements without variables become membership checks in the map, whereas Set elements - * with variables trigger iteration over the set with matching on each element. - */ - private K convertSet(KApply k, KLabel collectionLabel, List components) { - if (rhsOf == null) { - //left hand side - KVariable frame = null; - Set elements = new LinkedHashSet<>(); - KLabel elementLabel = KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); - //build the components of the set from the flattened KApply. - for (K component : components) { - if (component instanceof KVariable) { - if (frame != null) { - throw KEMException.internalError("Unsupported associative matching on Set. Found variables " + component + " and " + frame, k); - } - frame = (KVariable) component; - } else if (component instanceof KApply kapp) { - - boolean needsWrapper = false; - if (kapp.klabel().equals(elementLabel) - || (needsWrapper = kapp.klabel().equals(getWrapElement(collectionLabel)))) { - if (kapp.klist().size() != 1 && !needsWrapper) { - throw KEMException.internalError("Unexpected arity of set element: " + kapp.klist().size(), kapp); - } - K stack = lhsOf; - // setting lhsOf prevents inner lists from being translated to rewrites, - lhsOf = kapp; - - // overloading means the following two apply functions are actually different methods - elements.add(needsWrapper ? super.apply(kapp) : super.apply(kapp.klist().items().get(0))); - - lhsOf = stack; - } else { - throw KEMException.internalError("Unexpected term in set, not a set element.", kapp); - } - } - } - KVariable set = newDotVariable(); - K accum = set; - // Ctx[SetItem(K1) K2] => Ctx[S] requires K1 := choice(S) andBool K2 := S -Set SetItem(K1) - // Ctx[SetItem(5) SetItem(6) K] => Ctx[S] requires 5 in S andBool 6 in S andBool K := S -Set SetItem(5) SetItem(6) - for (K element : elements) { - // TODO(dwightguth): choose better between lookup and choice. - Multiset vars = HashMultiset.create(); - gatherVars(element, vars); - if (vars.isEmpty()) { - state.add(KApply(KLabel("Set:in"), element, accum)); - } else { - //set choice - state.add(KApply(KLabel("#setChoice"), element, accum)); - } - accum = KApply(KLabel("Set:difference"), accum, KApply(elementLabel, element)); - } - KLabel unit = KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT())); - if (frame != null) { - state.add(KApply(KLabel("#match"), frame, accum)); - } else { - state.add(KApply(KLabel("_==K_"), KApply(unit), accum)); - } - if (lhsOf == null) { - if (!hasRewrite(k)) { - return set; - } - // An outermost set may contain nested rewrites, so the term - // is translated into a rewrite from compiled match into the original right-hand side. - return KRewrite(set, infer(RewriteToTop.toRight(k))); - } else { - return set; - } - } else { - return infer(super.apply(k)); - } + for (int i = 0; i < elementsRight.size(); i++) { + K element = elementsRight.get(i); + state.add( + KApply( + KLabel("#match"), + element, + KApply( + KLabel("List:get"), + list, + KToken(Integer.toString(i - elementsRight.size()), Sorts.Int())))); } - - private K lhsOf; - private K rhsOf; - - @Override - public K apply(KRewrite k) { - lhsOf = k; - K l = apply(k.left()); - lhsOf = null; - rhsOf = k; - K r = apply(k.right()); - rhsOf = null; - if (l != k.left() || r != k.right()) { - return KRewrite(l, r, k.att()); - } else { - return k; + } + if (lhsOf == null) { + if (!hasRewrite(k)) { + return list; + } + // An outermost list may contain nested rewrites, so the term + // is translated into a rewrite from compiled match into the original right-hand side. + return KRewrite(list, infer(RewriteToTop.toRight(k))); + } else { + return list; + } + } else { + return infer(super.apply(k)); + } + } + + /** + * Convert a map pattern, requiring that there is at most one map variable component. Map keys + * must either be a variable, or bound elsewhere in the rule. Map value patterns become + * additional matching constraints on lookups in the map. + */ + private K convertMap( + KApply k, + KLabel collectionLabel, + List components, + Multiset varConstraints) { + if (rhsOf == null) { + // left hand side + KVariable frame = null; + Map elements = new LinkedHashMap<>(); + // build the components of the map from the flattened KApply. + for (K component : components) { + if (component instanceof KVariable) { + if (frame != null) { + throw KEMException.internalError( + "Unsupported associative matching on Map. Found variables " + + component + + " and " + + frame, + k); + } + frame = (KVariable) component; + } else if (component instanceof KApply kapp) { + + boolean needsWrapper = false; + if (kapp.klabel() + .equals(KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT()))) + || (needsWrapper = kapp.klabel().equals(getWrapElement(collectionLabel)))) { + if (kapp.klist().size() != 2 && !needsWrapper) { + throw KEMException.internalError( + "Unexpected arity of map element: " + kapp.klist().size(), kapp); } + K stack = lhsOf; + // setting lhsOf prevents inner lists from being translated to rewrites, + lhsOf = kapp; + + elements.put( + super.apply(kapp.klist().items().get(0)), + needsWrapper ? super.apply(kapp) : super.apply(kapp.klist().items().get(1))); + + lhsOf = stack; + } else { + throw KEMException.internalError( + "Unexpected term in map, not a map element.", kapp); + } } - }.apply(body); - } - - private Boolean hasRewrite(KApply k) { - return new FoldK() { - public Boolean unit() { - return false; + } + KVariable map = newDotVariable(); + // K1,Ctx[K1 |-> K2 K3] => K1,Ctx[M] requires K3 := M[K1<-undef] andBool K1 := choice(M) + // andBool K2 := M[K1] + KLabel remove = + KLabel( + m.attributesFor() + .apply(collectionLabel) + .getOptional(Att.REMOVE()) + .orElse("_[_<-undef]")); + if (frame != null) { + state.add( + KApply( + KLabel("#match"), + frame, + elements.keySet().stream().reduce(map, (a1, a2) -> KApply(remove, a1, a2)))); + } else { + KLabel unit = KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT())); + state.add( + KApply( + KLabel("_==K_"), + KApply(unit), + elements.keySet().stream().reduce(map, (a1, a2) -> KApply(remove, a1, a2)))); + } + for (Map.Entry element : elements.entrySet()) { + // TODO(dwightguth): choose better between lookup and choice. + if (element.getKey() instanceof KVariable + && varConstraints.count(element.getKey()) == 1) { + state.add(KApply(KLabel("#mapChoice"), element.getKey(), map)); } - - public Boolean merge(Boolean a, Boolean b) { - return a || b; + state.add( + KApply( + KLabel("#match"), + element.getValue(), + KApply(KLabel("Map:lookup"), map, element.getKey()))); + } + if (lhsOf == null) { + if (!hasRewrite(k)) { + return map; } - - public Boolean apply(KRewrite rew) { - return true; + // An outermost map may contain nested rewrites, so the term + // is translated into a rewrite from compiled match into the original right-hand side. + return KRewrite(map, infer(RewriteToTop.toRight(k))); + } else { + return map; + } + } else { + return infer(super.apply(k)); + } + } + + private KLabel getWrapElement(KLabel collectionLabel) { + return KLabel(m.attributesFor().apply(collectionLabel).get(Att.WRAP_ELEMENT())); + } + + /** + * Convert a set pattern, requiring that there is at most one set variable component. Set + * elements without variables become membership checks in the map, whereas Set elements with + * variables trigger iteration over the set with matching on each element. + */ + private K convertSet(KApply k, KLabel collectionLabel, List components) { + if (rhsOf == null) { + // left hand side + KVariable frame = null; + Set elements = new LinkedHashSet<>(); + KLabel elementLabel = KLabel(m.attributesFor().apply(collectionLabel).get(Att.ELEMENT())); + // build the components of the set from the flattened KApply. + for (K component : components) { + if (component instanceof KVariable) { + if (frame != null) { + throw KEMException.internalError( + "Unsupported associative matching on Set. Found variables " + + component + + " and " + + frame, + k); + } + frame = (KVariable) component; + } else if (component instanceof KApply kapp) { + + boolean needsWrapper = false; + if (kapp.klabel().equals(elementLabel) + || (needsWrapper = kapp.klabel().equals(getWrapElement(collectionLabel)))) { + if (kapp.klist().size() != 1 && !needsWrapper) { + throw KEMException.internalError( + "Unexpected arity of set element: " + kapp.klist().size(), kapp); + } + K stack = lhsOf; + // setting lhsOf prevents inner lists from being translated to rewrites, + lhsOf = kapp; + + // overloading means the following two apply functions are actually different + // methods + elements.add( + needsWrapper ? super.apply(kapp) : super.apply(kapp.klist().items().get(0))); + + lhsOf = stack; + } else { + throw KEMException.internalError( + "Unexpected term in set, not a set element.", kapp); + } } - }.apply(k); - } - - - public Sentence convert(Sentence s) { - if (s.att().contains(Att.SMT_LEMMA()) - || s.att().contains(Att.PATTERN_FOLDING())) { - return s; - } else if (s instanceof Rule) { - return convert((Rule) s); - } else if (s instanceof Context) { - return convert((Context) s); + } + KVariable set = newDotVariable(); + K accum = set; + // Ctx[SetItem(K1) K2] => Ctx[S] requires K1 := choice(S) andBool K2 := S -Set SetItem(K1) + // Ctx[SetItem(5) SetItem(6) K] => Ctx[S] requires 5 in S andBool 6 in S andBool K := S + // -Set SetItem(5) SetItem(6) + for (K element : elements) { + // TODO(dwightguth): choose better between lookup and choice. + Multiset vars = HashMultiset.create(); + gatherVars(element, vars); + if (vars.isEmpty()) { + state.add(KApply(KLabel("Set:in"), element, accum)); + } else { + // set choice + state.add(KApply(KLabel("#setChoice"), element, accum)); + } + accum = KApply(KLabel("Set:difference"), accum, KApply(elementLabel, element)); + } + KLabel unit = KLabel(m.attributesFor().apply(collectionLabel).get(Att.UNIT())); + if (frame != null) { + state.add(KApply(KLabel("#match"), frame, accum)); + } else { + state.add(KApply(KLabel("_==K_"), KApply(unit), accum)); + } + if (lhsOf == null) { + if (!hasRewrite(k)) { + return set; + } + // An outermost set may contain nested rewrites, so the term + // is translated into a rewrite from compiled match into the original right-hand side. + return KRewrite(set, infer(RewriteToTop.toRight(k))); + } else { + return set; + } } else { - return s; + return infer(super.apply(k)); } + } + + private K lhsOf; + private K rhsOf; + + @Override + public K apply(KRewrite k) { + lhsOf = k; + K l = apply(k.left()); + lhsOf = null; + rhsOf = k; + K r = apply(k.right()); + rhsOf = null; + if (l != k.left() || r != k.right()) { + return KRewrite(l, r, k.att()); + } else { + return k; + } + } + }.apply(body); + } + + private Boolean hasRewrite(KApply k) { + return new FoldK() { + public Boolean unit() { + return false; + } + + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } + + public Boolean apply(KRewrite rew) { + return true; + } + }.apply(k); + } + + public Sentence convert(Sentence s) { + if (s.att().contains(Att.SMT_LEMMA()) || s.att().contains(Att.PATTERN_FOLDING())) { + return s; + } else if (s instanceof Rule) { + return convert((Rule) s); + } else if (s instanceof Context) { + return convert((Context) s); + } else { + return s; } - - public static boolean isLookupKLabel(KLabel k) { - return k.name().equals("#match") || k.name().equals("#mapChoice") || k.name().equals("#filterMapChoice") || k.name().equals("#setChoice"); - } - - public static boolean isLookupKLabel(KApply k) { - return isLookupKLabel(k.klabel()); - } - + } + + public static boolean isLookupKLabel(KLabel k) { + return k.name().equals("#match") + || k.name().equals("#mapChoice") + || k.name().equals("#filterMapChoice") + || k.name().equals("#setChoice"); + } + + public static boolean isLookupKLabel(KApply k) { + return isLookupKLabel(k.klabel()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/DeconstructIntegerAndFloatLiterals.java b/kernel/src/main/java/org/kframework/compile/DeconstructIntegerAndFloatLiterals.java index d66152214a0..d2206735f0d 100644 --- a/kernel/src/main/java/org/kframework/compile/DeconstructIntegerAndFloatLiterals.java +++ b/kernel/src/main/java/org/kframework/compile/DeconstructIntegerAndFloatLiterals.java @@ -1,6 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.Sorts; import org.kframework.definition.Context; @@ -8,163 +14,152 @@ import org.kframework.definition.Sentence; import org.kframework.kore.*; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - /** - * Transforms patterns in the LHS of rules which have tokens of sort Int or Float - * into side conditions generating equality over a reconstructed value. - * Thus, + * Transforms patterns in the LHS of rules which have tokens of sort Int or Float into side + * conditions generating equality over a reconstructed value. Thus, * - * rule 5 => .K + *

rule 5 => .K * - * becomes + *

becomes * - * rule I:Int => .K when I ==K 5 + *

rule I:Int => .K when I ==K 5 */ public class DeconstructIntegerAndFloatLiterals { - private final Set state = new HashSet<>(); - private final Set vars = new HashSet<>(); - - void reset() { - state.clear(); - vars.clear(); + private final Set state = new HashSet<>(); + private final Set vars = new HashSet<>(); + + void reset() { + state.clear(); + vars.clear(); + } + + void gatherVars(K term) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + super.apply(v); + } + }.apply(term); + } + + public Sentence convert(Sentence s) { + if (ExpandMacros.isMacro(s)) { + return s; } - - void gatherVars(K term) { - new VisitK() { - @Override - public void apply(KVariable v) { - vars.add(v); - super.apply(v); - } - }.apply(term); + if (s instanceof Rule) { + return convert((Rule) s); + } else if (s instanceof Context) { + return convert((Context) s); + } else { + return s; } - - public Sentence convert(Sentence s) { - if (ExpandMacros.isMacro(s)) { - return s; - } - if (s instanceof Rule) { - return convert((Rule) s); - } else if (s instanceof Context) { - return convert((Context) s); - } else { - return s; - } + } + + private Rule convert(Rule rule) { + reset(); + gatherVars(rule.body()); + gatherVars(rule.requires()); + gatherVars(rule.ensures()); + K body = convert(rule.body()); + K requires = convertLookups(rule.requires()); + return Rule(body, addSideCondition(requires), rule.ensures(), rule.att()); + } + + private K convertLookups(K requires) { + return new Transformer(false).apply(requires); + } + + private Context convert(Context context) { + reset(); + gatherVars(context.body()); + gatherVars(context.requires()); + K body = convert(context.body()); + return Context(body, addSideCondition(context.requires()), context.att()); + } + + private int counter = 0; + + KVariable newDotVariable(Sort sort) { + KVariable newLabel; + do { + newLabel = KVariable("_Gen" + (counter++), Att().add(Sort.class, sort)); + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } + + K addSideCondition(K requires) { + Optional sideCondition = state.stream().reduce(BooleanUtils::and); + if (!sideCondition.isPresent()) { + return requires; + } else if (requires.equals(BooleanUtils.TRUE) && sideCondition.isPresent()) { + return sideCondition.get(); + } else { + return BooleanUtils.and(requires, sideCondition.get()); } + } - private Rule convert(Rule rule) { - reset(); - gatherVars(rule.body()); - gatherVars(rule.requires()); - gatherVars(rule.ensures()); - K body = convert(rule.body()); - K requires = convertLookups(rule.requires()); - return Rule( - body, - addSideCondition(requires), - rule.ensures(), - rule.att()); - } + private K convert(K term) { + return new Transformer(true).apply(term); + } - private K convertLookups(K requires) { - return new Transformer(false).apply(requires); - } + private class Transformer extends TransformK { - private Context convert(Context context) { - reset(); - gatherVars(context.body()); - gatherVars(context.requires()); - K body = convert(context.body()); - return Context( - body, - addSideCondition(context.requires()), - context.att()); + @Override + public K apply(KToken k) { + if (lhs) { + if (k.sort().equals(Sorts.Int()) || k.sort().equals(Sorts.Float())) { + KVariable var = newDotVariable(k.sort()); + state.add(KApply(KLabel("_==" + k.sort().name() + "_"), var, k)); + return var; + } + } + return super.apply(k); } - private int counter = 0; - KVariable newDotVariable(Sort sort) { - KVariable newLabel; - do { - newLabel = KVariable("_Gen" + (counter++), Att().add(Sort.class, sort)); - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; - } + private boolean lhs; - K addSideCondition(K requires) { - Optional sideCondition = state.stream().reduce(BooleanUtils::and); - if (!sideCondition.isPresent()) { - return requires; - } else if (requires.equals(BooleanUtils.TRUE) && sideCondition.isPresent()) { - return sideCondition.get(); - } else { - return BooleanUtils.and(requires, sideCondition.get()); - } + public Transformer(boolean lhs) { + this.lhs = lhs; } - private K convert(K term) { - return new Transformer(true).apply(term); + public boolean isLookupKLabel(KLabel k) { + return k.name().equals("#match") + || k.name().equals("#mapChoice") + || k.name().equals("#filterMapChoice") + || k.name().equals("#setChoice"); } - private class Transformer extends TransformK { - - @Override - public K apply(KToken k) { - if (lhs) { - if (k.sort().equals(Sorts.Int()) || k.sort().equals(Sorts.Float())) { - KVariable var = newDotVariable(k.sort()); - state.add(KApply(KLabel("_==" + k.sort().name() + "_"), var, k)); - return var; - } - } - return super.apply(k); - } - - private boolean lhs; - - public Transformer(boolean lhs) { - this.lhs = lhs; - } - - public boolean isLookupKLabel(KLabel k) { - return k.name().equals("#match") || k.name().equals("#mapChoice") || k.name().equals("#filterMapChoice") || k.name().equals("#setChoice"); - } - - @Override - public K apply(KApply k) { - if (isLookupKLabel(k.klabel())) { - assert k.klist().size() == 2; - K r = apply(k.klist().items().get(1)); - lhs = true; - K l = apply(k.klist().items().get(0)); - lhs = false; - if (l != k.klist().items().get(0) || r != k.klist().items().get(1)) { - return KApply(k.klabel(), l, r); - } else { - return k; - } - } - return super.apply(k); + @Override + public K apply(KApply k) { + if (isLookupKLabel(k.klabel())) { + assert k.klist().size() == 2; + K r = apply(k.klist().items().get(1)); + lhs = true; + K l = apply(k.klist().items().get(0)); + lhs = false; + if (l != k.klist().items().get(0) || r != k.klist().items().get(1)) { + return KApply(k.klabel(), l, r); + } else { + return k; } + } + return super.apply(k); + } - @Override - public K apply(KRewrite k) { - K l = apply(k.left()); - lhs = false; - K r = apply(k.right()); - lhs = true; - if (l != k.left() || r != k.right()) { - return KRewrite(l, r, k.att()); - } else { - return k; - } - } + @Override + public K apply(KRewrite k) { + K l = apply(k.left()); + lhs = false; + K r = apply(k.right()); + lhs = true; + if (l != k.left() || r != k.right()) { + return KRewrite(l, r, k.att()); + } else { + return k; + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/ExpandMacros.java b/kernel/src/main/java/org/kframework/compile/ExpandMacros.java index d860de110cf..e27a885686c 100644 --- a/kernel/src/main/java/org/kframework/compile/ExpandMacros.java +++ b/kernel/src/main/java/org/kframework/compile/ExpandMacros.java @@ -1,6 +1,26 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.io.BufferedWriter; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.backend.kore.ModuleToKORE; import org.kframework.builtin.BooleanUtils; @@ -20,7 +40,6 @@ import org.kframework.kore.KApply; import org.kframework.kore.KAs; import org.kframework.kore.KLabel; -import org.kframework.kore.KRewrite; import org.kframework.kore.KSequence; import org.kframework.kore.KToken; import org.kframework.kore.KVariable; @@ -32,380 +51,417 @@ import org.kframework.utils.file.FileUtil; import scala.Option; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; - -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; - -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; -import static org.kframework.definition.Constructors.*; - /** - * Expands all the macros in a particular module. A macro is a rule (without a side condition) - * which is tagged with the "macro" attribute. This class assumes that all such macros perform no complex - * matching on the left hand side of the rule, and generates a simple substitution and recursively applies it. + * Expands all the macros in a particular module. A macro is a rule (without a side condition) which + * is tagged with the "macro" attribute. This class assumes that all such macros perform no complex + * matching on the left hand side of the rule, and generates a simple substitution and recursively + * applies it. */ public class ExpandMacros { - private final Map> macros; - private final Map> macrosBySort; - private final Module mod; - private final boolean cover; - private final PrintWriter coverage; - private final FileChannel channel; - private final boolean reverse; - private final ResolveFunctionWithConfig transformer; - private final KompileOptions kompileOptions; - private final KExceptionManager kem; - - public static ExpandMacros fromMainModule(Module mod, FileUtil files, KExceptionManager kem, KompileOptions kompileOptions, boolean reverse) { - return new ExpandMacros(mod, files, kem, kompileOptions, reverse, true); - } - - public static ExpandMacros forNonSentences(Module mod, FileUtil files, KompileOptions kompileOptions, boolean reverse) { - return new ExpandMacros(mod, files, null, kompileOptions, reverse, false); + private final Map> macros; + private final Map> macrosBySort; + private final Module mod; + private final boolean cover; + private final PrintWriter coverage; + private final FileChannel channel; + private final boolean reverse; + private final ResolveFunctionWithConfig transformer; + private final KompileOptions kompileOptions; + private final KExceptionManager kem; + + public static ExpandMacros fromMainModule( + Module mod, + FileUtil files, + KExceptionManager kem, + KompileOptions kompileOptions, + boolean reverse) { + return new ExpandMacros(mod, files, kem, kompileOptions, reverse, true); + } + + public static ExpandMacros forNonSentences( + Module mod, FileUtil files, KompileOptions kompileOptions, boolean reverse) { + return new ExpandMacros(mod, files, null, kompileOptions, reverse, false); + } + + private ExpandMacros( + Module mod, + FileUtil files, + KExceptionManager kem, + KompileOptions kompileOptions, + boolean reverse, + boolean sentences) { + this( + sentences ? new ResolveFunctionWithConfig(mod) : null, + mod, + files, + kem, + kompileOptions, + reverse); + } + + public ExpandMacros( + ResolveFunctionWithConfig transformer, + Module mod, + FileUtil files, + KExceptionManager kem, + KompileOptions kompileOptions, + boolean reverse) { + this.mod = mod; + this.reverse = reverse; + this.cover = kompileOptions.coverage; + this.kompileOptions = kompileOptions; + this.kem = kem; + files.resolveKompiled(".").mkdirs(); + List allMacros = + stream(mod.rules()) + .filter(r -> isMacro(r.att(), reverse)) + .sorted(Comparator.comparingInt(r -> ModuleToKORE.getPriority(r.att()))) + .collect(Collectors.toList()); + macros = + allMacros.stream() + .filter(r -> getLeft(r, reverse) instanceof KApply) + .collect(Collectors.groupingBy(r -> ((KApply) getLeft(r, reverse)).klabel())); + macrosBySort = + stream(mod.allSorts()) + .collect( + Collectors.toMap( + s -> s, + s -> + allMacros.stream() + .filter( + r -> { + K left = getLeft(r, reverse); + if (left instanceof KToken || left instanceof KVariable) { + return sort(left, r).contains(s); + } else { + return false; + } + }) + .collect(Collectors.toList()))); + this.transformer = transformer; + if (cover) { + try { + FileOutputStream os = new FileOutputStream(files.resolveKompiled("coverage.txt"), true); + channel = os.getChannel(); + coverage = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os))); + } catch (IOException e) { + throw KEMException.internalError("Could not write list of rules to coverage document.", e); + } + } else { + channel = null; + coverage = null; } + } - private ExpandMacros(Module mod, FileUtil files, KExceptionManager kem, KompileOptions kompileOptions, boolean reverse, boolean sentences) { - this(sentences ? new ResolveFunctionWithConfig(mod) : null, mod, files, kem, kompileOptions, reverse); + private K getLeft(Rule r, boolean reverse) { + if (reverse) { + return RewriteToTop.toRight(r.body()); } - - public ExpandMacros(ResolveFunctionWithConfig transformer, Module mod, FileUtil files, KExceptionManager kem, KompileOptions kompileOptions, boolean reverse) { - this.mod = mod; - this.reverse = reverse; - this.cover = kompileOptions.coverage; - this.kompileOptions = kompileOptions; - this.kem = kem; - files.resolveKompiled(".").mkdirs(); - List allMacros = stream(mod.rules()).filter(r -> isMacro(r.att(), reverse)).sorted(Comparator.comparingInt(r -> ModuleToKORE.getPriority(r.att()))).collect(Collectors.toList()); - macros = allMacros.stream().filter(r -> getLeft(r, reverse) instanceof KApply).collect(Collectors.groupingBy(r -> ((KApply)getLeft(r, reverse)).klabel())); - macrosBySort = stream(mod.allSorts()).collect(Collectors.toMap(s -> s, s -> allMacros.stream().filter(r -> { - K left = getLeft(r, reverse); - if (left instanceof KToken || left instanceof KVariable) { - return sort(left, r).contains(s); - } else { - return false; - } - }).collect(Collectors.toList()))); - this.transformer = transformer; - if (cover) { - try { - FileOutputStream os = new FileOutputStream(files.resolveKompiled("coverage.txt"), true); - channel = os.getChannel(); - coverage = new PrintWriter(new BufferedWriter(new OutputStreamWriter(os))); - } catch (IOException e) { - throw KEMException.internalError("Could not write list of rules to coverage document.", e); + return RewriteToTop.toLeft(r.body()); + } + + private boolean isMacro(Att att, boolean reverse) { + return att.contains(Att.ALIAS_REC()) + || att.contains(Att.ALIAS()) + || (!reverse && (att.contains(Att.MACRO()) || att.contains(Att.MACRO_REC()))); + } + + private final Set vars = new HashSet<>(); + + void resetVars() { + vars.clear(); + } + + void gatherVars(K term) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + super.apply(v); + } + }.apply(term); + } + + private int counter = 0; + + KVariable newDotVariable(Att att) { + KVariable newLabel; + do { + newLabel = KVariable("_Gen" + (counter++), att.add(Att.ANONYMOUS())); + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } + + private RuleOrClaim expand(RuleOrClaim rule) { + resetVars(); + gatherVars(rule.body()); + gatherVars(rule.requires()); + gatherVars(rule.ensures()); + RuleOrClaim result = + rule.newInstance( + expand(rule.body()), expand(rule.requires()), expand(rule.ensures()), rule.att()); + return (RuleOrClaim) check(result); + } + + private Context expand(Context context) { + resetVars(); + gatherVars(context.body()); + gatherVars(context.requires()); + Context result = Context(expand(context.body()), expand(context.requires()), context.att()); + return (Context) check(result); + } + + private Sentence check(Sentence s) { + Set errors = new HashSet<>(); + new CheckFunctions(errors, mod).check(s); + new CheckSmtLemmas(errors, mod).check(s); + + /** + * At this point, all macros inside rules should have been expanded. However, a user could have + * accidentally left out a rule that expands the macro or incorrectly programmed this rule. If + * this is the case, rules may contain macros that have not been expanded. + */ + if (s instanceof RuleOrClaim) { + VisitK visitor = + new VisitK() { + @Override + public void apply(KApply k) { + Option atts = mod.attributesFor().get(k.klabel()); + if (atts.isDefined() + && mod.attributesFor().apply(k.klabel()).getMacro().isDefined()) { + errors.add( + KEMException.compilerError( + "Rule contains macro symbol that was not expanded", s)); + } + k.klist().items().forEach(super::apply); } - } else { - channel = null; - coverage = null; - } - } + }; - private K getLeft(Rule r, boolean reverse) { - if (reverse) { - return RewriteToTop.toRight(r.body()); - } - return RewriteToTop.toLeft(r.body()); + visitor.accept(((RuleOrClaim) s).body()); + visitor.accept(((RuleOrClaim) s).requires()); + visitor.accept(((RuleOrClaim) s).ensures()); } - private boolean isMacro(Att att, boolean reverse) { - return att.contains(Att.ALIAS_REC()) || att.contains(Att.ALIAS()) || (!reverse && (att.contains(Att.MACRO()) || att.contains(Att.MACRO_REC()))); + if (!errors.isEmpty()) { + kem.addAllKException(errors.stream().map(e -> e.exception).collect(Collectors.toList())); + throw KEMException.compilerError( + "Had " + errors.size() + " structural errors after macro expansion."); } - - private final Set vars = new HashSet<>(); - - void resetVars() { - vars.clear(); + return s; + } + + public K expand(K term) { + if (macros.size() == 0 && macrosBySort.size() == 0) return term; + FileLock lock = null; + if (cover) { + try { + lock = channel.lock(); + } catch (IOException e) { + throw KEMException.internalError("Could not lock coverage file", e); + } } + try { + K result = + new TransformK() { + private Set appliedRules = new HashSet<>(); - void gatherVars(K term) { - new VisitK() { @Override - public void apply(KVariable v) { - vars.add(v); - super.apply(v); + public K apply(KApply k) { + List rules = macros.get(k.klabel()); + return applyMacros(k, rules, super::apply); } - }.apply(term); - } - - private int counter = 0; - KVariable newDotVariable(Att att) { - KVariable newLabel; - do { - newLabel = KVariable("_Gen" + (counter++), att.add(Att.ANONYMOUS())); - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; - } - private RuleOrClaim expand(RuleOrClaim rule) { - resetVars(); - gatherVars(rule.body()); - gatherVars(rule.requires()); - gatherVars(rule.ensures()); - RuleOrClaim result = rule.newInstance(expand(rule.body()), - expand(rule.requires()), - expand(rule.ensures()), - rule.att()); - return (RuleOrClaim) check(result); - } - - private Context expand(Context context) { - resetVars(); - gatherVars(context.body()); - gatherVars(context.requires()); - Context result = Context( - expand(context.body()), - expand(context.requires()), - context.att()); - return (Context)check(result); - } - - private Sentence check(Sentence s) { - Set errors = new HashSet<>(); - new CheckFunctions(errors, mod).check(s); - new CheckSmtLemmas(errors, mod).check(s); - - /** - * At this point, all macros inside rules should have been expanded. However, a user could have accidentally - * left out a rule that expands the macro or incorrectly programmed this rule. If this is the case, rules may - * contain macros that have not been expanded. - */ - if (s instanceof RuleOrClaim){ - VisitK visitor = new VisitK() { - @Override - public void apply(KApply k) { - Option atts = mod.attributesFor().get(k.klabel()); - if (atts.isDefined() && mod.attributesFor().apply(k.klabel()).getMacro().isDefined()) { - errors.add(KEMException.compilerError("Rule contains macro symbol that was not expanded", s)); - } - k.klist().items().forEach(super::apply); + private K applyMacros(T k, List rules, Function superApply) { + if (rules == null) return superApply.apply(k); + K applied = superApply.apply(k); + for (Rule r : rules) { + if (!r.requires().equals(BooleanUtils.TRUE)) { + throw KEMException.compilerError( + "Cannot compute macros with side conditions.", r); } - }; - - visitor.accept(((RuleOrClaim) s).body()); - visitor.accept(((RuleOrClaim) s).requires()); - visitor.accept(((RuleOrClaim) s).ensures()); - } - - if (!errors.isEmpty()) { - kem.addAllKException(errors.stream().map(e -> e.exception).collect(Collectors.toList())); - throw KEMException.compilerError("Had " + errors.size() + " structural errors after macro expansion."); - } - return s; - } - - public K expand(K term) { - if (macros.size() == 0 && macrosBySort.size() == 0) - return term; - FileLock lock = null; - if (cover) { - try { - lock = channel.lock(); - } catch (IOException e) { - throw KEMException.internalError("Could not lock coverage file", e); - } - } - try { - K result = new TransformK() { - private Set appliedRules = new HashSet<>(); - - @Override - public K apply(KApply k) { - List rules = macros.get(k.klabel()); - return applyMacros(k, rules, super::apply); + K left = RewriteToTop.toLeft(r.body()); + K right = RewriteToTop.toRight(r.body()); + if (reverse) { + K tmp = left; + left = right; + right = tmp; } - - private K applyMacros(T k, List rules, Function superApply) { - if (rules == null) - return superApply.apply(k); - K applied = superApply.apply(k); - for (Rule r : rules) { - if (!r.requires().equals(BooleanUtils.TRUE)) { - throw KEMException.compilerError("Cannot compute macros with side conditions.", r); - } - K left = RewriteToTop.toLeft(r.body()); - K right = RewriteToTop.toRight(r.body()); - if (reverse) { - K tmp = left; - left = right; - right = tmp; - } - final Map subst = new HashMap<>(); - if (match(subst, left, applied, r) && (r.att().contains(Att.MACRO_REC()) || r.att().contains(Att.ALIAS_REC()) || !appliedRules.contains(r))) { - if (cover) { - if (!r.att().contains(Att.UNIQUE_ID())) System.out.println(r); - coverage.println(r.att().get(Att.UNIQUE_ID())); - } - Set oldAppliedRules = appliedRules; - appliedRules = new HashSet<>(appliedRules); - appliedRules.add(r); - K result = apply(new TransformK() { - @Override - public K apply(KVariable k) { - K result = subst.get(k); - if (result == null) { - if (k.name().equals("#Configuration")) { - return k; - } - result = newDotVariable(k.att()); - subst.put(k, result); - } - return result; + final Map subst = new HashMap<>(); + if (match(subst, left, applied, r) + && (r.att().contains(Att.MACRO_REC()) + || r.att().contains(Att.ALIAS_REC()) + || !appliedRules.contains(r))) { + if (cover) { + if (!r.att().contains(Att.UNIQUE_ID())) System.out.println(r); + coverage.println(r.att().get(Att.UNIQUE_ID())); + } + Set oldAppliedRules = appliedRules; + appliedRules = new HashSet<>(appliedRules); + appliedRules.add(r); + K result = + apply( + new TransformK() { + @Override + public K apply(KVariable k) { + K result = subst.get(k); + if (result == null) { + if (k.name().equals("#Configuration")) { + return k; } - }.apply(right)); - appliedRules = oldAppliedRules; - return result; - } - } - return applied; - } - - @Override - public K apply(KToken k) { - List rules = macrosBySort.get(k.sort()); - return applyMacros(k, rules, super::apply); + result = newDotVariable(k.att()); + subst.put(k, result); + } + return result; + } + }.apply(right)); + appliedRules = oldAppliedRules; + return result; } + } + return applied; + } - }.apply(term); - return result; - } finally { - if (cover) { - coverage.flush(); - try { - lock.close(); - } catch (IOException e) { - throw KEMException.internalError("Could not unlock coverage file", e); - } + @Override + public K apply(KToken k) { + List rules = macrosBySort.get(k.sort()); + return applyMacros(k, rules, super::apply); } + }.apply(term); + return result; + } finally { + if (cover) { + coverage.flush(); + try { + lock.close(); + } catch (IOException e) { + throw KEMException.internalError("Could not unlock coverage file", e); } + } } + } - private boolean hasPolyAtt(Production prod, int idx) { - if (prod.params().isEmpty()) { - return false; - } - for (Sort param : iterable(prod.params())) { - if (prod.sort().equals(param) && prod.nonterminals().apply(idx).sort().equals(param)) { - return true; - } - } + private boolean hasPolyAtt(Production prod, int idx) { + if (prod.params().isEmpty()) { return false; } - - - private Set sort(K k, RuleOrClaim r) { - if (k instanceof KVariable) { - return Collections.singleton(k.att().getOptional(Sort.class).orElse(null)); - } else if (k instanceof KToken) { - return Collections.singleton(((KToken)k).sort()); - } else if (k instanceof KApply kapp) { - if (kapp.klabel() instanceof KVariable) { - throw KEMException.compilerError("Cannot compute macros with klabel variables.", r); - } - Set prods = new HashSet<>(mutable(mod.productionsFor().apply(kapp.klabel()))); - prods.removeIf(p -> p.arity() != kapp.items().size()); - Set polySorts = new HashSet<>(); - for (int i = 0; i < kapp.items().size(); i++) { - final int idx = i; - Set sorts = sort(kapp.items().get(idx), r); - if (prods.stream().anyMatch(p -> hasPolyAtt(p, idx))) { - polySorts.addAll(sorts); - } - if (!sorts.contains(null)) { - prods.removeIf(p -> !hasPolyAtt(p, idx) && sorts.stream().noneMatch(s -> mod.subsorts().lessThanEq(s, p.nonterminal(idx).sort()))); - } - } - Set candidates = prods.stream().map(Production::sort).collect(Collectors.toSet()); - candidates.addAll(polySorts); - return candidates; - } else if (k instanceof KSequence) { - return Collections.singleton(Sorts.K()); - } else if (k instanceof KAs) { - return sort(((KAs)k).pattern(), r); - } else { - throw KEMException.compilerError("Cannot compute macros with sort check on terms that are not KApply, KToken, or KVariable.", r); - } + for (Sort param : iterable(prod.params())) { + if (prod.sort().equals(param) && prod.nonterminals().apply(idx).sort().equals(param)) { + return true; + } } - - private boolean match(Map subst, K pattern, K subject, RuleOrClaim r) { - if (pattern instanceof KVariable) { - if (subst.containsKey(pattern)) { - return subst.get(pattern).equals(subject); - } else { - if (pattern.att().contains(Sort.class)) { - Sort patternSort = pattern.att().get(Sort.class); - if (sort(subject, r).stream().anyMatch(s -> s == null || mod.subsorts().lessThanEq(s, patternSort))) { - subst.put((KVariable)pattern, subject); - return true; - } else { - return false; - } - } else { - subst.put((KVariable)pattern, subject); - return true; - } - } - } - if (pattern instanceof KApply p && subject instanceof KApply s) { - if (p.klabel() instanceof KVariable || s.klabel() instanceof KVariable) { - throw KEMException.compilerError("Cannot compute macros with klabel variables.", r); - } - if (!p.klabel().name().equals(s.klabel().name())) { - if (!mod.overloads().greaterThan(mod.productionsFor().apply(p.klabel()).head(), mod.productionsFor().apply(s.klabel()).head())) { - return false; - } - } - if (p.klist().size() != s.klist().size()) { - return false; - } - boolean match = true; - for (int i = 0; i < p.klist().size(); i++) { - match = match && match(subst, p.klist().items().get(i), s.klist().items().get(i), r); - } - return match; + return false; + } + + private Set sort(K k, RuleOrClaim r) { + if (k instanceof KVariable) { + return Collections.singleton(k.att().getOptional(Sort.class).orElse(null)); + } else if (k instanceof KToken) { + return Collections.singleton(((KToken) k).sort()); + } else if (k instanceof KApply kapp) { + if (kapp.klabel() instanceof KVariable) { + throw KEMException.compilerError("Cannot compute macros with klabel variables.", r); + } + Set prods = new HashSet<>(mutable(mod.productionsFor().apply(kapp.klabel()))); + prods.removeIf(p -> p.arity() != kapp.items().size()); + Set polySorts = new HashSet<>(); + for (int i = 0; i < kapp.items().size(); i++) { + final int idx = i; + Set sorts = sort(kapp.items().get(idx), r); + if (prods.stream().anyMatch(p -> hasPolyAtt(p, idx))) { + polySorts.addAll(sorts); } - if (subject instanceof KToken && pattern instanceof KToken) { - return subject.equals(pattern); + if (!sorts.contains(null)) { + prods.removeIf( + p -> + !hasPolyAtt(p, idx) + && sorts.stream() + .noneMatch(s -> mod.subsorts().lessThanEq(s, p.nonterminal(idx).sort()))); } - if (subject instanceof KVariable) { + } + Set candidates = prods.stream().map(Production::sort).collect(Collectors.toSet()); + candidates.addAll(polySorts); + return candidates; + } else if (k instanceof KSequence) { + return Collections.singleton(Sorts.K()); + } else if (k instanceof KAs) { + return sort(((KAs) k).pattern(), r); + } else { + throw KEMException.compilerError( + "Cannot compute macros with sort check on terms that are not KApply, KToken, or" + + " KVariable.", + r); + } + } + + private boolean match(Map subst, K pattern, K subject, RuleOrClaim r) { + if (pattern instanceof KVariable) { + if (subst.containsKey(pattern)) { + return subst.get(pattern).equals(subject); + } else { + if (pattern.att().contains(Sort.class)) { + Sort patternSort = pattern.att().get(Sort.class); + if (sort(subject, r).stream() + .anyMatch(s -> s == null || mod.subsorts().lessThanEq(s, patternSort))) { + subst.put((KVariable) pattern, subject); + return true; + } else { return false; + } + } else { + subst.put((KVariable) pattern, subject); + return true; } - if (subject instanceof KToken || pattern instanceof KToken) { - return false; + } + } + if (pattern instanceof KApply p && subject instanceof KApply s) { + if (p.klabel() instanceof KVariable || s.klabel() instanceof KVariable) { + throw KEMException.compilerError("Cannot compute macros with klabel variables.", r); + } + if (!p.klabel().name().equals(s.klabel().name())) { + if (!mod.overloads() + .greaterThan( + mod.productionsFor().apply(p.klabel()).head(), + mod.productionsFor().apply(s.klabel()).head())) { + return false; } - throw KEMException.compilerError("Cannot compute macros with terms that are not KApply, KToken, or KVariable.", r); + } + if (p.klist().size() != s.klist().size()) { + return false; + } + boolean match = true; + for (int i = 0; i < p.klist().size(); i++) { + match = match && match(subst, p.klist().items().get(i), s.klist().items().get(i), r); + } + return match; } - - public static boolean isMacro(HasAtt s) { - return s.isMacro(); + if (subject instanceof KToken && pattern instanceof KToken) { + return subject.equals(pattern); } - - public Sentence expand(Sentence s) { - if (s instanceof Rule && !isMacro(s)) { - return transformer.resolve(expand((Rule) s), mod); - } else if (s instanceof Claim) { - return transformer.resolve(expand((Claim) s), mod); - } else if (s instanceof Context) { - return transformer.resolve(expand((Context) s), mod); - } else { - return s; - } + if (subject instanceof KVariable) { + return false; + } + if (subject instanceof KToken || pattern instanceof KToken) { + return false; + } + throw KEMException.compilerError( + "Cannot compute macros with terms that are not KApply, KToken, or KVariable.", r); + } + + public static boolean isMacro(HasAtt s) { + return s.isMacro(); + } + + public Sentence expand(Sentence s) { + if (s instanceof Rule && !isMacro(s)) { + return transformer.resolve(expand((Rule) s), mod); + } else if (s instanceof Claim) { + return transformer.resolve(expand((Claim) s), mod); + } else if (s instanceof Context) { + return transformer.resolve(expand((Context) s), mod); + } else { + return s; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/FloatBuiltin.java b/kernel/src/main/java/org/kframework/compile/FloatBuiltin.java index 026c5b2c04c..91183c5edb9 100644 --- a/kernel/src/main/java/org/kframework/compile/FloatBuiltin.java +++ b/kernel/src/main/java/org/kframework/compile/FloatBuiltin.java @@ -1,197 +1,191 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.apache.commons.lang3.tuple.Pair; -import org.kframework.mpfr.BigFloat; -import org.kframework.mpfr.BinaryMathContext; - import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang3.tuple.Pair; +import org.kframework.mpfr.BigFloat; +import org.kframework.mpfr.BinaryMathContext; public class FloatBuiltin { - /* Token cache */ - private static final Map, FloatBuiltin> tokenCache = new HashMap<>(); - - /** - * Returns a {@link FloatBuiltin} representing the given {@link BigFloat} value - * and the given exponent range, in bits. - * - * @param value - * @return - */ - public static FloatBuiltin of(BigFloat value, Integer exponent) { - assert value != null; - Pair key = Pair.of(value, exponent); - FloatBuiltin floatBuiltin = tokenCache.get(key); - if (floatBuiltin == null) { - floatBuiltin = new FloatBuiltin(value, exponent); - tokenCache.put(key, floatBuiltin); - } - return floatBuiltin; - } - - /** - * Returns a {@link FloatBuiltin} representing the given {@link double} value. - * - * @param value - * @return - */ - public static FloatBuiltin of(double value) { - return of(new BigFloat(value, BinaryMathContext.BINARY64), BinaryMathContext.BINARY64_EXPONENT_BITS); - } - - /** - * Returns a {@link FloatBuiltin} representing the given {@link float} value. - * - * @param value - * @return - */ - public static FloatBuiltin of(float value) { - return of(new BigFloat(value, BinaryMathContext.BINARY32), BinaryMathContext.BINARY32_EXPONENT_BITS); - } - - /** - * Returns a {@link FloatBuiltin} representing the given {@link String} value. - * - * @param value - * @return - */ - public static FloatBuiltin of(String value) { - Pair pair = FloatBuiltin.parseKFloat(value); - return of(pair.getLeft(), pair.getRight()); - } - - private final BigFloat value; - private final int exponent; - - private FloatBuiltin(BigFloat value, int exponent) { - this.value = value; - this.exponent = exponent; - } - - private static final Pattern precisionAndExponent = Pattern.compile("(.*)[pP](\\d+)[xX](\\d+)"); - public static Pair parseKFloat(String s) { - try { - Matcher m = precisionAndExponent.matcher(s); - int precision, exponent; - String value; - if (m.matches()) { - precision = Integer.parseInt(m.group(2)); - exponent = Integer.parseInt(m.group(3)); - value = m.group(1); - } else if (s.endsWith("f") || s.endsWith("F")) { - precision = BinaryMathContext.BINARY32.precision; - exponent = BinaryMathContext.BINARY32_EXPONENT_BITS; - value = s.substring(0, s.length() - 1); - } else { - precision = BinaryMathContext.BINARY64.precision; - exponent = BinaryMathContext.BINARY64_EXPONENT_BITS; - if (s.endsWith("d") || s.endsWith("D")) { - value = s.substring(0, s.length() - 1); - } else { - value = s; - } - } - BinaryMathContext mc = new BinaryMathContext(precision, exponent); - BigFloat result = new BigFloat(value, mc); - return Pair.of(result, exponent); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - throw new NumberFormatException(); - } - } - - /** - * Returns a {@link BigFloat} representing the (interpreted) value of the float token. - */ - public BigFloat bigFloatValue() { - return value; - } - - public float floatValue() { - return value.floatValue(); - } - - public double doubleValue() { - return value.doubleValue(); - } - - /** - * Returns a {@link BinaryMathContext} representing the context to perform arithmetic under. - */ - public int exponent() { - return exponent; - } - - public BinaryMathContext getMathContext() { - return new BinaryMathContext(precision(), exponent()); - } - - public int precision() { - return value.precision(); - } - - /** - * Returns a {@link String} representing the (uninterpreted) value of the float token. - */ - public String value() { - return printKFloat(value) + printKFloatSuffix(value, exponent); - } - - /** - * Return a {@link String} representing the (uninterpreted) value of the numerical - * float corresponding to the value of the float token. - */ - - public static String printKFloat(BigFloat value) { - return printKFloat(value, value::toString); - } - - - public static String printKFloat(BigFloat value, Supplier toString) { - if (value.isInfinite()) { - if (value.sign()) { - return "-Infinity"; - } else { - return "Infinity"; - } - } else if (value.isNaN()) { - return "NaN"; + /* Token cache */ + private static final Map, FloatBuiltin> tokenCache = new HashMap<>(); + + /** + * Returns a {@link FloatBuiltin} representing the given {@link BigFloat} value and the given + * exponent range, in bits. + * + * @param value + * @return + */ + public static FloatBuiltin of(BigFloat value, Integer exponent) { + assert value != null; + Pair key = Pair.of(value, exponent); + FloatBuiltin floatBuiltin = tokenCache.get(key); + if (floatBuiltin == null) { + floatBuiltin = new FloatBuiltin(value, exponent); + tokenCache.put(key, floatBuiltin); + } + return floatBuiltin; + } + + /** + * Returns a {@link FloatBuiltin} representing the given {@link double} value. + * + * @param value + * @return + */ + public static FloatBuiltin of(double value) { + return of( + new BigFloat(value, BinaryMathContext.BINARY64), BinaryMathContext.BINARY64_EXPONENT_BITS); + } + + /** + * Returns a {@link FloatBuiltin} representing the given {@link float} value. + * + * @param value + * @return + */ + public static FloatBuiltin of(float value) { + return of( + new BigFloat(value, BinaryMathContext.BINARY32), BinaryMathContext.BINARY32_EXPONENT_BITS); + } + + /** + * Returns a {@link FloatBuiltin} representing the given {@link String} value. + * + * @param value + * @return + */ + public static FloatBuiltin of(String value) { + Pair pair = FloatBuiltin.parseKFloat(value); + return of(pair.getLeft(), pair.getRight()); + } + + private final BigFloat value; + private final int exponent; + + private FloatBuiltin(BigFloat value, int exponent) { + this.value = value; + this.exponent = exponent; + } + + private static final Pattern precisionAndExponent = Pattern.compile("(.*)[pP](\\d+)[xX](\\d+)"); + + public static Pair parseKFloat(String s) { + try { + Matcher m = precisionAndExponent.matcher(s); + int precision, exponent; + String value; + if (m.matches()) { + precision = Integer.parseInt(m.group(2)); + exponent = Integer.parseInt(m.group(3)); + value = m.group(1); + } else if (s.endsWith("f") || s.endsWith("F")) { + precision = BinaryMathContext.BINARY32.precision; + exponent = BinaryMathContext.BINARY32_EXPONENT_BITS; + value = s.substring(0, s.length() - 1); + } else { + precision = BinaryMathContext.BINARY64.precision; + exponent = BinaryMathContext.BINARY64_EXPONENT_BITS; + if (s.endsWith("d") || s.endsWith("D")) { + value = s.substring(0, s.length() - 1); } else { - return toString.get(); + value = s; } - } - - public static String printKFloatSuffix(BigFloat value, int exponent) { - return "p" + value.precision() + "x" + exponent; - } - - @Override - public int hashCode() { - return value.hashCode() * 31 + exponent; - } - - @Override - public boolean equals(Object object) { - if (object == null) { - return false; - } - if (!object.getClass().equals(FloatBuiltin.class)) { - return false; - } - FloatBuiltin other = (FloatBuiltin)object; - if (!value.equals(other.value)) { - return false; - } - return exponent == other.exponent; - } - - @Override - public String toString() { - return value(); - } + } + BinaryMathContext mc = new BinaryMathContext(precision, exponent); + BigFloat result = new BigFloat(value, mc); + return Pair.of(result, exponent); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + throw new NumberFormatException(); + } + } + + /** Returns a {@link BigFloat} representing the (interpreted) value of the float token. */ + public BigFloat bigFloatValue() { + return value; + } + + public float floatValue() { + return value.floatValue(); + } + + public double doubleValue() { + return value.doubleValue(); + } + + /** Returns a {@link BinaryMathContext} representing the context to perform arithmetic under. */ + public int exponent() { + return exponent; + } + + public BinaryMathContext getMathContext() { + return new BinaryMathContext(precision(), exponent()); + } + + public int precision() { + return value.precision(); + } + + /** Returns a {@link String} representing the (uninterpreted) value of the float token. */ + public String value() { + return printKFloat(value) + printKFloatSuffix(value, exponent); + } + + /** + * Return a {@link String} representing the (uninterpreted) value of the numerical float + * corresponding to the value of the float token. + */ + public static String printKFloat(BigFloat value) { + return printKFloat(value, value::toString); + } + + public static String printKFloat(BigFloat value, Supplier toString) { + if (value.isInfinite()) { + if (value.sign()) { + return "-Infinity"; + } else { + return "Infinity"; + } + } else if (value.isNaN()) { + return "NaN"; + } else { + return toString.get(); + } + } + + public static String printKFloatSuffix(BigFloat value, int exponent) { + return "p" + value.precision() + "x" + exponent; + } + + @Override + public int hashCode() { + return value.hashCode() * 31 + exponent; + } + + @Override + public boolean equals(Object object) { + if (object == null) { + return false; + } + if (!object.getClass().equals(FloatBuiltin.class)) { + return false; + } + FloatBuiltin other = (FloatBuiltin) object; + if (!value.equals(other.value)) { + return false; + } + return exponent == other.exponent; + } + + @Override + public String toString() { + return value(); + } } diff --git a/kernel/src/main/java/org/kframework/compile/GatherVarsVisitor.java b/kernel/src/main/java/org/kframework/compile/GatherVarsVisitor.java index c5c044a69e5..707c3fcd285 100644 --- a/kernel/src/main/java/org/kframework/compile/GatherVarsVisitor.java +++ b/kernel/src/main/java/org/kframework/compile/GatherVarsVisitor.java @@ -1,63 +1,61 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.Set; import org.kframework.builtin.KLabels; import org.kframework.kore.InjectedKLabel; import org.kframework.kore.KApply; import org.kframework.kore.KVariable; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - -/** - * Created by dwightguth on 3/6/17. - */ +/** Created by dwightguth on 3/6/17. */ public class GatherVarsVisitor extends RewriteAwareVisitor { - private final Set vars; - private final Set errors; - private final boolean errorExistential; - private boolean isInMLBinderLhs = false; + private final Set vars; + private final Set errors; + private final boolean errorExistential; + private boolean isInMLBinderLhs = false; - public GatherVarsVisitor(boolean isBody, Set errors, Set vars, boolean errorExistential) { - super(isBody, errors); - this.errors = errors; - this.vars = vars; - this.errorExistential = errorExistential; - } + public GatherVarsVisitor( + boolean isBody, Set errors, Set vars, boolean errorExistential) { + super(isBody, errors); + this.errors = errors; + this.vars = vars; + this.errorExistential = errorExistential; + } - @Override - public void apply(KVariable v) { - if (isLHS() && !ResolveAnonVar.isAnonVar(v)) - vars.add(v); - if (isRHS() && isInMLBinderLhs) - vars.add(v); - if (errorExistential && v.name().startsWith("?")) { - errors.add(KEMException.compilerError("Found existential variable not supported by concrete backend.", v)); - } - super.apply(v); + @Override + public void apply(KVariable v) { + if (isLHS() && !ResolveAnonVar.isAnonVar(v)) vars.add(v); + if (isRHS() && isInMLBinderLhs) vars.add(v); + if (errorExistential && v.name().startsWith("?")) { + errors.add( + KEMException.compilerError( + "Found existential variable not supported by concrete backend.", v)); } + super.apply(v); + } - @Override - public void apply(KApply k) { - if (k.klabel() instanceof KVariable) { - apply((KVariable) k.klabel()); - } - if (k.klabel().equals(KLabels.ML_EXISTS) || k.klabel().equals(KLabels.ML_FORALL)) { - boolean tmp = isInMLBinderLhs; - isInMLBinderLhs = true; - apply(k.items().get(0)); - isInMLBinderLhs = tmp; - apply(k.items().get(1)); - return; - } - super.apply(k); + @Override + public void apply(KApply k) { + if (k.klabel() instanceof KVariable) { + apply((KVariable) k.klabel()); + } + if (k.klabel().equals(KLabels.ML_EXISTS) || k.klabel().equals(KLabels.ML_FORALL)) { + boolean tmp = isInMLBinderLhs; + isInMLBinderLhs = true; + apply(k.items().get(0)); + isInMLBinderLhs = tmp; + apply(k.items().get(1)); + return; } + super.apply(k); + } - @Override - public void apply(InjectedKLabel k) { - if (k.klabel() instanceof KVariable) { - apply((KVariable) k.klabel()); - } - super.apply(k); + @Override + public void apply(InjectedKLabel k) { + if (k.klabel() instanceof KVariable) { + apply((KVariable) k.klabel()); } + super.apply(k); + } } diff --git a/kernel/src/main/java/org/kframework/compile/GenerateCoverage.java b/kernel/src/main/java/org/kframework/compile/GenerateCoverage.java index 28c601891a9..5c5c9845dfa 100644 --- a/kernel/src/main/java/org/kframework/compile/GenerateCoverage.java +++ b/kernel/src/main/java/org/kframework/compile/GenerateCoverage.java @@ -1,6 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import org.kframework.attributes.Att; import org.kframework.attributes.Source; import org.kframework.builtin.Sorts; @@ -11,33 +13,37 @@ import org.kframework.utils.StringUtil; import org.kframework.utils.file.FileUtil; -import java.io.File; - -import static org.kframework.kore.KORE.*; - public record GenerateCoverage(boolean cover, FileUtil files) { - public K gen(RuleOrClaim r, K body, Module mod) { - if (!cover || r.att().getOptional(Source.class).isEmpty()) { - return body; - } - K left = RewriteToTop.toLeft(body); - K right = RewriteToTop.toRight(body); - String id = r.att().get(Att.UNIQUE_ID()); + public K gen(RuleOrClaim r, K body, Module mod) { + if (!cover || r.att().getOptional(Source.class).isEmpty()) { + return body; + } + K left = RewriteToTop.toLeft(body); + K right = RewriteToTop.toRight(body); + String id = r.att().get(Att.UNIQUE_ID()); - if (ExpandMacros.isMacro(r)) { - //handled by macro expander - return body; - } + if (ExpandMacros.isMacro(r)) { + // handled by macro expander + return body; + } - AddSortInjections inj = new AddSortInjections(mod); + AddSortInjections inj = new AddSortInjections(mod); - Sort s = inj.topSort(body); + Sort s = inj.topSort(body); - K k = KApply(KLabel("sideEffect:" + s.toString()), KApply(KLabel("#logToFile"), - KToken(StringUtil.enquoteKString(files.resolveKompiled("coverage.txt").getAbsolutePath()), Sorts.String()), - KToken(StringUtil.enquoteKString(id + '\n'), Sorts.String())), right); + K k = + KApply( + KLabel("sideEffect:" + s.toString()), + KApply( + KLabel("#logToFile"), + KToken( + StringUtil.enquoteKString( + files.resolveKompiled("coverage.txt").getAbsolutePath()), + Sorts.String()), + KToken(StringUtil.enquoteKString(id + '\n'), Sorts.String())), + right); - return KRewrite(left, k); - } + return KRewrite(left, k); + } } diff --git a/kernel/src/main/java/org/kframework/compile/GenerateSentencesFromConfigDecl.java b/kernel/src/main/java/org/kframework/compile/GenerateSentencesFromConfigDecl.java index 8b7273f7c87..3baab924f0e 100644 --- a/kernel/src/main/java/org/kframework/compile/GenerateSentencesFromConfigDecl.java +++ b/kernel/src/main/java/org/kframework/compile/GenerateSentencesFromConfigDecl.java @@ -1,7 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Lists; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.attributes.Location; @@ -24,620 +33,812 @@ import scala.Tuple4; import scala.collection.Set; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - -/** - * Created by dwightguth on 3/27/15. - */ +/** Created by dwightguth on 3/27/15. */ public class GenerateSentencesFromConfigDecl { - /** - * Takes a configuration declaration and returns the sentences that it desugars into. - * - * Cells of multiplicity 1 desugar into an initializer production, an initializer rule, and a cell production. - * Cells of multiplicity * desugar into an initializer production, an initializer rule, a cell production, and a bag - * sort to represent a bag of those cells. - * Cells of multiplicity ? desugar into an initializer production, an initializer rule, a cell production, and an - * empty production indicating the absence of that cell. - * Cells with children additionally generate a *CellFragment sort with the same arity as the cell production, - * but the arguments made optional by generating additional sorts. - * Cells which have parents and are not multiplicity * generate a CellOpt sort which is a supersort of the cell sort - * and has an additional production name like {@code -absent}. (For a cell with multiplicitly ? this is - * necessary to distinguish a fragment that did capture the state of the cell when it wasn't present, from - * a cell fragment that didn't even try to capture the cell). - * - * Currently the implementation does not handle initializer rules; we will address this eventually. - * @param body The body of the configuration declaration. - * @param ensures The ensures clause of the configuration declaration. - * @param att The attributes of the configuration declaration. - * @param m The module the configuration declaration exists in. - * @return A set of sentences representing the configuration declaration. - */ - public static Set gen(K body, K ensures, Att att, Module m) { - return genInternal(body, ensures, att, m)._1(); - } - - /** - * Recurses over a cell and computes all the sentences corresponding to its children, and then generates - * the sentences for itself. - * @param term The term to be processed. Can be either a cell, in which case it processes that cell, - * a list of cells, in which case it processes each of those cells, or a noncell, in which case - * its parent is treated as a leaf cell. - * @param ensures The ensures clause from the configuration declaration. This is appended to the initializer of - * the top cell, but not any other cells. The algorithm assumes this will be null if and only if - * it is not the top cell of a configuration declaration. - * @param cfgAtt The attributes of the configuration declaration. Appended to all cell productions generated. - * @param m The module the configuration declaration is in. Used to get the sort of leaf cells. - * @return A tuple of the sentences generated, a list of the sorts of the children of the cell, and the body of the initializer. - */ - private static Tuple4, List, K, Boolean> genInternal(K term, K ensures, Att cfgAtt, Module m) { - if (term instanceof KApply kapp) { - if (kapp.klabel().name().equals("#configCell")) { - // is a single cell - if (kapp.klist().size() == 4) { - K startLabel = kapp.klist().items().get(0); - K endLabel = kapp.klist().items().get(3); - if (startLabel.equals(endLabel)) { - if (startLabel instanceof KToken label) { - if (label.sort().equals(Sort("#CellName"))) { - String cellName = label.s(); - Att cellProperties = getCellPropertiesAsAtt(kapp.klist().items().get(1), cellName, ensures); - Multiplicity multiplicity = convertStringMultiplicity( - cellProperties.getOption(Att.MULTIPLICITY()), term); - boolean isStream = cellProperties.getOption(Att.STREAM()).isDefined(); - - K cellContents = kapp.klist().items().get(2); - Att att = cfgAtt; - if (kapp.att().contains(Location.class)) - att = cfgAtt.add(Location.class, kapp.att().get(Location.class)); - Tuple4, List, K, Boolean> childResult = genInternal( - cellContents, null, att, m); - - boolean isLeafCell = childResult._4(); - Tuple4, Sort, K, Boolean> myResult = computeSentencesOfWellFormedCell(isLeafCell, isStream, multiplicity, att, m, cellName, cellProperties, - childResult._2(), childResult._3(), ensures, hasConfigOrRegularVariable(cellContents, m)); - return Tuple4.apply((Set)childResult._1().$bar(myResult._1()), Lists.newArrayList(myResult._2()), myResult._3(), false); - } - } - } - } - throw KEMException.compilerError("Malformed cell in configuration declaration.", term); - } else if (kapp.klabel().name().equals("#externalCell")) { - if (kapp.klist().size() == 1) { - K startLabel = kapp.klist().items().get(0); - if (startLabel instanceof KToken label) { - if (label.sort().equals(Sort("#CellName"))) { - String cellName = label.s(); - Sort sort = Sort(getSortOfCell(cellName)); - Option> initializerProduction = m.productionsFor().get(KLabel(getInitLabel(sort))); - if (initializerProduction.isDefined()) { - Set realProds = stream(initializerProduction.get()) - .filter(p -> !p.att().contains(Att.RECORD_PRD(), Production.class)) - .collect(Collections.toSet()); - if (realProds.size() == 1) { // should be only a single initializer - if (realProds.head().items().size() == 1) { - // XCell ::= "initXCell" - return Tuple4.apply(Set(), Lists.newArrayList(sort), KApply(KLabel(getInitLabel(sort))), true); - } else if (realProds.head().items().size() == 4) { - // XCell ::= "initXCell" "(" Map ")" - return Tuple4.apply(Set(), Lists.newArrayList(sort), KApply(KLabel(getInitLabel(sort)), INIT), true); - } - } - } - } - } - } - throw KEMException.compilerError("Malformed external cell in configuration declaration.", term); - } else if (KLabels.CELLS.equals(kapp.klabel())) { - //is a cell bag, and thus represents the multiple children of its parent cell - if (ensures != null) { - //top level cell, therefore, should be the children of the generatedTop cell - KToken cellLabel = KToken(KLabels.GENERATED_TOP_CELL_NAME, Sort("#CellName")); - K generatedTop = KApply(KLabel("#configCell"), cellLabel, KApply(KLabel("#cellPropertyListTerminator")), term, cellLabel); - return genInternal(generatedTop, ensures, cfgAtt, m); - } - List cells = Assoc.flatten(kapp.klabel(), kapp.klist().items(), m); - Set accumSentences = Set(); - List sorts = Lists.newArrayList(); - List initializers = Lists.newArrayList(); - for (K cell : cells) { - //for each cell, generate the child and inform the parent of the children it contains - Tuple4, List, K, Boolean> childResult = genInternal(cell, null, cfgAtt, m); - accumSentences = (Set)accumSentences.$bar(childResult._1()); - sorts.addAll(childResult._2()); - initializers.add(childResult._3()); + /** + * Takes a configuration declaration and returns the sentences that it desugars into. + * + *

Cells of multiplicity 1 desugar into an initializer production, an initializer rule, and a + * cell production. + * + *

Cells of multiplicity * desugar into an initializer production, an initializer rule, a cell + * production, and a bag sort to represent a bag of those cells. + * + *

Cells of multiplicity ? desugar into an initializer production, an initializer rule, a cell + * production, and an empty production indicating the absence of that cell. + * + *

Cells with children additionally generate a *CellFragment sort with the same arity as the + * cell production, but the arguments made optional by generating additional sorts. + * + *

Cells which have parents and are not multiplicity * generate a CellOpt sort which is a + * supersort of the cell sort and has an additional production name like {@code -absent}. + * (For a cell with multiplicitly ? this is necessary to distinguish a fragment that did capture + * the state of the cell when it wasn't present, from a cell fragment that didn't even try to + * capture the cell). + * + *

Currently the implementation does not handle initializer rules; we will address this + * eventually. + * + * @param body The body of the configuration declaration. + * @param ensures The ensures clause of the configuration declaration. + * @param att The attributes of the configuration declaration. + * @param m The module the configuration declaration exists in. + * @return A set of sentences representing the configuration declaration. + */ + public static Set gen(K body, K ensures, Att att, Module m) { + return genInternal(body, ensures, att, m)._1(); + } + + /** + * Recurses over a cell and computes all the sentences corresponding to its children, and then + * generates the sentences for itself. + * + * @param term The term to be processed. Can be either a cell, in which case it processes that + * cell, a list of cells, in which case it processes each of those cells, or a noncell, in + * which case its parent is treated as a leaf cell. + * @param ensures The ensures clause from the configuration declaration. This is appended to the + * initializer of the top cell, but not any other cells. The algorithm assumes this will be + * null if and only if it is not the top cell of a configuration declaration. + * @param cfgAtt The attributes of the configuration declaration. Appended to all cell productions + * generated. + * @param m The module the configuration declaration is in. Used to get the sort of leaf cells. + * @return A tuple of the sentences generated, a list of the sorts of the children of the cell, + * and the body of the initializer. + */ + private static Tuple4, List, K, Boolean> genInternal( + K term, K ensures, Att cfgAtt, Module m) { + if (term instanceof KApply kapp) { + if (kapp.klabel().name().equals("#configCell")) { + // is a single cell + if (kapp.klist().size() == 4) { + K startLabel = kapp.klist().items().get(0); + K endLabel = kapp.klist().items().get(3); + if (startLabel.equals(endLabel)) { + if (startLabel instanceof KToken label) { + if (label.sort().equals(Sort("#CellName"))) { + String cellName = label.s(); + Att cellProperties = + getCellPropertiesAsAtt(kapp.klist().items().get(1), cellName, ensures); + Multiplicity multiplicity = + convertStringMultiplicity(cellProperties.getOption(Att.MULTIPLICITY()), term); + boolean isStream = cellProperties.getOption(Att.STREAM()).isDefined(); + + K cellContents = kapp.klist().items().get(2); + Att att = cfgAtt; + if (kapp.att().contains(Location.class)) + att = cfgAtt.add(Location.class, kapp.att().get(Location.class)); + Tuple4, List, K, Boolean> childResult = + genInternal(cellContents, null, att, m); + + boolean isLeafCell = childResult._4(); + Tuple4, Sort, K, Boolean> myResult = + computeSentencesOfWellFormedCell( + isLeafCell, + isStream, + multiplicity, + att, + m, + cellName, + cellProperties, + childResult._2(), + childResult._3(), + ensures, + hasConfigOrRegularVariable(cellContents, m)); + return Tuple4.apply( + (Set) childResult._1().$bar(myResult._1()), + Lists.newArrayList(myResult._2()), + myResult._3(), + false); + } + } + } + } + throw KEMException.compilerError("Malformed cell in configuration declaration.", term); + } else if (kapp.klabel().name().equals("#externalCell")) { + if (kapp.klist().size() == 1) { + K startLabel = kapp.klist().items().get(0); + if (startLabel instanceof KToken label) { + if (label.sort().equals(Sort("#CellName"))) { + String cellName = label.s(); + Sort sort = Sort(getSortOfCell(cellName)); + Option> initializerProduction = + m.productionsFor().get(KLabel(getInitLabel(sort))); + if (initializerProduction.isDefined()) { + Set realProds = + stream(initializerProduction.get()) + .filter(p -> !p.att().contains(Att.RECORD_PRD(), Production.class)) + .collect(Collections.toSet()); + if (realProds.size() == 1) { // should be only a single initializer + if (realProds.head().items().size() == 1) { + // XCell ::= "initXCell" + return Tuple4.apply( + Set(), Lists.newArrayList(sort), KApply(KLabel(getInitLabel(sort))), true); + } else if (realProds.head().items().size() == 4) { + // XCell ::= "initXCell" "(" Map ")" + return Tuple4.apply( + Set(), + Lists.newArrayList(sort), + KApply(KLabel(getInitLabel(sort)), INIT), + true); + } } - return Tuple4.apply(accumSentences, sorts, KApply(KLabels.CELLS, immutable(initializers)), false); + } } - //TODO: call generic getSort method of some kind - // child of a leaf cell. Generate no productions, but inform parent that it has a child of a particular sort. - // A leaf cell initializes to the value specified in the configuration declaration. - Sort sort = kapp.att().get(Production.class).sort(); - Tuple2> res = getLeafInitializer(term, m); - return Tuple4.apply(res._2(), Lists.newArrayList(sort), res._1(), true); - } else if (term instanceof KToken ktoken) { - // child of a leaf cell. Generate no productions, but inform parent that it has a child of a particular sort. - // A leaf cell initializes to the value specified in the configuration declaration. - Tuple2> res = getLeafInitializer(term, m); - return Tuple4.apply(res._2(), Lists.newArrayList(ktoken.sort()), res._1(), true); - } else if (term instanceof KSequence || term instanceof KVariable || term instanceof InjectedKLabel) { - // child of a leaf cell. Generate no productions, but inform parent that it has a child of a particular sort. - // A leaf cell initializes to the value specified in the configuration declaration. - Tuple2> res = getLeafInitializer(term, m); - return Tuple4.apply(res._2(), Lists.newArrayList(Sorts.K()), res._1(), true); - } else { - throw KEMException.compilerError("Unexpected value found in configuration declaration, expected KToken, KSequence, or KApply", term); + } + } + throw KEMException.compilerError( + "Malformed external cell in configuration declaration.", term); + } else if (KLabels.CELLS.equals(kapp.klabel())) { + // is a cell bag, and thus represents the multiple children of its parent cell + if (ensures != null) { + // top level cell, therefore, should be the children of the generatedTop cell + KToken cellLabel = KToken(KLabels.GENERATED_TOP_CELL_NAME, Sort("#CellName")); + K generatedTop = + KApply( + KLabel("#configCell"), + cellLabel, + KApply(KLabel("#cellPropertyListTerminator")), + term, + cellLabel); + return genInternal(generatedTop, ensures, cfgAtt, m); } + List cells = Assoc.flatten(kapp.klabel(), kapp.klist().items(), m); + Set accumSentences = Set(); + List sorts = Lists.newArrayList(); + List initializers = Lists.newArrayList(); + for (K cell : cells) { + // for each cell, generate the child and inform the parent of the children it contains + Tuple4, List, K, Boolean> childResult = + genInternal(cell, null, cfgAtt, m); + accumSentences = (Set) accumSentences.$bar(childResult._1()); + sorts.addAll(childResult._2()); + initializers.add(childResult._3()); + } + return Tuple4.apply( + accumSentences, sorts, KApply(KLabels.CELLS, immutable(initializers)), false); + } + // TODO: call generic getSort method of some kind + // child of a leaf cell. Generate no productions, but inform parent that it has a child of a + // particular sort. + // A leaf cell initializes to the value specified in the configuration declaration. + Sort sort = kapp.att().get(Production.class).sort(); + Tuple2> res = getLeafInitializer(term, m); + return Tuple4.apply(res._2(), Lists.newArrayList(sort), res._1(), true); + } else if (term instanceof KToken ktoken) { + // child of a leaf cell. Generate no productions, but inform parent that it has a child of a + // particular sort. + // A leaf cell initializes to the value specified in the configuration declaration. + Tuple2> res = getLeafInitializer(term, m); + return Tuple4.apply(res._2(), Lists.newArrayList(ktoken.sort()), res._1(), true); + } else if (term instanceof KSequence + || term instanceof KVariable + || term instanceof InjectedKLabel) { + // child of a leaf cell. Generate no productions, but inform parent that it has a child of a + // particular sort. + // A leaf cell initializes to the value specified in the configuration declaration. + Tuple2> res = getLeafInitializer(term, m); + return Tuple4.apply(res._2(), Lists.newArrayList(Sorts.K()), res._1(), true); + } else { + throw KEMException.compilerError( + "Unexpected value found in configuration declaration, expected KToken, KSequence, or" + + " KApply", + term); } - - public static String getInitLabel(Sort sort) { - return "init" + sort.toString(); + } + + public static String getInitLabel(Sort sort) { + return "init" + sort.toString(); + } + + /** + * Returns true if the specified term has a configuration or regular variable + * + * @param contents + */ + private static boolean hasConfigOrRegularVariable(K contents, Module m) { + FindConfigOrRegularVar visitor = new FindConfigOrRegularVar(m); + visitor.apply(contents); + return visitor.hasConfigVar; + } + + private static class FindConfigOrRegularVar extends VisitK { + + private final Module m; + boolean hasConfigVar; + + public FindConfigOrRegularVar(Module m) { + this.m = m; } - /** - * Returns true if the specified term has a configuration or regular variable - * @param contents - */ - private static boolean hasConfigOrRegularVariable(K contents, Module m) { - FindConfigOrRegularVar visitor = new FindConfigOrRegularVar(m); - visitor.apply(contents); - return visitor.hasConfigVar; + @Override + public void apply(KToken k) { + if (k.sort().equals(Sorts.KConfigVar())) { + hasConfigVar = true; + } } - private static class FindConfigOrRegularVar extends VisitK { - - private final Module m; - boolean hasConfigVar; - - public FindConfigOrRegularVar(Module m) { - this.m = m; - } - - @Override - public void apply(KToken k) { - if (k.sort().equals(Sorts.KConfigVar())) { - hasConfigVar = true; - } - } - - @Override - public void apply(KApply kapp) { - if (kapp.klabel().name().equals("#externalCell")) { - if (kapp.klist().size() == 1) { - K startLabel = kapp.klist().items().get(0); - if (startLabel instanceof KToken label) { - if (label.sort().equals(Sort("#CellName"))) { - String cellName = label.s(); - Sort sort = Sort(getSortOfCell(cellName)); - Option> initializerProduction = m.productionsFor().get(KLabel(getInitLabel(sort))); - if (initializerProduction.isDefined()) { - Set realProds = stream(initializerProduction.get()) - .filter(p -> !p.att().contains(Att.RECORD_PRD(), Production.class)) - .collect(Collections.toSet()); - if (realProds.size() == 1) { // should be only a single initializer - if (realProds.head().items().size() == 4) { - hasConfigVar = true; - } - } - } - } - } + @Override + public void apply(KApply kapp) { + if (kapp.klabel().name().equals("#externalCell")) { + if (kapp.klist().size() == 1) { + K startLabel = kapp.klist().items().get(0); + if (startLabel instanceof KToken label) { + if (label.sort().equals(Sort("#CellName"))) { + String cellName = label.s(); + Sort sort = Sort(getSortOfCell(cellName)); + Option> initializerProduction = + m.productionsFor().get(KLabel(getInitLabel(sort))); + if (initializerProduction.isDefined()) { + Set realProds = + stream(initializerProduction.get()) + .filter(p -> !p.att().contains(Att.RECORD_PRD(), Production.class)) + .collect(Collections.toSet()); + if (realProds.size() == 1) { // should be only a single initializer + if (realProds.head().items().size() == 4) { + hasConfigVar = true; + } } + } } - super.apply(kapp); - } - - @Override - public void apply(KVariable k) { - hasConfigVar = true; + } } + } + super.apply(kapp); } - /** - * Returns the body of an initializer for a leaf cell: replaces any configuration variables - * with map lookups in the initialization map. - * @param leafContents - * @return - */ - private static Tuple2> getLeafInitializer(K leafContents, Module m) { - class Holder { - Set sentences = Set(); - } - Holder h = new Holder(); - return Tuple2.apply(new TransformK() { - private Sort sort; - - @Override - public K apply(KApply k) { - if (k.klabel().name().startsWith("#SemanticCastTo")) { - sort = k.att().get(Production.class).sort(); - } - return super.apply(k); + @Override + public void apply(KVariable k) { + hasConfigVar = true; + } + } + + /** + * Returns the body of an initializer for a leaf cell: replaces any configuration variables with + * map lookups in the initialization map. + * + * @param leafContents + * @return + */ + private static Tuple2> getLeafInitializer(K leafContents, Module m) { + class Holder { + Set sentences = Set(); + } + Holder h = new Holder(); + return Tuple2.apply( + new TransformK() { + private Sort sort; + + @Override + public K apply(KApply k) { + if (k.klabel().name().startsWith("#SemanticCastTo")) { + sort = k.att().get(Production.class).sort(); } + return super.apply(k); + } - @Override - public K apply(KToken k) { - if (k.sort().equals(Sorts.KConfigVar())) { - if (sort == null || sort.equals(Sorts.K())) { - return KApply(GenerateSortProjections.getProjectLbl(Sorts.KItem(), m), KApply(KLabel("Map:lookup"), INIT, k)); - } else { - return KApply(GenerateSortProjections.getProjectLbl(sort, m), KApply(KLabel("Map:lookup"), INIT, k)); - } - } - return k; + @Override + public K apply(KToken k) { + if (k.sort().equals(Sorts.KConfigVar())) { + if (sort == null || sort.equals(Sorts.K())) { + return KApply( + GenerateSortProjections.getProjectLbl(Sorts.KItem(), m), + KApply(KLabel("Map:lookup"), INIT, k)); + } else { + return KApply( + GenerateSortProjections.getProjectLbl(sort, m), + KApply(KLabel("Map:lookup"), INIT, k)); + } } - }.apply(leafContents), h.sentences); + return k; + } + }.apply(leafContents), + h.sentences); + } + + private static final KVariable INIT = KVariable("Init", Att.empty().add(Sort.class, Sorts.Map())); + + /** + * Generates the sentences associated with a particular cell. + * + *

As a special case, cells with the maincell attribute (usually just the {@code } cell) are + * generated with contents of sort K, rather than a narrower sort calculated from the contents. + * + * @param isLeaf true if this cell has no child cells. + * @param isStream true if this cell has a stream attribute. + * @param multiplicity The multiplicity of the cell + * @param configAtt The attributes on the configuration declaration. + * @param m The module containing the configuration. + * @param cellName The name of the cell being generated. + * @param cellProperties The attributes on the configuration cell (<cell + * foo="bar"></cell> + * @param childSorts The list of sorts computed via recursion of the children of the current cell. + * @param childInitializer The contents of the cell being processed, converted into the right hand + * side of an initializer. + * @param ensures The ensures clause to be used; null if the cell is not a top cell. + * @param hasConfigurationOrRegularVariable true if the initializer for the cell requires a + * configuration variable or a regular variable (when refering directly to configuration + * initializers). This causes cells of multiplicity * or ? to be initialized to a non-empty + * bag, and the initializer to take a Map argument containing the values of the configuration + * variables. + * @return A tuple containing the sentences associated with the cell, the sort of the cell, and + * the term to be used to initialize this cell in the initializer of its parent cell. + */ + private static Tuple4, Sort, K, Boolean> computeSentencesOfWellFormedCell( + boolean isLeaf, + boolean isStream, + Multiplicity multiplicity, + Att configAtt, + Module m, + String cellName, + Att cellProperties, + List childSorts, + K childInitializer, + K ensures, + boolean hasConfigurationOrRegularVariable) { + String sortName = getSortOfCell(cellName); + Sort sort = Sort(sortName); + + if (cellProperties.contains(Att.MAINCELL())) { + assert isLeaf; + assert childSorts.size() == 1; + childSorts = Lists.newArrayList(Sorts.K()); } - private static final KVariable INIT = KVariable("Init", Att.empty().add(Sort.class, Sorts.Map())); - - /** - * Generates the sentences associated with a particular cell. - * - * As a special case, cells with the maincell attribute (usually just the {@code } cell) - * are generated with contents of sort K, rather than a narrower sort calculated from the contents. - * @param isLeaf true if this cell has no child cells. - * @param isStream true if this cell has a stream attribute. - * @param multiplicity The multiplicity of the cell - * @param configAtt The attributes on the configuration declaration. - * @param m The module containing the configuration. - * @param cellName The name of the cell being generated. - * @param cellProperties The attributes on the configuration cell (<cell foo="bar"></cell> - * @param childSorts The list of sorts computed via recursion of the children of the current cell. - * @param childInitializer The contents of the cell being processed, converted into the right hand side of an initializer. - * @param ensures The ensures clause to be used; null if the cell is not a top cell. - * @param hasConfigurationOrRegularVariable true if the initializer for the cell requires a configuration variable or a - * regular variable (when refering directly to configuration initializers). - * This causes cells of multiplicity * or ? to be initialized to a non-empty bag, - * and the initializer to take a Map argument containing the values of the configuration - * variables. - * @return A tuple containing the sentences associated with the cell, the sort of the cell, and the term to be used to initialize - * this cell in the initializer of its parent cell. - */ - private static Tuple4, Sort, K, Boolean> computeSentencesOfWellFormedCell( - boolean isLeaf, - boolean isStream, - Multiplicity multiplicity, - Att configAtt, - Module m, - String cellName, - Att cellProperties, - List childSorts, - K childInitializer, - K ensures, - boolean hasConfigurationOrRegularVariable) { - String sortName = getSortOfCell(cellName); - Sort sort = Sort(sortName); - - if (cellProperties.contains(Att.MAINCELL())) { - assert isLeaf; - assert childSorts.size() == 1; - childSorts = Lists.newArrayList(Sorts.K()); - } - - List items = Stream.concat(Stream.concat(Stream.of( - Terminal("<" + cellName + ">")), childSorts.stream() - .map(Constructors::NonTerminal)), Stream.of(Terminal(""))) - .collect(Collectors.toList()); - - java.util.Set sentences = new HashSet(); - - String klabel = "<" + cellName + ">"; - Att att = cellProperties.addAll(configAtt); - - StringBuilder format = new StringBuilder(); - if (!cellProperties.contains(Att.FORMAT())) { - format.append("%1%i"); - int i; - for (i = 2; i < 2 + childSorts.size(); i++) { - format.append("%n%").append(i); - } - format.append("%d%n%").append(i); - att = att.add(Att.FORMAT(), format.toString()); - } - - // syntax Cell ::= "" Children... "" [cell, cellProperties, configDeclAttributes] - if(!m.definedKLabels().contains(KLabel(klabel)) && multiplicity != Multiplicity.OPTIONAL) { - Production cellProduction = Production(KLabel(klabel), sort, immutable(items), att); - sentences.add(cellProduction); - } + List items = + Stream.concat( + Stream.concat( + Stream.of(Terminal("<" + cellName + ">")), + childSorts.stream().map(Constructors::NonTerminal)), + Stream.of(Terminal(""))) + .collect(Collectors.toList()); + + java.util.Set sentences = new HashSet(); + + String klabel = "<" + cellName + ">"; + Att att = cellProperties.addAll(configAtt); + + StringBuilder format = new StringBuilder(); + if (!cellProperties.contains(Att.FORMAT())) { + format.append("%1%i"); + int i; + for (i = 2; i < 2 + childSorts.size(); i++) { + format.append("%n%").append(i); + } + format.append("%d%n%").append(i); + att = att.add(Att.FORMAT(), format.toString()); + } - // syntax Cell ::= "initCell" [initializer, function] - // -or- - // syntax Cell ::= initCell(Map) [initializer, function] - String initLabel = getInitLabel(sort); - Sentence initializer; - Rule initializerRule; - Sort initSort = sort; - - if (multiplicity == Multiplicity.STAR) { - String type = cellProperties.getOptional(Att.TYPE()).orElse("Bag"); - initSort = Sort(sortName + type); - } + // syntax Cell ::= "" Children... "" [cell, cellProperties, configDeclAttributes] + if (!m.definedKLabels().contains(KLabel(klabel)) && multiplicity != Multiplicity.OPTIONAL) { + Production cellProduction = Production(KLabel(klabel), sort, immutable(items), att); + sentences.add(cellProduction); + } - if (hasConfigurationOrRegularVariable || isStream) { - initializer = Production(KLabel(initLabel), initSort, Seq(Terminal(initLabel), Terminal("("), NonTerminal(Sorts.Map()), Terminal(")")), Att().add(Att.INITIALIZER()).add(Att.FUNCTION())); - initializerRule = Rule(KRewrite(KApply(KLabel(initLabel), INIT), IncompleteCellUtils.make(KLabel("<" + cellName + ">"), false, childInitializer, false)), BooleanUtils.TRUE, ensures == null ? BooleanUtils.TRUE : ensures, Att().add(Att.INITIALIZER())); - } else { - initializer = Production(KLabel(initLabel), initSort, Seq(Terminal(initLabel)), Att().add(Att.INITIALIZER()).add(Att.FUNCTION())); - initializerRule = Rule(KRewrite(KApply(KLabel(initLabel)), IncompleteCellUtils.make(KLabel("<" + cellName + ">"), false, childInitializer, false)), BooleanUtils.TRUE, ensures == null ? BooleanUtils.TRUE : ensures, Att().add(Att.INITIALIZER())); - } - if (!m.definedKLabels().contains(KLabel(initLabel))) { - sentences.add(initializer); - } - sentences.add(initializerRule); - - if (!isLeaf) { - // syntax CellFragment ::= -fragment Child1CellOpt Child2CellOpt ... ChildNCellOpt -fragment [cellFragment(Cell)] - // syntax Child1CellOpt[cellFragmentOpt(Child1Cell)] ::= Child1Cell | "noChild1Cell"[cellFragmentOptAbsent] - // ... - // syntax ChildNCellOpt[cellFragmentOpt(ChildNCell)] ::= ChildNCell | "noChildNCell"[cellFragmentOptAbsent] - - // The "CellOpt" sorts are added for cells of multiplicitly other than * to allow representing fragments - // that didn't try to capture the corresponding cell, from a cell fragment variable written next to - // an explicit pattern for some cells. - // We don't need to add those sorts for cells of multiplicitly *, because explicit patterns in the - // context of a cell fragment variable can never be sure to capture all copies of such a cell. - Sort fragmentSort = Sort(sortName+"Fragment"); - List fragmentItems = new ArrayList(2+childSorts.size()); - fragmentItems.add(Terminal("<"+cellName+">-fragment")); - for (Sort childSort : childSorts) { - if (!childSort.name().endsWith("Cell")) { - // child was a multiplicity * List/Bag/Set - fragmentItems.add(NonTerminal(childSort)); - } else { - Sort childOptSort = Sort(childSort.name()+"Opt", childSort.params()); - fragmentItems.add(NonTerminal(childOptSort)); - - sentences.add(Production(Seq(), childOptSort, List(NonTerminal(childSort)))); - if (!m.definedKLabels().contains(KLabel("no" + childSort))) { - sentences.add(Production(KLabel("no" + childSort), childOptSort, List(Terminal("no" + childSort)), - Att().add(Att.CELL_OPT_ABSENT(),Sort.class,childSort))); - } - } - } - fragmentItems.add(Terminal("-fragment")); - if (!m.definedKLabels().contains(KLabel("<" + cellName + ">-fragment"))) { - sentences.add(Production(KLabel("<" + cellName + ">-fragment"), fragmentSort, immutable(fragmentItems), - Att().add(Att.CELL_FRAGMENT(), Sort.class, Sort(sortName)))); - } - } + // syntax Cell ::= "initCell" [initializer, function] + // -or- + // syntax Cell ::= initCell(Map) [initializer, function] + String initLabel = getInitLabel(sort); + Sentence initializer; + Rule initializerRule; + Sort initSort = sort; + + if (multiplicity == Multiplicity.STAR) { + String type = cellProperties.getOptional(Att.TYPE()).orElse("Bag"); + initSort = Sort(sortName + type); + } - Sort cellsSort; - K rhs; - if (multiplicity == Multiplicity.STAR) { - // syntax CellBag [hook(BAG.Bag)] - // syntax CellBag ::= Cell - // syntax CellBag ::= ".CellBag" [hook(BAG.unit), function] - // syntax CellBag ::= CellBagItem(Cell) [hook(BAG.element), function] - // syntax CellBag ::= CellBag CellBag [assoc, comm, unit(.CellBag), element(CellBagItem), wrapElement(), hook(BAG.concat), avoid, function] - // -or- - // syntax CellSet [hook(SET.Set)] - // syntax CellSet ::= Cell - // syntax CellSet ::= ".CellSet" [hook(SET.unit), function] - // syntax CellSet ::= CellSetItem(Cell) [hook(SET.element), function] - // syntax CellSet ::= CellSet CellSet [assoc, comm, idem, unit(.CellSet), element(CellSetItem), wrapElement(), hook(SET.concat), avoid, function] - // -or- - // syntax CellMap [hook(MAP.Map)] - // syntax CellMap ::= Cell - // syntax CellMap ::= ".CellMap" [hook(MAP.unit), function] - // syntax CellMap ::= CellMapItem(KeyCell, Cell) [hook(MAP.element), function] - // syntax CellMap ::= CellMap CellMap [assoc, comm, unit(.CellMap), element(CellMapItem), wrapElement(), hook(MAP.concat), avoid, function] - // -or- - // syntax CellList [hook(LIST.List)] - // syntax CellList ::= Cell - // syntax CellList ::= ".CellList" [hook(LIST.unit), function] - // syntax CellList ::= CellListItem(Cell) [hook(LIST.element), function] - // syntax CellList ::= CellList CellList [assoc, unit(.CellList), element(CellListItem), wrapElement(), hook(LIST.concat), avoid, function] - String type = cellProperties.getOptional(Att.TYPE()).orElse("Bag"); - Sort bagSort = Sort(sortName + type); - Att bagAtt = Att() - .add(Att.ASSOC(), "") - .add(Att.CELL_COLLECTION()) - .add(Att.ELEMENT(), bagSort.name() + "Item") - .add(Att.WRAP_ELEMENT(), "<" + cellName + ">") - .add(Att.UNIT(), "." + bagSort.name()) - .add(Att.HOOK(), type.toUpperCase() + ".concat") - .add(Att.AVOID()) // needed to ensure cell collections are parsed as Bag instead of CellBag - .add(Att.FUNCTION()); - String unitHook = type.toUpperCase() + ".unit", elementHook = type.toUpperCase() + ".element"; - switch(type) { - case "Set": - bagAtt = bagAtt.add(Att.IDEM(), ""); - // fall through - case "Map": - bagAtt = bagAtt.add(Att.COMM(), ""); - break; - case "Bag": - bagAtt = bagAtt.add(Att.COMM(), "").add(Att.BAG()); - break; - case "List": - break; - default: - throw KEMException.compilerError("Unexpected type for multiplicity * cell: " + cellName - + ". Should be one of: Set, Bag, List, Map", KApply(KLabel("#EmptyK"), Seq(), configAtt)); - } - SyntaxSort sortDecl = SyntaxSort(Seq(), bagSort, Att().add(Att.HOOK(), type.toUpperCase() + '.' + type).add(Att.CELL_COLLECTION())); - Sentence bagSubsort = Production(Seq(), bagSort, Seq(NonTerminal(sort))); - Sentence bagElement; - if (type.equals("Map")) { - if (childSorts.isEmpty()) { - throw KEMException.compilerError("Cells of type Map expect at least one child cell as their key", - KApply(KLabel("#EmptyK"), Seq(), configAtt)); - } - bagElement = Production(KLabel(bagSort.name() + "Item"), bagSort, Seq( - Terminal(bagSort.name() + "Item"), - Terminal("("), - NonTerminal(childSorts.get(0)), - Terminal(","), - NonTerminal(sort), - Terminal(")")), Att().add(Att.HOOK(), elementHook).add(Att.FUNCTION()).add(Att.FORMAT(), "%5")); - } else { - bagElement = Production(KLabel(bagSort.name() + "Item"), bagSort, Seq( - Terminal(bagSort.name() + "Item"), - Terminal("("), - NonTerminal(sort), - Terminal(")")), Att().add(Att.HOOK(), elementHook).add(Att.FUNCTION()).add(Att.FORMAT(), "%3")); - } - Sentence bagUnit = Production(KLabel("." + bagSort.name()), bagSort, Seq(Terminal("." + bagSort.name())), Att().add(Att.HOOK(), unitHook).add(Att.FUNCTION())); - Sentence bag = Production(KLabel("_" + bagSort + "_"), bagSort, Seq(NonTerminal(bagSort), NonTerminal(bagSort)), - bagAtt); - sentences.add(sortDecl); - sentences.add(bagSubsort); - sentences.add(bagElement); - sentences.add(bagUnit); - sentences.add(bag); - if (type.equals("Map")) { - // syntax Bool ::= KeyCell "in_keys" "(" CellMap ")" [function, total, hook(MAP.in_keys)] - sentences.add(Production(KLabel(bagSort.name() + ":in_keys"), Sorts.Bool(), Seq(NonTerminal(childSorts.get(0)), Terminal("in_keys"), Terminal("("), NonTerminal(bagSort), Terminal(")")), Att().add(Att.HOOK(), "MAP.in_keys").add(Att.FUNCTION()).add(Att.TOTAL()))); - - // syntax KeyCell ::= CellMapKey(Cell) [function, total] - // rule CellMapKey( K ...<\cell>) => K - KLabel cellMapKeyLabel = KLabel(bagSort.name() + "Key"); - Production cellMapKeyProduction = Production(cellMapKeyLabel, childSorts.get(0), Seq(Terminal(bagSort.name() + "Key"), Terminal("("), NonTerminal(sort), Terminal(")")), Att().add(Att.FUNCTION()).add(Att.TOTAL())); - KVariable key = KVariable("Key", Att.empty().add(Sort.class, childSorts.get(0))); - Rule cellMapKeyRule = Rule(KRewrite(KApply(cellMapKeyLabel, IncompleteCellUtils.make(KLabel(klabel), false, key, true)), key), BooleanUtils.TRUE, BooleanUtils.TRUE); - sentences.add(cellMapKeyProduction); - sentences.add(cellMapKeyRule); - } - // rule initCell => .CellBag - // -or- - // rule initCell(Init) => Context[$var] - cellsSort = bagSort; - rhs = optionalCellInitializer(hasConfigurationOrRegularVariable, cellProperties, initLabel); - } else if (multiplicity == Multiplicity.OPTIONAL) { - // syntax Cell ::= ".Cell" - Production cellUnit = Production(KLabel("." + sortName), sort, Seq(Terminal("." + sortName))); - sentences.add(cellUnit); - // add UNIT attribute to cell production. - if(!m.definedKLabels().contains(KLabel(klabel))) { - Production cellProduction = Production(KLabel(klabel), sort, immutable(items), att.add(Att.UNIT(), cellUnit.klabel().get().name())); - sentences.add(cellProduction); - } - // rule initCell => .CellBag - // -or- - // rule initCell(Init) => Context[$var] - cellsSort = sort; - rhs = optionalCellInitializer(hasConfigurationOrRegularVariable, cellProperties, initLabel); + if (hasConfigurationOrRegularVariable || isStream) { + initializer = + Production( + KLabel(initLabel), + initSort, + Seq(Terminal(initLabel), Terminal("("), NonTerminal(Sorts.Map()), Terminal(")")), + Att().add(Att.INITIALIZER()).add(Att.FUNCTION())); + initializerRule = + Rule( + KRewrite( + KApply(KLabel(initLabel), INIT), + IncompleteCellUtils.make( + KLabel("<" + cellName + ">"), false, childInitializer, false)), + BooleanUtils.TRUE, + ensures == null ? BooleanUtils.TRUE : ensures, + Att().add(Att.INITIALIZER())); + } else { + initializer = + Production( + KLabel(initLabel), + initSort, + Seq(Terminal(initLabel)), + Att().add(Att.INITIALIZER()).add(Att.FUNCTION())); + initializerRule = + Rule( + KRewrite( + KApply(KLabel(initLabel)), + IncompleteCellUtils.make( + KLabel("<" + cellName + ">"), false, childInitializer, false)), + BooleanUtils.TRUE, + ensures == null ? BooleanUtils.TRUE : ensures, + Att().add(Att.INITIALIZER())); + } + if (!m.definedKLabels().contains(KLabel(initLabel))) { + sentences.add(initializer); + } + sentences.add(initializerRule); + + if (!isLeaf) { + // syntax CellFragment ::= -fragment Child1CellOpt Child2CellOpt ... ChildNCellOpt + // -fragment [cellFragment(Cell)] + // syntax Child1CellOpt[cellFragmentOpt(Child1Cell)] ::= Child1Cell | + // "noChild1Cell"[cellFragmentOptAbsent] + // ... + // syntax ChildNCellOpt[cellFragmentOpt(ChildNCell)] ::= ChildNCell | + // "noChildNCell"[cellFragmentOptAbsent] + + // The "CellOpt" sorts are added for cells of multiplicitly other than * to allow representing + // fragments + // that didn't try to capture the corresponding cell, from a cell fragment variable written + // next to + // an explicit pattern for some cells. + // We don't need to add those sorts for cells of multiplicitly *, because explicit patterns in + // the + // context of a cell fragment variable can never be sure to capture all copies of such a cell. + Sort fragmentSort = Sort(sortName + "Fragment"); + List fragmentItems = new ArrayList(2 + childSorts.size()); + fragmentItems.add(Terminal("<" + cellName + ">-fragment")); + for (Sort childSort : childSorts) { + if (!childSort.name().endsWith("Cell")) { + // child was a multiplicity * List/Bag/Set + fragmentItems.add(NonTerminal(childSort)); } else { - // rule initCell => initChildren... - // -or- - // rule initCell(Init) => initChildren(Init)... - cellsSort = sort; - if (hasConfigurationOrRegularVariable || isStream) { - rhs = KApply(KLabel(initLabel), INIT); - } else { - rhs = KApply(KLabel(initLabel)); - } + Sort childOptSort = Sort(childSort.name() + "Opt", childSort.params()); + fragmentItems.add(NonTerminal(childOptSort)); + + sentences.add(Production(Seq(), childOptSort, List(NonTerminal(childSort)))); + if (!m.definedKLabels().contains(KLabel("no" + childSort))) { + sentences.add( + Production( + KLabel("no" + childSort), + childOptSort, + List(Terminal("no" + childSort)), + Att().add(Att.CELL_OPT_ABSENT(), Sort.class, childSort))); + } } - - if (cellProperties.contains(Att.EXIT())) { - KLabel getExitCodeLabel = KLabel("getExitCode"); - Production getExitCode = Production(getExitCodeLabel, Sorts.Int(), Seq(Terminal("getExitCode"), Terminal("("), NonTerminal(Sorts.GeneratedTopCell()), Terminal(")")), Att.empty().add(Att.FUNCTION())); - sentences.add(getExitCode); - KVariable var = KVariable("Exit", Att.empty().add(Sort.class, Sorts.Int())); - Rule getExitCodeRule = Rule(KRewrite(KApply(getExitCodeLabel, IncompleteCellUtils.make(KLabels.GENERATED_TOP_CELL, true, IncompleteCellUtils.make(KLabel(klabel), false, var, false), true)), var), BooleanUtils.TRUE, BooleanUtils.TRUE); - sentences.add(SyntaxSort.apply(Seq(), Sorts.GeneratedTopCell(), Att.empty())); - sentences.add(getExitCodeRule); - } - return Tuple4.apply(immutable(sentences),cellsSort,rhs, false); + } + fragmentItems.add(Terminal("-fragment")); + if (!m.definedKLabels().contains(KLabel("<" + cellName + ">-fragment"))) { + sentences.add( + Production( + KLabel("<" + cellName + ">-fragment"), + fragmentSort, + immutable(fragmentItems), + Att().add(Att.CELL_FRAGMENT(), Sort.class, Sort(sortName)))); + } } - /** - * Returns the term used to initialize an optinoal cell. An optional cell is initialized to the empty bag if - * it contains no configuration variables, and to a single cell if it contains configuration variables. - */ - private static KApply optionalCellInitializer(boolean initializeOptionalCell, Att cellProperties, String initLabel) { - if (initializeOptionalCell) { - return KApply(KLabel(initLabel), INIT); - } else if (cellProperties.contains(Att.INITIAL())) { - return KApply(KLabel(initLabel)); - } else { - return KApply(KLabels.CELLS); + Sort cellsSort; + K rhs; + if (multiplicity == Multiplicity.STAR) { + // syntax CellBag [hook(BAG.Bag)] + // syntax CellBag ::= Cell + // syntax CellBag ::= ".CellBag" [hook(BAG.unit), function] + // syntax CellBag ::= CellBagItem(Cell) [hook(BAG.element), function] + // syntax CellBag ::= CellBag CellBag [assoc, comm, unit(.CellBag), element(CellBagItem), + // wrapElement(), hook(BAG.concat), avoid, function] + // -or- + // syntax CellSet [hook(SET.Set)] + // syntax CellSet ::= Cell + // syntax CellSet ::= ".CellSet" [hook(SET.unit), function] + // syntax CellSet ::= CellSetItem(Cell) [hook(SET.element), function] + // syntax CellSet ::= CellSet CellSet [assoc, comm, idem, unit(.CellSet), + // element(CellSetItem), wrapElement(), hook(SET.concat), avoid, function] + // -or- + // syntax CellMap [hook(MAP.Map)] + // syntax CellMap ::= Cell + // syntax CellMap ::= ".CellMap" [hook(MAP.unit), function] + // syntax CellMap ::= CellMapItem(KeyCell, Cell) [hook(MAP.element), function] + // syntax CellMap ::= CellMap CellMap [assoc, comm, unit(.CellMap), element(CellMapItem), + // wrapElement(), hook(MAP.concat), avoid, function] + // -or- + // syntax CellList [hook(LIST.List)] + // syntax CellList ::= Cell + // syntax CellList ::= ".CellList" [hook(LIST.unit), function] + // syntax CellList ::= CellListItem(Cell) [hook(LIST.element), function] + // syntax CellList ::= CellList CellList [assoc, unit(.CellList), element(CellListItem), + // wrapElement(), hook(LIST.concat), avoid, function] + String type = cellProperties.getOptional(Att.TYPE()).orElse("Bag"); + Sort bagSort = Sort(sortName + type); + Att bagAtt = + Att() + .add(Att.ASSOC(), "") + .add(Att.CELL_COLLECTION()) + .add(Att.ELEMENT(), bagSort.name() + "Item") + .add(Att.WRAP_ELEMENT(), "<" + cellName + ">") + .add(Att.UNIT(), "." + bagSort.name()) + .add(Att.HOOK(), type.toUpperCase() + ".concat") + .add(Att.AVOID()) // needed to ensure cell collections are parsed as Bag instead of + // CellBag + .add(Att.FUNCTION()); + String unitHook = type.toUpperCase() + ".unit", elementHook = type.toUpperCase() + ".element"; + switch (type) { + case "Set": + bagAtt = bagAtt.add(Att.IDEM(), ""); + // fall through + case "Map": + bagAtt = bagAtt.add(Att.COMM(), ""); + break; + case "Bag": + bagAtt = bagAtt.add(Att.COMM(), "").add(Att.BAG()); + break; + case "List": + break; + default: + throw KEMException.compilerError( + "Unexpected type for multiplicity * cell: " + + cellName + + ". Should be one of: Set, Bag, List, Map", + KApply(KLabel("#EmptyK"), Seq(), configAtt)); + } + SyntaxSort sortDecl = + SyntaxSort( + Seq(), + bagSort, + Att().add(Att.HOOK(), type.toUpperCase() + '.' + type).add(Att.CELL_COLLECTION())); + Sentence bagSubsort = Production(Seq(), bagSort, Seq(NonTerminal(sort))); + Sentence bagElement; + if (type.equals("Map")) { + if (childSorts.isEmpty()) { + throw KEMException.compilerError( + "Cells of type Map expect at least one child cell as their key", + KApply(KLabel("#EmptyK"), Seq(), configAtt)); } + bagElement = + Production( + KLabel(bagSort.name() + "Item"), + bagSort, + Seq( + Terminal(bagSort.name() + "Item"), + Terminal("("), + NonTerminal(childSorts.get(0)), + Terminal(","), + NonTerminal(sort), + Terminal(")")), + Att().add(Att.HOOK(), elementHook).add(Att.FUNCTION()).add(Att.FORMAT(), "%5")); + } else { + bagElement = + Production( + KLabel(bagSort.name() + "Item"), + bagSort, + Seq( + Terminal(bagSort.name() + "Item"), + Terminal("("), + NonTerminal(sort), + Terminal(")")), + Att().add(Att.HOOK(), elementHook).add(Att.FUNCTION()).add(Att.FORMAT(), "%3")); + } + Sentence bagUnit = + Production( + KLabel("." + bagSort.name()), + bagSort, + Seq(Terminal("." + bagSort.name())), + Att().add(Att.HOOK(), unitHook).add(Att.FUNCTION())); + Sentence bag = + Production( + KLabel("_" + bagSort + "_"), + bagSort, + Seq(NonTerminal(bagSort), NonTerminal(bagSort)), + bagAtt); + sentences.add(sortDecl); + sentences.add(bagSubsort); + sentences.add(bagElement); + sentences.add(bagUnit); + sentences.add(bag); + if (type.equals("Map")) { + // syntax Bool ::= KeyCell "in_keys" "(" CellMap ")" [function, total, hook(MAP.in_keys)] + sentences.add( + Production( + KLabel(bagSort.name() + ":in_keys"), + Sorts.Bool(), + Seq( + NonTerminal(childSorts.get(0)), + Terminal("in_keys"), + Terminal("("), + NonTerminal(bagSort), + Terminal(")")), + Att().add(Att.HOOK(), "MAP.in_keys").add(Att.FUNCTION()).add(Att.TOTAL()))); + + // syntax KeyCell ::= CellMapKey(Cell) [function, total] + // rule CellMapKey( K ...<\cell>) => K + KLabel cellMapKeyLabel = KLabel(bagSort.name() + "Key"); + Production cellMapKeyProduction = + Production( + cellMapKeyLabel, + childSorts.get(0), + Seq( + Terminal(bagSort.name() + "Key"), + Terminal("("), + NonTerminal(sort), + Terminal(")")), + Att().add(Att.FUNCTION()).add(Att.TOTAL())); + KVariable key = KVariable("Key", Att.empty().add(Sort.class, childSorts.get(0))); + Rule cellMapKeyRule = + Rule( + KRewrite( + KApply( + cellMapKeyLabel, + IncompleteCellUtils.make(KLabel(klabel), false, key, true)), + key), + BooleanUtils.TRUE, + BooleanUtils.TRUE); + sentences.add(cellMapKeyProduction); + sentences.add(cellMapKeyRule); + } + // rule initCell => .CellBag + // -or- + // rule initCell(Init) => Context[$var] + cellsSort = bagSort; + rhs = optionalCellInitializer(hasConfigurationOrRegularVariable, cellProperties, initLabel); + } else if (multiplicity == Multiplicity.OPTIONAL) { + // syntax Cell ::= ".Cell" + Production cellUnit = Production(KLabel("." + sortName), sort, Seq(Terminal("." + sortName))); + sentences.add(cellUnit); + // add UNIT attribute to cell production. + if (!m.definedKLabels().contains(KLabel(klabel))) { + Production cellProduction = + Production( + KLabel(klabel), + sort, + immutable(items), + att.add(Att.UNIT(), cellUnit.klabel().get().name())); + sentences.add(cellProduction); + } + // rule initCell => .CellBag + // -or- + // rule initCell(Init) => Context[$var] + cellsSort = sort; + rhs = optionalCellInitializer(hasConfigurationOrRegularVariable, cellProperties, initLabel); + } else { + // rule initCell => initChildren... + // -or- + // rule initCell(Init) => initChildren(Init)... + cellsSort = sort; + if (hasConfigurationOrRegularVariable || isStream) { + rhs = KApply(KLabel(initLabel), INIT); + } else { + rhs = KApply(KLabel(initLabel)); + } } - private static Att getCellPropertiesAsAtt(K k, String cellName, K ensures) { - Att att = Att(); - if (cellName.equals("k")) { - att = att.add(Att.MAINCELL()); - } - att = att.add(Att.CELL()).add(Att.CELL_NAME(), cellName); - return att.addAll(getCellPropertiesAsAtt(k)); + if (cellProperties.contains(Att.EXIT())) { + KLabel getExitCodeLabel = KLabel("getExitCode"); + Production getExitCode = + Production( + getExitCodeLabel, + Sorts.Int(), + Seq( + Terminal("getExitCode"), + Terminal("("), + NonTerminal(Sorts.GeneratedTopCell()), + Terminal(")")), + Att.empty().add(Att.FUNCTION())); + sentences.add(getExitCode); + KVariable var = KVariable("Exit", Att.empty().add(Sort.class, Sorts.Int())); + Rule getExitCodeRule = + Rule( + KRewrite( + KApply( + getExitCodeLabel, + IncompleteCellUtils.make( + KLabels.GENERATED_TOP_CELL, + true, + IncompleteCellUtils.make(KLabel(klabel), false, var, false), + true)), + var), + BooleanUtils.TRUE, + BooleanUtils.TRUE); + sentences.add(SyntaxSort.apply(Seq(), Sorts.GeneratedTopCell(), Att.empty())); + sentences.add(getExitCodeRule); + } + return Tuple4.apply(immutable(sentences), cellsSort, rhs, false); + } + + /** + * Returns the term used to initialize an optinoal cell. An optional cell is initialized to the + * empty bag if it contains no configuration variables, and to a single cell if it contains + * configuration variables. + */ + private static KApply optionalCellInitializer( + boolean initializeOptionalCell, Att cellProperties, String initLabel) { + if (initializeOptionalCell) { + return KApply(KLabel(initLabel), INIT); + } else if (cellProperties.contains(Att.INITIAL())) { + return KApply(KLabel(initLabel)); + } else { + return KApply(KLabels.CELLS); } + } - private static Att getCellPropertiesAsAtt(K k) { - if (k instanceof KApply kapp) { - if (kapp.klabel().name().equals("#cellPropertyListTerminator")) { - return Att(); - } else if (kapp.klabel().name().equals("#cellPropertyList")) { - if (kapp.klist().size() == 2) { - Tuple2 attribute = getCellProperty(kapp.klist().items().get(0)); - return ProcessGroupAttributes.getProcessedAtt( - Att().add(attribute._1(), attribute._2()) - .addAll(getCellPropertiesAsAtt(kapp.klist().items().get(1))), - k); - } - } + private static Att getCellPropertiesAsAtt(K k, String cellName, K ensures) { + Att att = Att(); + if (cellName.equals("k")) { + att = att.add(Att.MAINCELL()); + } + att = att.add(Att.CELL()).add(Att.CELL_NAME(), cellName); + return att.addAll(getCellPropertiesAsAtt(k)); + } + + private static Att getCellPropertiesAsAtt(K k) { + if (k instanceof KApply kapp) { + if (kapp.klabel().name().equals("#cellPropertyListTerminator")) { + return Att(); + } else if (kapp.klabel().name().equals("#cellPropertyList")) { + if (kapp.klist().size() == 2) { + Tuple2 attribute = getCellProperty(kapp.klist().items().get(0)); + return ProcessGroupAttributes.getProcessedAtt( + Att() + .add(attribute._1(), attribute._2()) + .addAll(getCellPropertiesAsAtt(kapp.klist().items().get(1))), + k); } - throw KEMException.compilerError("Malformed cell properties", k); + } } - - private static Tuple2 getCellProperty(K k) { - if (k instanceof KApply kapp) { - if (kapp.klabel().name().equals("#cellProperty")) { - if (kapp.klist().size() == 2) { - if (kapp.klist().items().get(0) instanceof KToken keyToken) { - if (keyToken.sort().equals(Sort("#CellName"))) { - Att.Key key = Att.getBuiltinKeyOptional(keyToken.s()) - .orElseThrow(() -> - KEMException.compilerError("Unrecognized attribute: " + keyToken.s() + - "\nHint: User-defined groups can be added with the group=\"...\" attribute.", k)); - if (kapp.klist().items().get(0) instanceof KToken) { - KToken valueToken = (KToken) kapp.klist().items().get(1); - if (valueToken.sort().equals(Sorts.KString())) { - String value = StringUtil.unquoteKString(valueToken.s()); - return Tuple2.apply(key, value); - } - } - } - } + throw KEMException.compilerError("Malformed cell properties", k); + } + + private static Tuple2 getCellProperty(K k) { + if (k instanceof KApply kapp) { + if (kapp.klabel().name().equals("#cellProperty")) { + if (kapp.klist().size() == 2) { + if (kapp.klist().items().get(0) instanceof KToken keyToken) { + if (keyToken.sort().equals(Sort("#CellName"))) { + Att.Key key = + Att.getBuiltinKeyOptional(keyToken.s()) + .orElseThrow( + () -> + KEMException.compilerError( + "Unrecognized attribute: " + + keyToken.s() + + "\n" + + "Hint: User-defined groups can be added with the" + + " group=\"...\" attribute.", + k)); + if (kapp.klist().items().get(0) instanceof KToken) { + KToken valueToken = (KToken) kapp.klist().items().get(1); + if (valueToken.sort().equals(Sorts.KString())) { + String value = StringUtil.unquoteKString(valueToken.s()); + return Tuple2.apply(key, value); } + } } + } } - throw KEMException.compilerError("Malformed cell property", k); + } } - - public static String getSortOfCell(String cellName) { - char[] chars = cellName.toCharArray(); - StringBuilder sb = new StringBuilder(); - sb.append(Character.toUpperCase(chars[0])); - for (int i = 1; i < chars.length; i++) { - if (chars[i] == '-' && i + 1 < chars.length && Character.isLowerCase(chars[i+1])) { - chars[i+1] = Character.toUpperCase(chars[i+1]); - } else if (chars[i] != '-') { - sb.append(chars[i]); - } - } - sb.append("Cell"); - return sb.toString(); + throw KEMException.compilerError("Malformed cell property", k); + } + + public static String getSortOfCell(String cellName) { + char[] chars = cellName.toCharArray(); + StringBuilder sb = new StringBuilder(); + sb.append(Character.toUpperCase(chars[0])); + for (int i = 1; i < chars.length; i++) { + if (chars[i] == '-' && i + 1 < chars.length && Character.isLowerCase(chars[i + 1])) { + chars[i + 1] = Character.toUpperCase(chars[i + 1]); + } else if (chars[i] != '-') { + sb.append(chars[i]); + } } - - private static Multiplicity convertStringMultiplicity(Option multiplicity, K body) { - if (multiplicity.isEmpty()) - return Multiplicity.ONE; - try { - return Multiplicity.of(multiplicity.get()); - } catch (IllegalArgumentException x) { - throw KEMException.compilerError("Invalid multiplicity found in cell: " + multiplicity.get(), body); - } + sb.append("Cell"); + return sb.toString(); + } + + private static Multiplicity convertStringMultiplicity(Option multiplicity, K body) { + if (multiplicity.isEmpty()) return Multiplicity.ONE; + try { + return Multiplicity.of(multiplicity.get()); + } catch (IllegalArgumentException x) { + throw KEMException.compilerError( + "Invalid multiplicity found in cell: " + multiplicity.get(), body); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateRules.java b/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateRules.java index 925f63ec8c8..14d07647bfc 100644 --- a/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateRules.java +++ b/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateRules.java @@ -1,17 +1,20 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.apache.commons.lang3.mutable.MutableBoolean; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; -import org.kframework.definition.NonTerminal; -import org.kframework.definition.Production; import org.kframework.definition.Rule; import org.kframework.definition.Sentence; -import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KLabel; import org.kframework.kore.KRewrite; @@ -19,43 +22,54 @@ import org.kframework.kore.Sort; import scala.collection.Set; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - /** - * Generates sort predicates from the subsort hierarchy of the module. This module assumes that the backend implements - * the following rules: - * isSort(#token(Sort, _)) => true - * isK(K) => true - * isKItem(K1(K2)) => true - * isKItem(#token(_, _)) => true + * Generates sort predicates from the subsort hierarchy of the module. This module assumes that the + * backend implements the following rules: + * + *

+ *  isSort(#token(Sort, _)) => true
+ *  isK(K) => true
+ *  isKItem(K1(K2)) => true
+ *  isKItem(#token(_, _)) => true
+ * 
* * plus one sort membership function for each builtin-hooked sort. */ public class GenerateSortPredicateRules { - public Module gen(Module mod) { - return Module(mod.name(), mod.imports(), (Set) mod.localSentences().$bar(stream(mod.allSorts()) - .flatMap(this::gen).collect(Collections.toSet())), mod.att()); - } + public Module gen(Module mod) { + return Module( + mod.name(), + mod.imports(), + (Set) + mod.localSentences() + .$bar(stream(mod.allSorts()).flatMap(this::gen).collect(Collections.toSet())), + mod.att()); + } - private Stream gen(Sort sort) { - if (sort.equals(Sorts.K())) { - return Stream.of(Rule(KRewrite(KApply(KLabel("is" + sort), KVariable("K")), BooleanUtils.TRUE), BooleanUtils.TRUE, BooleanUtils.TRUE)); - } else { - List res = new ArrayList<>(); - res.add(Rule(KRewrite(KApply(KLabel("is" + sort), KVariable(sort.name(), Att().add(Sort.class, sort))), BooleanUtils.TRUE), BooleanUtils.TRUE, BooleanUtils.TRUE)); - res.add(Rule(KRewrite(KApply(KLabel("is" + sort), KVariable("K")), BooleanUtils.FALSE), BooleanUtils.TRUE, BooleanUtils.TRUE, Att().add(Att.OWISE()))); - return res.stream(); - } + private Stream gen(Sort sort) { + if (sort.equals(Sorts.K())) { + return Stream.of( + Rule( + KRewrite(KApply(KLabel("is" + sort), KVariable("K")), BooleanUtils.TRUE), + BooleanUtils.TRUE, + BooleanUtils.TRUE)); + } else { + List res = new ArrayList<>(); + res.add( + Rule( + KRewrite( + KApply(KLabel("is" + sort), KVariable(sort.name(), Att().add(Sort.class, sort))), + BooleanUtils.TRUE), + BooleanUtils.TRUE, + BooleanUtils.TRUE)); + res.add( + Rule( + KRewrite(KApply(KLabel("is" + sort), KVariable("K")), BooleanUtils.FALSE), + BooleanUtils.TRUE, + BooleanUtils.TRUE, + Att().add(Att.OWISE()))); + return res.stream(); } - + } } diff --git a/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateSyntax.java b/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateSyntax.java index bbc405f8de1..d213025a2ba 100644 --- a/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateSyntax.java +++ b/kernel/src/main/java/org/kframework/compile/GenerateSortPredicateSyntax.java @@ -1,6 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; @@ -8,36 +15,32 @@ import org.kframework.definition.Sentence; import org.kframework.kore.Sort; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import static org.kframework.kore.KORE.*; -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; - -/** - * Created by dwightguth on 5/28/15. - */ +/** Created by dwightguth on 5/28/15. */ public class GenerateSortPredicateSyntax { - public Module gen(Module mod) { - Set res = new HashSet<>(); - for (Sort sort : iterable(mod.allSorts())) { - res.addAll(gen(mod, sort)); - } - if (!res.isEmpty()) { - res.add(SyntaxSort(Seq(), Sorts.K())); - } - return Module(mod.name(), mod.imports(), (scala.collection.Set) mod.localSentences().$bar(immutable(res)), mod.att()); + public Module gen(Module mod) { + Set res = new HashSet<>(); + for (Sort sort : iterable(mod.allSorts())) { + res.addAll(gen(mod, sort)); } - - public Set gen(Module mod, Sort sort) { - Production prod = Production(KLabel("is" + sort.toString()), Sorts.Bool(), - Seq(Terminal("is" + sort), Terminal("("), NonTerminal(Sorts.K()), Terminal(")")), - Att().add(Att.FUNCTION()).add(Att.TOTAL()).add(Att.PREDICATE(), Sort.class, sort)); - if (!mod.productions().contains(prod)) - return Collections.singleton(prod); - return Collections.emptySet(); + if (!res.isEmpty()) { + res.add(SyntaxSort(Seq(), Sorts.K())); } + return Module( + mod.name(), + mod.imports(), + (scala.collection.Set) mod.localSentences().$bar(immutable(res)), + mod.att()); + } + + public Set gen(Module mod, Sort sort) { + Production prod = + Production( + KLabel("is" + sort.toString()), + Sorts.Bool(), + Seq(Terminal("is" + sort), Terminal("("), NonTerminal(Sorts.K()), Terminal(")")), + Att().add(Att.FUNCTION()).add(Att.TOTAL()).add(Att.PREDICATE(), Sort.class, sort)); + if (!mod.productions().contains(prod)) return Collections.singleton(prod); + return Collections.emptySet(); + } } diff --git a/kernel/src/main/java/org/kframework/compile/GenerateSortProjections.java b/kernel/src/main/java/org/kframework/compile/GenerateSortProjections.java index 89ff228a0e0..6a0c8f6bbca 100644 --- a/kernel/src/main/java/org/kframework/compile/GenerateSortProjections.java +++ b/kernel/src/main/java/org/kframework/compile/GenerateSortProjections.java @@ -1,8 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.attributes.Att; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Stream; import org.kframework.Collections; +import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; @@ -17,94 +25,137 @@ import org.kframework.parser.inner.RuleGrammarGenerator; import scala.collection.Set; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Stream; +public class GenerateSortProjections { -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; + private Module mod; + private final boolean cover; -public class GenerateSortProjections { + public GenerateSortProjections(boolean cover) { + this.cover = cover; + } - private Module mod; - private final boolean cover; + public GenerateSortProjections(Module mod) { + this.mod = mod; + this.cover = false; + } - public GenerateSortProjections(boolean cover) { - this.cover = cover; - } + public Module gen(Module mod) { + this.mod = mod; + return Module( + mod.name(), + mod.imports(), + (Set) + mod.localSentences() + .$bar( + Stream.concat( + stream(mod.allSorts()).flatMap(this::gen), + stream(mod.localProductions()).flatMap(this::gen)) + .collect(Collections.toSet())), + mod.att()); + } - public GenerateSortProjections(Module mod) { - this.mod = mod; - this.cover = false; - } + public static KLabel getProjectLbl(Sort sort, Module m) { + KLabel lbl; + lbl = KLabel("project:" + sort.toString()); + return lbl; + } - public Module gen(Module mod) { - this.mod = mod; - return Module(mod.name(), mod.imports(), (Set) mod.localSentences().$bar( - Stream.concat(stream(mod.allSorts()).flatMap(this::gen), - stream(mod.localProductions()).flatMap(this::gen)).collect(Collections.toSet())), mod.att()); - } + public static KLabel getProjectLbl(String klabel, String name) { + return KLabel("project:" + klabel + ":" + name); + } - public static KLabel getProjectLbl(Sort sort, Module m) { - KLabel lbl; - lbl = KLabel("project:" + sort.toString()); - return lbl; + public Stream gen(Sort sort) { + if (RuleGrammarGenerator.isParserSort(sort) + && !sort.equals(Sorts.KItem()) + && !sort.equals(Sorts.K())) { + return Stream.empty(); } - - public static KLabel getProjectLbl(String klabel, String name) { - return KLabel("project:" + klabel + ":" + name); + KLabel lbl = getProjectLbl(sort, mod); + KVariable var = KVariable("K", Att.empty().add(Sort.class, sort)); + Rule r = + Rule( + KRewrite(KApply(lbl, var), var), + BooleanUtils.TRUE, + BooleanUtils.TRUE, + Att().add(Att.PROJECTION())); + if (mod.definedKLabels().contains(lbl)) { + return Stream.empty(); } - - public Stream gen(Sort sort) { - if (RuleGrammarGenerator.isParserSort(sort) && !sort.equals(Sorts.KItem()) && !sort.equals(Sorts.K())) { - return Stream.empty(); - } - KLabel lbl = getProjectLbl(sort, mod); - KVariable var = KVariable("K", Att.empty().add(Sort.class, sort)); - Rule r = Rule(KRewrite(KApply(lbl, var), var), BooleanUtils.TRUE, BooleanUtils.TRUE, Att().add(Att.PROJECTION())); - if (mod.definedKLabels().contains(lbl)) { - return Stream.empty(); - } - Production prod = Production(lbl, sort, Seq(Terminal(lbl.name()), Terminal("("), NonTerminal(Sorts.K()), Terminal(")")), Att().add(Att.FUNCTION()).add(Att.PROJECTION())); - if (cover) { - KLabel sideEffectLbl = KLabel("sideEffect:" + sort); - Production sideEffect = Production(sideEffectLbl, sort, Seq(Terminal(sideEffectLbl.name()), Terminal("("), NonTerminal(Sorts.K()), Terminal(","), NonTerminal(sort), Terminal(")")), Att().add(Att.FUNCTION())); - Rule sideEffectR = Rule(KRewrite(KApply(sideEffectLbl, KVariable("K2", Att.empty().add(Sort.class, Sorts.K())), var), var), BooleanUtils.TRUE, BooleanUtils.TRUE); - return stream(Set(prod, r, sideEffect, sideEffectR)); - } else { - return stream(Set(prod, r)); - } + Production prod = + Production( + lbl, + sort, + Seq(Terminal(lbl.name()), Terminal("("), NonTerminal(Sorts.K()), Terminal(")")), + Att().add(Att.FUNCTION()).add(Att.PROJECTION())); + if (cover) { + KLabel sideEffectLbl = KLabel("sideEffect:" + sort); + Production sideEffect = + Production( + sideEffectLbl, + sort, + Seq( + Terminal(sideEffectLbl.name()), + Terminal("("), + NonTerminal(Sorts.K()), + Terminal(","), + NonTerminal(sort), + Terminal(")")), + Att().add(Att.FUNCTION())); + Rule sideEffectR = + Rule( + KRewrite( + KApply( + sideEffectLbl, KVariable("K2", Att.empty().add(Sort.class, Sorts.K())), var), + var), + BooleanUtils.TRUE, + BooleanUtils.TRUE); + return stream(Set(prod, r, sideEffect, sideEffectR)); + } else { + return stream(Set(prod, r)); } + } - public Stream gen(Production prod) { - if (prod.att().contains(Att.FUNCTION()) || (prod.klabel().isDefined() && mod.macroKLabels().contains(prod.klabel().get()))) { - return Stream.empty(); - } - java.util.Set sentences = new HashSet<>(); - List vars = new ArrayList<>(); - int i = 0; - boolean hasName = false; - for (NonTerminal nt : iterable(prod.nonterminals())) { - vars.add(KVariable("K" + i++, Att.empty().add(Sort.class, nt.sort()))); - hasName = hasName || nt.name().isDefined(); - } - if (!hasName) { - return Stream.empty(); - } - i = 0; - for (NonTerminal nt : iterable(prod.nonterminals())) { - if (nt.name().isDefined()) { - KLabel lbl = getProjectLbl(prod.klabel().get().name(), nt.name().get()); - if (mod.definedKLabels().contains(lbl)) { - return Stream.empty(); - } - sentences.add(Production(lbl, nt.sort(), Seq(Terminal(nt.name().get()), Terminal("("), NonTerminal(prod.sort()), Terminal(")")), Att().add(Att.FUNCTION()))); - sentences.add(Rule(KRewrite(KApply(lbl, KApply(prod.klabel().get(), KList(vars))), vars.get(i)), BooleanUtils.TRUE, BooleanUtils.TRUE)); + public Stream gen(Production prod) { + if (prod.att().contains(Att.FUNCTION()) + || (prod.klabel().isDefined() && mod.macroKLabels().contains(prod.klabel().get()))) { + return Stream.empty(); + } + java.util.Set sentences = new HashSet<>(); + List vars = new ArrayList<>(); + int i = 0; + boolean hasName = false; + for (NonTerminal nt : iterable(prod.nonterminals())) { + vars.add(KVariable("K" + i++, Att.empty().add(Sort.class, nt.sort()))); + hasName = hasName || nt.name().isDefined(); + } + if (!hasName) { + return Stream.empty(); + } + i = 0; + for (NonTerminal nt : iterable(prod.nonterminals())) { + if (nt.name().isDefined()) { + KLabel lbl = getProjectLbl(prod.klabel().get().name(), nt.name().get()); + if (mod.definedKLabels().contains(lbl)) { + return Stream.empty(); } - i++; + sentences.add( + Production( + lbl, + nt.sort(), + Seq( + Terminal(nt.name().get()), + Terminal("("), + NonTerminal(prod.sort()), + Terminal(")")), + Att().add(Att.FUNCTION()))); + sentences.add( + Rule( + KRewrite(KApply(lbl, KApply(prod.klabel().get(), KList(vars))), vars.get(i)), + BooleanUtils.TRUE, + BooleanUtils.TRUE)); } - return sentences.stream(); + i++; } + return sentences.stream(); + } } diff --git a/kernel/src/main/java/org/kframework/compile/GuardOrPatterns.java b/kernel/src/main/java/org/kframework/compile/GuardOrPatterns.java index d15b075f20d..bfc2c5d0cac 100644 --- a/kernel/src/main/java/org/kframework/compile/GuardOrPatterns.java +++ b/kernel/src/main/java/org/kframework/compile/GuardOrPatterns.java @@ -1,110 +1,107 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.HashSet; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; import org.kframework.definition.Context; import org.kframework.definition.Module; -import org.kframework.definition.Production; import org.kframework.definition.Rule; import org.kframework.definition.Sentence; import org.kframework.kore.*; -import java.util.HashSet; -import java.util.Set; +public class GuardOrPatterns { -import static org.kframework.kore.KORE.*; + private final Set vars = new HashSet<>(); -public class GuardOrPatterns { + void resetVars() { + vars.clear(); + } - private final Set vars = new HashSet<>(); + private Rule resolve(Module m, Rule rule) { + resetVars(); + gatherVars(rule.body()); + gatherVars(rule.requires()); + gatherVars(rule.ensures()); + return new Rule( + transform(rule.body(), m), + transform(rule.requires(), m), + transform(rule.ensures(), m), + rule.att()); + } - void resetVars() { - vars.clear(); - } + private Context resolve(Module m, Context context) { + resetVars(); + gatherVars(context.body()); + gatherVars(context.requires()); + return new Context( + transform(context.body(), m), transform(context.requires(), m), context.att()); + } - private Rule resolve(Module m, Rule rule) { - resetVars(); - gatherVars(rule.body()); - gatherVars(rule.requires()); - gatherVars(rule.ensures()); - return new Rule( - transform(rule.body(), m), - transform(rule.requires(), m), - transform(rule.ensures(), m), - rule.att()); - } + public K resolveK(Module m, K k) { + resetVars(); + gatherVars(k); + return transform(k, m); + } - private Context resolve(Module m, Context context) { - resetVars(); - gatherVars(context.body()); - gatherVars(context.requires()); - return new Context( - transform(context.body(), m), - transform(context.requires(), m), - context.att()); + public synchronized Sentence resolve(Module m, Sentence s) { + if (s instanceof Rule) { + return resolve(m, (Rule) s); + } else if (s instanceof Context) { + return resolve(m, (Context) s); + } else { + return s; } + } - public K resolveK(Module m, K k) { - resetVars(); - gatherVars(k); - return transform(k, m); - } + void gatherVars(K term) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + super.apply(v); + } + }.apply(term); + } - public synchronized Sentence resolve(Module m, Sentence s) { - if (s instanceof Rule) { - return resolve(m, (Rule) s); - } else if (s instanceof Context) { - return resolve(m, (Context) s); - } else { - return s; + K transform(K term, Module m) { + return new TransformK() { + @Override + public K apply(KApply k) { + if (k.klabel().head().equals(KLabels.ML_OR)) { + AddSortInjections inj = new AddSortInjections(m); + return KAs(k, newDotVariable(inj.sort(k, null))); } - } + return super.apply(k); + } - void gatherVars(K term) { - new VisitK() { - @Override - public void apply(KVariable v) { - vars.add(v); - super.apply(v); - } - }.apply(term); - } - - K transform(K term, Module m) { - return new TransformK() { - @Override - public K apply(KApply k) { - if (k.klabel().head().equals(KLabels.ML_OR)) { - AddSortInjections inj = new AddSortInjections(m); - return KAs(k, newDotVariable(inj.sort(k, null))); - } - return super.apply(k); - } + @Override + public K apply(KAs k) { + return k; + } - @Override - public K apply(KAs k) { - return k; - } + @Override + public K apply(KRewrite k) { + return k; + } + }.apply(term); + } - @Override - public K apply(KRewrite k) { - return k; - } - }.apply(term); - } + private int counter = 0; - private int counter = 0; - KVariable newDotVariable(Sort s) { - if (s == null) { - s = Sorts.K(); - } - KVariable newLabel; - do { - newLabel = KVariable("_Gen" + (counter++), Att().add(Att.ANONYMOUS()).add(Sort.class, s)); - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; + KVariable newDotVariable(Sort s) { + if (s == null) { + s = Sorts.K(); } + KVariable newLabel; + do { + newLabel = KVariable("_Gen" + (counter++), Att().add(Att.ANONYMOUS()).add(Sort.class, s)); + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } } diff --git a/kernel/src/main/java/org/kframework/compile/IncompleteCellUtils.java b/kernel/src/main/java/org/kframework/compile/IncompleteCellUtils.java index 3a93e84bca5..2827257d0d3 100644 --- a/kernel/src/main/java/org/kframework/compile/IncompleteCellUtils.java +++ b/kernel/src/main/java/org/kframework/compile/IncompleteCellUtils.java @@ -1,82 +1,82 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.List; import org.kframework.builtin.KLabels; import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KLabel; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.List; - -import static org.kframework.kore.KORE.*; - /** - * Utility methods for dealing with cells as seen in Full K. - * These are represented in kast by applying the cell label - * to three argument - (left dots, body, right dots) - * rather than the arity declared in their production. - * dots are represented with an application #dots() or #noDots() - * Multiple cells, rewrites, or other items are joined into - * a single argument by using the label #cells - * (which this class will allow with arbitrary arity). + * Utility methods for dealing with cells as seen in Full K. These are represented in kast by + * applying the cell label to three argument - (left dots, body, right dots) rather than the arity + * declared in their production. dots are represented with an application #dots() or #noDots() + * Multiple cells, rewrites, or other items are joined into a single argument by using the label + * #cells (which this class will allow with arbitrary arity). */ public class IncompleteCellUtils { - private final static KApply dots = KApply(KLabels.DOTS); - private final static KApply noDots = KApply(KLabels.NO_DOTS); + private static final KApply dots = KApply(KLabels.DOTS); + private static final KApply noDots = KApply(KLabels.NO_DOTS); - private static boolean isOpen(K flag) { - if (dots.equals(flag)) { - return true; - } else if (noDots.equals(flag)) { - return false; - } else { - throw KEMException.criticalError("Instead of #dots() or #noDots(), got " + flag); - } + private static boolean isOpen(K flag) { + if (dots.equals(flag)) { + return true; + } else if (noDots.equals(flag)) { + return false; + } else { + throw KEMException.criticalError("Instead of #dots() or #noDots(), got " + flag); } + } - public static boolean isOpenLeft(KApply cell) { - return isOpen(cell.klist().items().get(0)); - } - public static boolean isOpenRight(KApply cell) { - return isOpen(cell.klist().items().get(2)); - } + public static boolean isOpenLeft(KApply cell) { + return isOpen(cell.klist().items().get(0)); + } - private static void flattenCells(List children, K item) { - if (item instanceof KApply && KLabels.CELLS.equals(((KApply) item).klabel())) { - for (K deeper : ((KApply) item).klist().items()) { - flattenCells(children, deeper); - } - } else { - children.add(item); - } - } - public static List flattenCells(K cells) { - List children = new ArrayList(); - flattenCells(children, cells); - return children; - } + public static boolean isOpenRight(KApply cell) { + return isOpen(cell.klist().items().get(2)); + } - public static List getChildren(KApply cell) { - return flattenCells(cell.klist().items().get(1)); + private static void flattenCells(List children, K item) { + if (item instanceof KApply && KLabels.CELLS.equals(((KApply) item).klabel())) { + for (K deeper : ((KApply) item).klist().items()) { + flattenCells(children, deeper); + } + } else { + children.add(item); } + } - private static KApply makeDots(boolean isOpen) { - return isOpen ? dots : noDots; - } - static K makeBody(List children) { - if (children.size() == 1) { - return children.get(0); - } else { - return KApply(KLabels.CELLS, KList(children)); - } - } + public static List flattenCells(K cells) { + List children = new ArrayList(); + flattenCells(children, cells); + return children; + } - public static KApply make(KLabel label, boolean openLeft, K child, boolean openRight) { - return KApply(label, KList(makeDots(openLeft), child, makeDots(openRight))); - } - public static KApply make(KLabel label, boolean openLeft, List children, boolean openRight) { - return KApply(label, KList(makeDots(openLeft), makeBody(children), makeDots(openRight))); + public static List getChildren(KApply cell) { + return flattenCells(cell.klist().items().get(1)); + } + + private static KApply makeDots(boolean isOpen) { + return isOpen ? dots : noDots; + } + + static K makeBody(List children) { + if (children.size() == 1) { + return children.get(0); + } else { + return KApply(KLabels.CELLS, KList(children)); } + } + + public static KApply make(KLabel label, boolean openLeft, K child, boolean openRight) { + return KApply(label, KList(makeDots(openLeft), child, makeDots(openRight))); + } + + public static KApply make(KLabel label, boolean openLeft, List children, boolean openRight) { + return KApply(label, KList(makeDots(openLeft), makeBody(children), makeDots(openRight))); + } } diff --git a/kernel/src/main/java/org/kframework/compile/LiftToKSequence.java b/kernel/src/main/java/org/kframework/compile/LiftToKSequence.java index c951c9508bd..143ae4a3f4d 100644 --- a/kernel/src/main/java/org/kframework/compile/LiftToKSequence.java +++ b/kernel/src/main/java/org/kframework/compile/LiftToKSequence.java @@ -1,92 +1,85 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.builtin.Sorts; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.List; import org.kframework.builtin.KLabels; +import org.kframework.builtin.Sorts; import org.kframework.definition.Context; import org.kframework.definition.Rule; import org.kframework.definition.Sentence; import org.kframework.kore.*; -import java.util.ArrayList; -import java.util.List; - -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - /** * Raises all rules into a form with a KSequence in every position that expects a term of sort K. */ public class LiftToKSequence { - - public Sentence lift(Sentence s) { - if (s instanceof Rule) { - return lift((Rule) s); - } else if (s instanceof Context) { - return lift((Context) s); - } else { - return s; - } + public Sentence lift(Sentence s) { + if (s instanceof Rule) { + return lift((Rule) s); + } else if (s instanceof Context) { + return lift((Context) s); + } else { + return s; } + } - private Rule lift(Rule rule) { - return Rule( - lift(rule.body()), - lift(rule.requires()), - lift(rule.ensures()), - rule.att()); - } + private Rule lift(Rule rule) { + return Rule(lift(rule.body()), lift(rule.requires()), lift(rule.ensures()), rule.att()); + } - private Context lift(Context context) { - return Context( - lift(context.body()), - lift(context.requires()), - context.att()); - } + private Context lift(Context context) { + return Context(lift(context.body()), lift(context.requires()), context.att()); + } - public K lift(K term) { - K result = new TransformK() { - @Override - public K apply(KApply k) { - List children = new ArrayList<>(); - for (K child : k.klist().items()) { - K res = apply(child); - if (res instanceof KSequence || k.klabel().equals(KLabels.ML_OR)) { - children.add(res); - } else { - children.add(KSequence(res)); - } - } - return KApply(k.klabel(), KList(children), k.att()); + public K lift(K term) { + K result = + new TransformK() { + @Override + public K apply(KApply k) { + List children = new ArrayList<>(); + for (K child : k.klist().items()) { + K res = apply(child); + if (res instanceof KSequence || k.klabel().equals(KLabels.ML_OR)) { + children.add(res); + } else { + children.add(KSequence(res)); + } } + return KApply(k.klabel(), KList(children), k.att()); + } - @Override - public K apply(KAs k) { - K res = apply(k.pattern()); - KVariable var = (KVariable) k.alias(); - if (!(res instanceof KSequence) && var.att().getOptional(Sort.class).orElse(Sorts.K()).equals(Sorts.K())) { - res = KSequence(res); - } - return KAs(res, k.alias(), k.att()); + @Override + public K apply(KAs k) { + K res = apply(k.pattern()); + KVariable var = (KVariable) k.alias(); + if (!(res instanceof KSequence) + && var.att().getOptional(Sort.class).orElse(Sorts.K()).equals(Sorts.K())) { + res = KSequence(res); } + return KAs(res, k.alias(), k.att()); + } }.apply(term); - if (result instanceof KSequence) { - return result; - } else { - return KSequence(result); - } + if (result instanceof KSequence) { + return result; + } else { + return KSequence(result); } + } - public K lower(K term) { - return new TransformK() { - @Override - public K apply(KSequence k) { - if (k.items().size() == 1) { - return super.apply(k.items().get(0)); - } - return super.apply(k); - } - }.apply(term); - } + public K lower(K term) { + return new TransformK() { + @Override + public K apply(KSequence k) { + if (k.items().size() == 1) { + return super.apply(k.items().get(0)); + } + return super.apply(k); + } + }.apply(term); + } } diff --git a/kernel/src/main/java/org/kframework/compile/MarkExtraConcreteRules.java b/kernel/src/main/java/org/kframework/compile/MarkExtraConcreteRules.java index 1ec0c8c2607..62b144016d9 100644 --- a/kernel/src/main/java/org/kframework/compile/MarkExtraConcreteRules.java +++ b/kernel/src/main/java/org/kframework/compile/MarkExtraConcreteRules.java @@ -1,40 +1,43 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.HashSet; +import java.util.List; +import javax.annotation.Nullable; import org.kframework.attributes.Att; import org.kframework.definition.Definition; import org.kframework.definition.DefinitionTransformer; import org.kframework.definition.Rule; import org.kframework.utils.errorsystem.KEMException; -import javax.annotation.Nullable; -import java.util.HashSet; -import java.util.List; - public class MarkExtraConcreteRules { - /** - * Mark with [concrete] rules with labels enumerated in `--concrete-rules`. - */ - public static Definition mark(Definition def, @Nullable List extraConcreteRuleLabels) { - if (extraConcreteRuleLabels == null) { - return def; - } - HashSet concreteLabelsSet = new HashSet<>(extraConcreteRuleLabels); - Definition result = DefinitionTransformer.fromSentenceTransformer((mod, s) -> { - if (s instanceof Rule r) { - String label = r.att().getOption(Att.LABEL()).getOrElse(() -> null); - if (label != null && concreteLabelsSet.contains(label)) { - // rule labels must be unique, so it's safe to remove from the set as we iterate - concreteLabelsSet.remove(label); - return Rule.apply(r.body(), r.requires(), r.ensures(), r.att().add(Att.CONCRETE())); - } - } - return s; - }, "mark extra concrete rules").apply(def); - if (!concreteLabelsSet.isEmpty()) { - throw KEMException.criticalError("Unused concrete rule labels: " + concreteLabelsSet); - } - return result; + /** Mark with [concrete] rules with labels enumerated in `--concrete-rules`. */ + public static Definition mark(Definition def, @Nullable List extraConcreteRuleLabels) { + if (extraConcreteRuleLabels == null) { + return def; + } + HashSet concreteLabelsSet = new HashSet<>(extraConcreteRuleLabels); + Definition result = + DefinitionTransformer.fromSentenceTransformer( + (mod, s) -> { + if (s instanceof Rule r) { + String label = r.att().getOption(Att.LABEL()).getOrElse(() -> null); + if (label != null && concreteLabelsSet.contains(label)) { + // rule labels must be unique, so it's safe to remove from the set as we + // iterate + concreteLabelsSet.remove(label); + return Rule.apply( + r.body(), r.requires(), r.ensures(), r.att().add(Att.CONCRETE())); + } + } + return s; + }, + "mark extra concrete rules") + .apply(def); + if (!concreteLabelsSet.isEmpty()) { + throw KEMException.criticalError("Unused concrete rule labels: " + concreteLabelsSet); } + return result; + } } diff --git a/kernel/src/main/java/org/kframework/compile/MinimizeTermConstruction.java b/kernel/src/main/java/org/kframework/compile/MinimizeTermConstruction.java index 64d8aea9ec7..68088633ad5 100644 --- a/kernel/src/main/java/org/kframework/compile/MinimizeTermConstruction.java +++ b/kernel/src/main/java/org/kframework/compile/MinimizeTermConstruction.java @@ -1,211 +1,226 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.kframework.attributes.Att; +import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; -import org.kframework.builtin.BooleanUtils; import org.kframework.definition.Context; import org.kframework.definition.Module; import org.kframework.definition.Rule; import org.kframework.definition.Sentence; import org.kframework.kore.*; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - public class MinimizeTermConstruction { - private final Set vars = new HashSet<>(); - private final Map cache = new HashMap<>(); - private final Set usedOnRhs = new HashSet<>(); + private final Set vars = new HashSet<>(); + private final Map cache = new HashMap<>(); + private final Set usedOnRhs = new HashSet<>(); - private final Module module; - private final AddSortInjections sorts; + private final Module module; + private final AddSortInjections sorts; - public MinimizeTermConstruction(Module module) { - this.module = module; - this.sorts = new AddSortInjections(module); - } + public MinimizeTermConstruction(Module module) { + this.module = module; + this.sorts = new AddSortInjections(module); + } - void resetVars() { - vars.clear(); - cache.clear(); - usedOnRhs.clear(); - counter = 0; - } + void resetVars() { + vars.clear(); + cache.clear(); + usedOnRhs.clear(); + counter = 0; + } - private Rule resolve(Rule rule) { - if (rule.att().contains(Att.SIMPLIFICATION())) { - return rule; - } - resetVars(); - gatherVars(rule.body()); - gatherVars(rule.requires()); - gatherVars(rule.ensures()); - gatherTerms(rule.body(), true); - gatherTerms(rule.requires(), false); - gatherTerms(rule.ensures(), false); - filterTerms(rule.body(), true); - filterTerms(rule.requires(), false); - filterTerms(rule.ensures(), false); - return new Rule( - transform(rule.body(), true), - transform(rule.requires(), false), - transform(rule.ensures(), false), - rule.att()); + private Rule resolve(Rule rule) { + if (rule.att().contains(Att.SIMPLIFICATION())) { + return rule; } - - private Context resolve(Context context) { - resetVars(); - gatherVars(context.body()); - gatherVars(context.requires()); - gatherTerms(context.body(), true); - gatherTerms(context.requires(), false); - filterTerms(context.body(), true); - filterTerms(context.requires(), false); - return new Context( - transform(context.body(), true), - transform(context.requires(), false), - context.att()); + resetVars(); + gatherVars(rule.body()); + gatherVars(rule.requires()); + gatherVars(rule.ensures()); + gatherTerms(rule.body(), true); + gatherTerms(rule.requires(), false); + gatherTerms(rule.ensures(), false); + filterTerms(rule.body(), true); + filterTerms(rule.requires(), false); + filterTerms(rule.ensures(), false); + return new Rule( + transform(rule.body(), true), + transform(rule.requires(), false), + transform(rule.ensures(), false), + rule.att()); + } + + private Context resolve(Context context) { + resetVars(); + gatherVars(context.body()); + gatherVars(context.requires()); + gatherTerms(context.body(), true); + gatherTerms(context.requires(), false); + filterTerms(context.body(), true); + filterTerms(context.requires(), false); + return new Context( + transform(context.body(), true), transform(context.requires(), false), context.att()); + } + + public synchronized Sentence resolve(Sentence s) { + if (s instanceof Rule) { + return resolve((Rule) s); + } else if (s instanceof Context) { + return resolve((Context) s); + } else { + return s; } - - public synchronized Sentence resolve(Sentence s) { - if (s instanceof Rule) { - return resolve((Rule) s); - } else if (s instanceof Context) { - return resolve((Context) s); - } else { - return s; + } + + void gatherVars(K term) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + super.apply(v); + } + }.apply(term); + } + + void gatherTerms(K term, boolean body) { + new RewriteAwareVisitor(body, new HashSet<>()) { + @Override + public void apply(K k) { + if (isLHS() + && !isRHS() + && !(k instanceof KVariable) + && !atTop + && !k.equals(BooleanUtils.TRUE)) { + cache.put(k, newDotVariable(sorts.sort(k, Sorts.K()))); } - } + atTop = false; + super.apply(k); + } - void gatherVars(K term) { - new VisitK() { - @Override - public void apply(KVariable v) { - vars.add(v); - super.apply(v); - } - }.apply(term); - } - - void gatherTerms(K term, boolean body) { - new RewriteAwareVisitor(body, new HashSet<>()) { - @Override - public void apply(K k) { - if (isLHS() && !isRHS() && !(k instanceof KVariable) && !atTop && !k.equals(BooleanUtils.TRUE)) { - cache.put(k, newDotVariable(sorts.sort(k, Sorts.K()))); - } - atTop = false; - super.apply(k); - } - - boolean atTop = false; - - @Override - public void apply(KRewrite rew) { - if (rew == term) { - atTop = true; - } - super.apply(rew); - } - - @Override - public void apply(KApply k) { - if (k.klabel().head().equals(KLabels.ML_OR)) { - return; - } - String hook = module.attributesFor().get(k.klabel()).getOrElse(() -> Att.empty()).getOptional(Att.HOOK()).orElse(""); - if (hook.equals("SET.element") - || hook.equals("LIST.element") - || hook.equals("LIST.concat") - || hook.equals("MAP.concat") - || hook.equals("SET.concat")) { - return; - } - if (hook.equals("MAP.element")) { - apply(k.items().get(1)); - return; - } - super.apply(k); - } - }.apply(term); - } + boolean atTop = false; - void filterTerms(K term, boolean body) { - new RewriteAwareVisitor(body, new HashSet<>()) { - @Override - public void apply(K k) { - if (isRHS() && !isLHS() && cache.containsKey(k)) { - usedOnRhs.add(k); - return; - } - super.apply(k); - } - }.apply(term); - } + @Override + public void apply(KRewrite rew) { + if (rew == term) { + atTop = true; + } + super.apply(rew); + } - K transform(K term, boolean body) { - return new RewriteAwareTransformer(body) { - @Override - public K apply(K k) { - if (isRHS() && !isLHS()) { - if (cache.containsKey(k)) { - return cache.get(k); - } - } - if (isLHS() && !isRHS() && !inBad) { - if (usedOnRhs.contains(k)) { - return KAs(super.apply(k), cache.get(k), Att.empty().add(Sort.class, cache.get(k).att().get(Sort.class))); - } - } - return super.apply(k); - } - - boolean inBad = false; - - @Override - public K apply(KApply k) { - boolean stack = inBad; - if (k.klabel().head().equals(KLabels.ML_OR)) { - inBad = true; - } - String hook = module.attributesFor().get(k.klabel()).getOrElse(() -> Att.empty()).getOptional(Att.HOOK()).orElse(""); - if (hook.equals("SET.element") - || hook.equals("LIST.element") - || hook.equals("LIST.concat") - || hook.equals("MAP.concat") - || hook.equals("SET.concat")) { - inBad = true; - } - if (hook.equals("MAP.element")) { - inBad = true; - K key = apply(k.items().get(0)); - inBad = stack; - K val = apply(k.items().get(1)); - return KApply(k.klabel(), KList(key, val), k.att()); - } - K result = super.apply(k); - inBad = stack; - return result; - } - - }.apply(term); - } + @Override + public void apply(KApply k) { + if (k.klabel().head().equals(KLabels.ML_OR)) { + return; + } + String hook = + module + .attributesFor() + .get(k.klabel()) + .getOrElse(() -> Att.empty()) + .getOptional(Att.HOOK()) + .orElse(""); + if (hook.equals("SET.element") + || hook.equals("LIST.element") + || hook.equals("LIST.concat") + || hook.equals("MAP.concat") + || hook.equals("SET.concat")) { + return; + } + if (hook.equals("MAP.element")) { + apply(k.items().get(1)); + return; + } + super.apply(k); + } + }.apply(term); + } + + void filterTerms(K term, boolean body) { + new RewriteAwareVisitor(body, new HashSet<>()) { + @Override + public void apply(K k) { + if (isRHS() && !isLHS() && cache.containsKey(k)) { + usedOnRhs.add(k); + return; + } + super.apply(k); + } + }.apply(term); + } + + K transform(K term, boolean body) { + return new RewriteAwareTransformer(body) { + @Override + public K apply(K k) { + if (isRHS() && !isLHS()) { + if (cache.containsKey(k)) { + return cache.get(k); + } + } + if (isLHS() && !isRHS() && !inBad) { + if (usedOnRhs.contains(k)) { + return KAs( + super.apply(k), + cache.get(k), + Att.empty().add(Sort.class, cache.get(k).att().get(Sort.class))); + } + } + return super.apply(k); + } - private int counter = 0; - KVariable newDotVariable(Sort sort) { - KVariable newLabel; - do { - newLabel = KVariable("_Gen" + (counter++), Att().add(Sort.class, sort)); - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; - } + boolean inBad = false; + @Override + public K apply(KApply k) { + boolean stack = inBad; + if (k.klabel().head().equals(KLabels.ML_OR)) { + inBad = true; + } + String hook = + module + .attributesFor() + .get(k.klabel()) + .getOrElse(() -> Att.empty()) + .getOptional(Att.HOOK()) + .orElse(""); + if (hook.equals("SET.element") + || hook.equals("LIST.element") + || hook.equals("LIST.concat") + || hook.equals("MAP.concat") + || hook.equals("SET.concat")) { + inBad = true; + } + if (hook.equals("MAP.element")) { + inBad = true; + K key = apply(k.items().get(0)); + inBad = stack; + K val = apply(k.items().get(1)); + return KApply(k.klabel(), KList(key, val), k.att()); + } + K result = super.apply(k); + inBad = stack; + return result; + } + }.apply(term); + } + + private int counter = 0; + + KVariable newDotVariable(Sort sort) { + KVariable newLabel; + do { + newLabel = KVariable("_Gen" + (counter++), Att().add(Sort.class, sort)); + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } } diff --git a/kernel/src/main/java/org/kframework/compile/NormalizeVariables.java b/kernel/src/main/java/org/kframework/compile/NormalizeVariables.java index 096669daa58..f4dc3f7d75d 100644 --- a/kernel/src/main/java/org/kframework/compile/NormalizeVariables.java +++ b/kernel/src/main/java/org/kframework/compile/NormalizeVariables.java @@ -1,130 +1,122 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.attributes.Att; -import org.kframework.definition.Context; -import org.kframework.definition.Rule; -import org.kframework.definition.Sentence; -import org.kframework.kore.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; - -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; +import org.kframework.attributes.Att; +import org.kframework.definition.Context; +import org.kframework.definition.Rule; +import org.kframework.definition.Sentence; +import org.kframework.kore.*; /** - * Normalizes variable names in terms and sentences according to alpha equivalence. - * Variables that have previously been normalized are not normalized on succeeding passes, - * allowing the user to fine-tune the normalization such that arbitrary subterms can share - * a common prefix. + * Normalizes variable names in terms and sentences according to alpha equivalence. Variables that + * have previously been normalized are not normalized on succeeding passes, allowing the user to + * fine-tune the normalization such that arbitrary subterms can share a common prefix. */ public class NormalizeVariables { - private int counter = 0; - private Map vars = new HashMap<>(); - private KVariable normalize(KVariable var) { - if (var.att().contains(Att.DENORMAL())) - return var; - if (!vars.containsKey(var)) { - vars.put(var, "_" + counter++); - } - return KVariable(vars.get(var), var.att().add(Att.DENORMAL(), var.name())); - } + private int counter = 0; + private Map vars = new HashMap<>(); - /** - * Applies the normalization existing in a particular set of normalized terms to a denormal term - * @param denormal The term to be normalized. Only variables which exist in the specified - * {@code normals} are normalized. - * @param normals A list of terms that have previously been normalized using this class, or which - * have been constructed manually with all variables given the "denormal" - * attribute specifying their denormal name. The term to be normalized - * will be normalized according to the same normalization as these terms. - * @return The normalized version of {@code denormal}, in which each variable present in - * the denormal version of the specified {@code normals} is replaced with its normalized - * name. - */ - public K applyNormalization(K denormal, K... normals) { - Map normalization = inferNormalizationFromTerm(normals); - return new TransformK() { - @Override - public K apply(KVariable k) { - if (normalization.containsKey(k)) { - return KVariable(normalization.get(k), k.att().add(Att.DENORMAL(), k.name())); - } - return super.apply(k); - } - }.apply(denormal); + private KVariable normalize(KVariable var) { + if (var.att().contains(Att.DENORMAL())) return var; + if (!vars.containsKey(var)) { + vars.put(var, "_" + counter++); } + return KVariable(vars.get(var), var.att().add(Att.DENORMAL(), var.name())); + } - private Map inferNormalizationFromTerm(K[] normals) { - Map normalization = new HashMap<>(); - for (K normal : normals) { - new VisitK() { - @Override - public void apply(KVariable k) { - if (k.att().contains(Att.DENORMAL())) { - normalization.put(KVariable(k.att().get(Att.DENORMAL())), k.name()); - } - } - }.apply(normal); + /** + * Applies the normalization existing in a particular set of normalized terms to a denormal term + * + * @param denormal The term to be normalized. Only variables which exist in the specified {@code + * normals} are normalized. + * @param normals A list of terms that have previously been normalized using this class, or which + * have been constructed manually with all variables given the "denormal" attribute specifying + * their denormal name. The term to be normalized will be normalized according to the same + * normalization as these terms. + * @return The normalized version of {@code denormal}, in which each variable present in the + * denormal version of the specified {@code normals} is replaced with its normalized name. + */ + public K applyNormalization(K denormal, K... normals) { + Map normalization = inferNormalizationFromTerm(normals); + return new TransformK() { + @Override + public K apply(KVariable k) { + if (normalization.containsKey(k)) { + return KVariable(normalization.get(k), k.att().add(Att.DENORMAL(), k.name())); } - return normalization; - } + return super.apply(k); + } + }.apply(denormal); + } - public Rule applyNormalization(Rule denormal, K... normals) { - return Rule( - applyNormalization(denormal.body(), normals), - applyNormalization(denormal.requires(), normals), - applyNormalization(denormal.ensures(), normals), - denormal.att()); + private Map inferNormalizationFromTerm(K[] normals) { + Map normalization = new HashMap<>(); + for (K normal : normals) { + new VisitK() { + @Override + public void apply(KVariable k) { + if (k.att().contains(Att.DENORMAL())) { + normalization.put(KVariable(k.att().get(Att.DENORMAL())), k.name()); + } + } + }.apply(normal); } + return normalization; + } - public K normalize(K term, K... normals) { - resetVars(Stream.concat(Stream.of(term), Arrays.stream(normals)).toArray(K[]::new)); - return transform(term); - } + public Rule applyNormalization(Rule denormal, K... normals) { + return Rule( + applyNormalization(denormal.body(), normals), + applyNormalization(denormal.requires(), normals), + applyNormalization(denormal.ensures(), normals), + denormal.att()); + } - public K transform(K term) { - return new TransformK() { - @Override - public K apply(KVariable k) { - return normalize(k); - } - }.apply(term); - } + public K normalize(K term, K... normals) { + resetVars(Stream.concat(Stream.of(term), Arrays.stream(normals)).toArray(K[]::new)); + return transform(term); + } - private void resetVars(K... normals) { - vars = inferNormalizationFromTerm(normals); - counter = vars.size(); - } + public K transform(K term) { + return new TransformK() { + @Override + public K apply(KVariable k) { + return normalize(k); + } + }.apply(term); + } - public Rule normalize(Rule rule) { - resetVars(rule.body(), rule.requires(), rule.ensures()); - return Rule( - transform(rule.body()), - transform(rule.requires()), - transform(rule.ensures()), - rule.att()); - } + private void resetVars(K... normals) { + vars = inferNormalizationFromTerm(normals); + counter = vars.size(); + } - private Context normalize(Context context) { - resetVars(context.body(), context.requires()); - return new Context( - transform(context.body()), - transform(context.requires()), - context.att()); - } + public Rule normalize(Rule rule) { + resetVars(rule.body(), rule.requires(), rule.ensures()); + return Rule( + transform(rule.body()), transform(rule.requires()), transform(rule.ensures()), rule.att()); + } - public Sentence normalize(Sentence s) { - if (s instanceof Rule) { - return normalize((Rule) s); - } else if (s instanceof Context) { - return normalize((Context) s); - } else { - return s; - } + private Context normalize(Context context) { + resetVars(context.body(), context.requires()); + return new Context(transform(context.body()), transform(context.requires()), context.att()); + } + + public Sentence normalize(Sentence s) { + if (s instanceof Rule) { + return normalize((Rule) s); + } else if (s instanceof Context) { + return normalize((Context) s); + } else { + return s; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/NumberSentences.java b/kernel/src/main/java/org/kframework/compile/NumberSentences.java index c659d038aee..52867ddddf5 100644 --- a/kernel/src/main/java/org/kframework/compile/NumberSentences.java +++ b/kernel/src/main/java/org/kframework/compile/NumberSentences.java @@ -4,24 +4,24 @@ import org.bouncycastle.jcajce.provider.digest.SHA3; import org.bouncycastle.util.encoders.Hex; import org.kframework.attributes.Att; -import org.kframework.definition.Sentence; import org.kframework.definition.RuleOrClaim; +import org.kframework.definition.Sentence; public class NumberSentences { - public static Sentence number(Sentence s) { - if (!(s instanceof RuleOrClaim) || s.att().contains(Att.UNIQUE_ID())) { - return s; - } - String id = ruleHash(s.withAtt(Att.empty())); - return s.withAtt(s.att().add(Att.UNIQUE_ID(), id)); + public static Sentence number(Sentence s) { + if (!(s instanceof RuleOrClaim) || s.att().contains(Att.UNIQUE_ID())) { + return s; } + String id = ruleHash(s.withAtt(Att.empty())); + return s.withAtt(s.att().add(Att.UNIQUE_ID(), id)); + } - private static String ruleHash(Sentence s) { - String text = new NormalizeVariables().normalize(s).toString(); - SHA3.Digest256 sha3engine = new SHA3.Digest256(); - byte[] digest = sha3engine.digest(text.getBytes()); - String digestString = Hex.toHexString(digest); - return digestString; - } + private static String ruleHash(Sentence s) { + String text = new NormalizeVariables().normalize(s).toString(); + SHA3.Digest256 sha3engine = new SHA3.Digest256(); + byte[] digest = sha3engine.digest(text.getBytes()); + String digestString = Hex.toHexString(digest); + return digestString; + } } diff --git a/kernel/src/main/java/org/kframework/compile/PatternValueAwareVisitor.java b/kernel/src/main/java/org/kframework/compile/PatternValueAwareVisitor.java index cfaad75cbfa..50d32536f66 100644 --- a/kernel/src/main/java/org/kframework/compile/PatternValueAwareVisitor.java +++ b/kernel/src/main/java/org/kframework/compile/PatternValueAwareVisitor.java @@ -1,91 +1,93 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.Set; import org.kframework.kore.KApply; import org.kframework.kore.KRewrite; import org.kframework.kore.KVariable; import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - /** * A visitor designed to track whether we are currently in Pattern or Value position. * - * outside of rewrite = LHS&RHS, value&pattern - * lhs of rewrite = LHS, pattern - * rhs of rewrite = RHS, value - * requires = LHS, value - * ensures = RHS, value + *

outside of rewrite = LHS&RHS, value&pattern lhs of rewrite = LHS, pattern rhs of rewrite = + * RHS, value requires = LHS, value ensures = RHS, value */ public class PatternValueAwareVisitor extends VisitK { - private final Set errors; - public PatternValueAwareVisitor(boolean isBody, Set errors) { - this.errors = errors; - if (isBody) { - isValue = true; - isPattern = true; - } else { - isValue = true; - isPattern = false; - } + private final Set errors; + + public PatternValueAwareVisitor(boolean isBody, Set errors) { + this.errors = errors; + if (isBody) { + isValue = true; + isPattern = true; + } else { + isValue = true; + isPattern = false; } + } + private boolean isPattern; + private boolean isValue; - private boolean isPattern; - private boolean isValue; + @Override + public void apply(KRewrite k) { + isValue = false; + apply(k.left()); + isValue = true; + isPattern = false; + apply(k.right()); + isPattern = true; + } - @Override - public void apply(KRewrite k) { - isValue = false; - apply(k.left()); + @Override + public void apply(KApply k) { + if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#fun2") + || k.klabel().name().equals("#fun3") + || k.klabel().name().equals("#let")) { + boolean wasValue = isValue; + boolean wasPattern = isPattern; + if (isPattern) { + errors.add( + KEMException.compilerError( + "Found #fun expression in a pattern location (LHS and outside of rewrite).", k)); + } + if (k.klabel().name().equals("#fun2")) { isValue = true; - isPattern = false; - apply(k.right()); isPattern = true; + apply(k.items().get(0)); + // in well formed programs this should always reset to true and false, but we want to make + // sure we don't + // create spurious reports if this constraint was violated by the user. + isValue = wasValue; + isPattern = wasPattern; + apply(k.items().get(1)); + } else { + isPattern = true; + isValue = false; + apply(k.items().get(0)); + isPattern = false; + isValue = true; + apply(k.items().get(1)); + // in well formed programs this should always reset to true and false, but we want to make + // sure we don't + // create spurious reports if this constraint was violated by the user. + isValue = wasValue; + isPattern = wasPattern; + apply(k.items().get(2)); + } + } else { + super.apply(k); } + } - @Override - public void apply(KApply k) { - if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#fun2") || k.klabel().name().equals("#fun3") || k.klabel().name().equals("#let")) { - boolean wasValue = isValue; - boolean wasPattern = isPattern; - if (isPattern) { - errors.add(KEMException.compilerError("Found #fun expression in a pattern location (LHS and outside of rewrite).", k)); - } - if (k.klabel().name().equals("#fun2")) { - isValue = true; - isPattern = true; - apply(k.items().get(0)); - // in well formed programs this should always reset to true and false, but we want to make sure we don't - // create spurious reports if this constraint was violated by the user. - isValue = wasValue; - isPattern = wasPattern; - apply(k.items().get(1)); - } else { - isPattern = true; - isValue = false; - apply(k.items().get(0)); - isPattern = false; - isValue = true; - apply(k.items().get(1)); - // in well formed programs this should always reset to true and false, but we want to make sure we don't - // create spurious reports if this constraint was violated by the user. - isValue = wasValue; - isPattern = wasPattern; - apply(k.items().get(2)); - } - } else { - super.apply(k); - } - } - - public boolean isPattern() { - return isPattern; - } + public boolean isPattern() { + return isPattern; + } - public boolean isValue() { - return isValue; - } + public boolean isValue() { + return isValue; + } } diff --git a/kernel/src/main/java/org/kframework/compile/ProcessGroupAttributes.java b/kernel/src/main/java/org/kframework/compile/ProcessGroupAttributes.java index 6877a2a4a39..f479d367a3f 100644 --- a/kernel/src/main/java/org/kframework/compile/ProcessGroupAttributes.java +++ b/kernel/src/main/java/org/kframework/compile/ProcessGroupAttributes.java @@ -10,31 +10,31 @@ import scala.util.Either; /** - * A pass which handles all "user group" attributes. Specifically, - * the attribute [group(att1,...,attN)] is replaced with the underlying attributes [att1,...,attN]. + * A pass which handles all "user group" attributes. Specifically, the attribute + * [group(att1,...,attN)] is replaced with the underlying attributes [att1,...,attN]. */ public class ProcessGroupAttributes { - public static Att getProcessedAtt(Att att, HasLocation node) { - Either newAttOrError = att.withGroupAttAsUserGroups(); - if (newAttOrError.isLeft()) { - throw KEMException.compilerError(newAttOrError.left().get(), node); - } - Att newAtt = newAttOrError.right().get(); - return newAtt; + public static Att getProcessedAtt(Att att, HasLocation node) { + Either newAttOrError = att.withGroupAttAsUserGroups(); + if (newAttOrError.isLeft()) { + throw KEMException.compilerError(newAttOrError.left().get(), node); } + Att newAtt = newAttOrError.right().get(); + return newAtt; + } - public static void apply(Module m) { - m.setAttributes(getProcessedAtt(m.getAttributes(), m)); - m.getItems().stream() - .filter((modItem) -> modItem instanceof Syntax) - .flatMap((s) -> ((Syntax) s).getPriorityBlocks().stream()) - .flatMap((pb) -> pb.getProductions().stream()) - .forEach((p) -> p.setAttributes(getProcessedAtt(p.getAttributes(), p))); - } + public static void apply(Module m) { + m.setAttributes(getProcessedAtt(m.getAttributes(), m)); + m.getItems().stream() + .filter((modItem) -> modItem instanceof Syntax) + .flatMap((s) -> ((Syntax) s).getPriorityBlocks().stream()) + .flatMap((pb) -> pb.getProductions().stream()) + .forEach((p) -> p.setAttributes(getProcessedAtt(p.getAttributes(), p))); + } - public static void apply(Definition d) { - d.getItems().stream() - .filter((item) -> item instanceof Module) - .forEach((m) -> apply((Module) m)); - } + public static void apply(Definition d) { + d.getItems().stream() + .filter((item) -> item instanceof Module) + .forEach((m) -> apply((Module) m)); + } } diff --git a/kernel/src/main/java/org/kframework/compile/PropagateMacro.java b/kernel/src/main/java/org/kframework/compile/PropagateMacro.java index 7eeb05b5432..2d6d7ce72e7 100644 --- a/kernel/src/main/java/org/kframework/compile/PropagateMacro.java +++ b/kernel/src/main/java/org/kframework/compile/PropagateMacro.java @@ -7,18 +7,24 @@ import org.kframework.definition.Sentence; /** - * Propagate macro, macro-rec, alias, and alias-rec labels from productions to rules that only contain that klabel on the LHS - * This prepares rules for macro expansion in ExpandMacros. - * There is one exception: simplification rules are meant to be used for the haskell backend and macros should not be propagated - * to these rules. + * Propagate macro, macro-rec, alias, and alias-rec labels from productions to rules that only + * contain that klabel on the LHS This prepares rules for macro expansion in ExpandMacros. There is + * one exception: simplification rules are meant to be used for the haskell backend and macros + * should not be propagated to these rules. */ public record PropagateMacro(Module m) { - public Sentence propagate(Sentence s) { - if (s instanceof Rule && m.ruleLhsHasMacroKLabel((Rule) s) && !s.att().contains(Att.SIMPLIFICATION())) { - Att macroAtt = m.attributesFor().apply(m.matchKLabel((Rule) s)); - return Rule.apply(((Rule) s).body(), ((Rule) s).requires(), ((Rule) s).ensures(), s.att().add(macroAtt.getMacro().get())); - } - return s; + public Sentence propagate(Sentence s) { + if (s instanceof Rule + && m.ruleLhsHasMacroKLabel((Rule) s) + && !s.att().contains(Att.SIMPLIFICATION())) { + Att macroAtt = m.attributesFor().apply(m.matchKLabel((Rule) s)); + return Rule.apply( + ((Rule) s).body(), + ((Rule) s).requires(), + ((Rule) s).ensures(), + s.att().add(macroAtt.getMacro().get())); } + return s; + } } diff --git a/kernel/src/main/java/org/kframework/compile/RefreshRules.java b/kernel/src/main/java/org/kframework/compile/RefreshRules.java index d7b6f5622f2..c7328079f82 100644 --- a/kernel/src/main/java/org/kframework/compile/RefreshRules.java +++ b/kernel/src/main/java/org/kframework/compile/RefreshRules.java @@ -1,11 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; -import org.kframework.attributes.Att; -import org.kframework.definition.Rule; -import org.kframework.kore.K; -import org.kframework.kore.KVariable; -import org.kframework.kore.TransformK; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; import java.util.Collection; import java.util.HashMap; @@ -14,77 +11,78 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; +import org.kframework.attributes.Att; +import org.kframework.definition.Rule; +import org.kframework.kore.K; +import org.kframework.kore.KVariable; +import org.kframework.kore.TransformK; /** - * refreshes variable names in terms and sentences according to alpha equivalence. - * Variables that have previously been refreshed are not normalized on succeeding passes, - * allowing the user to fine-tune the applyRefresh process such that arbitrary subterms can share - * a common prefix. + * refreshes variable names in terms and sentences according to alpha equivalence. Variables that + * have previously been refreshed are not normalized on succeeding passes, allowing the user to + * fine-tune the applyRefresh process such that arbitrary subterms can share a common prefix. */ public class RefreshRules { - private final Set avoidVars; - private int counter = 0; - private final Map vars = new HashMap<>(); - - public RefreshRules(Set avoidVars) { - this.avoidVars = avoidVars; - } - - /** - * Refreshes a rule - * @param rule The rule to be refreshed. - * @return The refreshed version of {@code rule}, in which each variable - * is alpha-renamed to fresh variable. - * name. - */ - public static Rule refresh(Rule rule) { - return new RefreshRules(new HashSet<>()).applyRefresh(rule); - } + private final Set avoidVars; + private int counter = 0; + private final Map vars = new HashMap<>(); - /** - * Refreshes a set of rules such that no two rules would have variables in common. - * @param rules The rules to be refreshed. - * @return The refreshed version of {@code rules} - */ - public static Collection refresh(Collection rules, Set avoidVars) { - RefreshRules refreshRules = new RefreshRules(avoidVars); - return rules.stream().map(refreshRules::applyRefreshResetVars).collect(Collectors.toCollection(LinkedList::new)); - } + public RefreshRules(Set avoidVars) { + this.avoidVars = avoidVars; + } - private Rule applyRefresh(Rule rule) { - return Rule( - applyRefresh(rule.body()), - applyRefresh(rule.requires()), - applyRefresh(rule.ensures()), - rule.att()); - } + /** + * Refreshes a rule + * + * @param rule The rule to be refreshed. + * @return The refreshed version of {@code rule}, in which each variable is alpha-renamed to fresh + * variable. name. + */ + public static Rule refresh(Rule rule) { + return new RefreshRules(new HashSet<>()).applyRefresh(rule); + } - private Rule applyRefreshResetVars(Rule rule) { - vars.clear(); - return applyRefresh(rule); - } + /** + * Refreshes a set of rules such that no two rules would have variables in common. + * + * @param rules The rules to be refreshed. + * @return The refreshed version of {@code rules} + */ + public static Collection refresh(Collection rules, Set avoidVars) { + RefreshRules refreshRules = new RefreshRules(avoidVars); + return rules.stream() + .map(refreshRules::applyRefreshResetVars) + .collect(Collectors.toCollection(LinkedList::new)); + } - private K applyRefresh(K term) { - return new TransformK() { - @Override - public K apply(KVariable var) { - if (var.att().contains(Att.REFRESHED())) - return var; - if (!vars.containsKey(var)) { - String newVarName; - do { - newVarName = "_Gen" + counter++; - } while (avoidVars.contains(newVarName)); - vars.put(var, newVarName); - } - return KVariable(vars.get(var), var.att().add(Att.REFRESHED(), var.name())); - } - }.apply(term); - } + private Rule applyRefresh(Rule rule) { + return Rule( + applyRefresh(rule.body()), + applyRefresh(rule.requires()), + applyRefresh(rule.ensures()), + rule.att()); + } + private Rule applyRefreshResetVars(Rule rule) { + vars.clear(); + return applyRefresh(rule); + } + private K applyRefresh(K term) { + return new TransformK() { + @Override + public K apply(KVariable var) { + if (var.att().contains(Att.REFRESHED())) return var; + if (!vars.containsKey(var)) { + String newVarName; + do { + newVarName = "_Gen" + counter++; + } while (avoidVars.contains(newVarName)); + vars.put(var, newVarName); + } + return KVariable(vars.get(var), var.att().add(Att.REFRESHED(), var.name())); + } + }.apply(term); + } } diff --git a/kernel/src/main/java/org/kframework/compile/RemoveUnit.java b/kernel/src/main/java/org/kframework/compile/RemoveUnit.java index 4a9c3e96caa..7287e4f0e1b 100644 --- a/kernel/src/main/java/org/kframework/compile/RemoveUnit.java +++ b/kernel/src/main/java/org/kframework/compile/RemoveUnit.java @@ -1,6 +1,11 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.stream.Stream; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.definition.Module; @@ -9,23 +14,19 @@ import org.kframework.definition.Sentence; import org.kframework.kore.*; import org.kframework.utils.errorsystem.KEMException; - -import java.util.HashSet; -import java.util.stream.Stream; - import scala.collection.Set; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; -import static org.kframework.Collections.*; - public class RemoveUnit { private Module m; public Module apply(Module module) { m = module; - return Module(module.name(), module.imports(), stream(module.localSentences()).flatMap(this::gen).collect(Collections.toSet()), module.att()); + return Module( + module.name(), + module.imports(), + stream(module.localSentences()).flatMap(this::gen).collect(Collections.toSet()), + module.att()); } private Stream gen(Sentence s) { @@ -44,16 +45,16 @@ private K flattenLists(K k) { public K apply(KApply k) { Production p; if (m.productionsFor().contains(k.klabel())) { - Set s = m.productionsFor().get(k.klabel()).get(); - assert s.size() == 1; // There should only be one production for this label - p = s.head(); + Set s = m.productionsFor().get(k.klabel()).get(); + assert s.size() == 1; // There should only be one production for this label + p = s.head(); } else { - return super.apply(k); + return super.apply(k); } Att att = p.att(); // Ignore optional cells, which have a unit attribute but no assoc - if ( att.contains(Att.CELL()) + if (att.contains(Att.CELL()) && att.contains(Att.MULTIPLICITY()) && att.get(Att.MULTIPLICITY()).equals("?")) { return super.apply(k); @@ -61,9 +62,13 @@ public K apply(KApply k) { if (att.contains(Att.UNIT())) { if (!att.contains(Att.ASSOC())) { - throw KEMException.internalError("Unimplemented case when removing unit applications: unit attribute but no assoc", p); + throw KEMException.internalError( + "Unimplemented case when removing unit applications: unit attribute but no assoc", + p); } - return Assoc.flatten(k.klabel(), k.items(), m).stream().reduce((k1, k2) -> KApply(k.klabel(), k1, k2)).orElse(KApply(KLabel(att.get(Att.UNIT())))); + return Assoc.flatten(k.klabel(), k.items(), m).stream() + .reduce((k1, k2) -> KApply(k.klabel(), k1, k2)) + .orElse(KApply(KLabel(att.get(Att.UNIT())))); } return super.apply(k); } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveAnonVar.java b/kernel/src/main/java/org/kframework/compile/ResolveAnonVar.java index bfaef719619..ff89efaceee 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveAnonVar.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveAnonVar.java @@ -1,6 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.attributes.Location; import org.kframework.attributes.Source; @@ -10,134 +15,125 @@ import org.kframework.definition.Sentence; import org.kframework.kore.*; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - public class ResolveAnonVar { - public static KVariable ANON_VAR = KVariable("_"); - public static KVariable FRESH_ANON_VAR = KVariable("?_"); - public static KVariable FRESH_ANON_CONSTANT = KVariable("!_"); - public static KVariable FRESH_LIST_VAR = KVariable("@_"); - - public static boolean isAnonVar(KVariable var) { - return var.equals(ANON_VAR) || var.equals(FRESH_ANON_VAR) || var.equals(FRESH_ANON_CONSTANT) || var.equals(FRESH_LIST_VAR); - } - - public static boolean isAnonVarOrNamedAnonVar(KVariable var) { - return var.name().startsWith(ANON_VAR.name()) - || var.name().startsWith(FRESH_ANON_VAR.name()) - || var.name().startsWith(FRESH_ANON_CONSTANT.name()) - || var.name().startsWith(FRESH_LIST_VAR.name()); - } - - - private final Set vars = new HashSet<>(); - - void resetVars() { - vars.clear(); - counter = 0; + public static KVariable ANON_VAR = KVariable("_"); + public static KVariable FRESH_ANON_VAR = KVariable("?_"); + public static KVariable FRESH_ANON_CONSTANT = KVariable("!_"); + public static KVariable FRESH_LIST_VAR = KVariable("@_"); + + public static boolean isAnonVar(KVariable var) { + return var.equals(ANON_VAR) + || var.equals(FRESH_ANON_VAR) + || var.equals(FRESH_ANON_CONSTANT) + || var.equals(FRESH_LIST_VAR); + } + + public static boolean isAnonVarOrNamedAnonVar(KVariable var) { + return var.name().startsWith(ANON_VAR.name()) + || var.name().startsWith(FRESH_ANON_VAR.name()) + || var.name().startsWith(FRESH_ANON_CONSTANT.name()) + || var.name().startsWith(FRESH_LIST_VAR.name()); + } + + private final Set vars = new HashSet<>(); + + void resetVars() { + vars.clear(); + counter = 0; + } + + private RuleOrClaim resolve(RuleOrClaim rule) { + resetVars(); + gatherVars(rule.body()); + gatherVars(rule.requires()); + gatherVars(rule.ensures()); + return rule.newInstance( + transform(rule.body()), transform(rule.requires()), transform(rule.ensures()), rule.att()); + } + + private Context resolve(Context context) { + resetVars(); + gatherVars(context.body()); + gatherVars(context.requires()); + return new Context(transform(context.body()), transform(context.requires()), context.att()); + } + + private ContextAlias resolve(ContextAlias context) { + resetVars(); + gatherVars(context.body()); + gatherVars(context.requires()); + return new ContextAlias( + transform(context.body()), transform(context.requires()), context.att()); + } + + public K resolveK(K k) { + resetVars(); + gatherVars(k); + return transform(k); + } + + public synchronized Sentence resolve(Sentence s) { + if (s instanceof RuleOrClaim) { + return resolve((RuleOrClaim) s); + } else if (s instanceof Context) { + return resolve((Context) s); + } else if (s instanceof ContextAlias) { + return resolve((ContextAlias) s); + } else { + return s; } - - private RuleOrClaim resolve(RuleOrClaim rule) { - resetVars(); - gatherVars(rule.body()); - gatherVars(rule.requires()); - gatherVars(rule.ensures()); - return rule.newInstance( - transform(rule.body()), - transform(rule.requires()), - transform(rule.ensures()), - rule.att()); - } - - private Context resolve(Context context) { - resetVars(); - gatherVars(context.body()); - gatherVars(context.requires()); - return new Context( - transform(context.body()), - transform(context.requires()), - context.att()); - } - - private ContextAlias resolve(ContextAlias context) { - resetVars(); - gatherVars(context.body()); - gatherVars(context.requires()); - return new ContextAlias( - transform(context.body()), - transform(context.requires()), - context.att()); - } - - public K resolveK(K k) { - resetVars(); - gatherVars(k); - return transform(k); - } - - public synchronized Sentence resolve(Sentence s) { - if (s instanceof RuleOrClaim) { - return resolve((RuleOrClaim) s); - } else if (s instanceof Context) { - return resolve((Context) s); - } else if (s instanceof ContextAlias) { - return resolve((ContextAlias) s); - } else { - return s; + } + + void gatherVars(K term) { + new VisitK() { + @Override + public void apply(KVariable v) { + vars.add(v); + super.apply(v); + } + }.apply(term); + } + + K transform(K term) { + return new TransformK() { + @Override + public K apply(KVariable k) { + if (ANON_VAR.equals(k)) { + return newDotVariable("", k); } - } - - void gatherVars(K term) { - new VisitK() { - @Override - public void apply(KVariable v) { - vars.add(v); - super.apply(v); - } - }.apply(term); - } + if (FRESH_ANON_VAR.equals(k)) { + return newDotVariable("?", k); + } + if (FRESH_ANON_CONSTANT.equals(k)) { + return newDotVariable("!", k); + } + if (FRESH_LIST_VAR.equals(k)) { + return newDotVariable("@", k); + } + return super.apply(k); + } + }.apply(term); + } - K transform(K term) { - return new TransformK() { - @Override - public K apply(KVariable k) { - if (ANON_VAR.equals(k)) { - return newDotVariable("", k); - } - if (FRESH_ANON_VAR.equals(k)) { - return newDotVariable("?", k); - } - if (FRESH_ANON_CONSTANT.equals(k)) { - return newDotVariable("!", k); - } - if (FRESH_LIST_VAR.equals(k)) { - return newDotVariable("@", k); - } - return super.apply(k); - } - }.apply(term); - } + private int counter = 0; - private int counter = 0; - KVariable newDotVariable(String prefix, K k) { - KVariable newLabel; - Att locInfo = Optional.of(Att()) + KVariable newDotVariable(String prefix, K k) { + KVariable newLabel; + Att locInfo = + Optional.of(Att()) .flatMap(att -> k.att().getOptional(Source.class).map(s -> att.add(Source.class, s))) - .flatMap(att -> k.att().getOptional(Location.class).map(l -> att.add(Location.class, l))).orElse(Att()); - Att att = Att().add(Att.ANONYMOUS()).addAll(locInfo); - if (prefix.equals("?")) { - att = att.add(Att.FRESH()); - } - do { - newLabel = KVariable(prefix + "_Gen" + (counter++), att); - } while (vars.contains(newLabel)); - vars.add(newLabel); - return newLabel; + .flatMap( + att -> k.att().getOptional(Location.class).map(l -> att.add(Location.class, l))) + .orElse(Att()); + Att att = Att().add(Att.ANONYMOUS()).addAll(locInfo); + if (prefix.equals("?")) { + att = att.add(Att.FRESH()); } - + do { + newLabel = KVariable(prefix + "_Gen" + (counter++), att); + } while (vars.contains(newLabel)); + vars.add(newLabel); + return newLabel; + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveComm.java b/kernel/src/main/java/org/kframework/compile/ResolveComm.java index d393b267e5b..b5ed68806c4 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveComm.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveComm.java @@ -1,7 +1,14 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.immutable; +import static org.kframework.Collections.stream; +import static org.kframework.definition.Constructors.Module; + import com.google.common.collect.Lists; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.attributes.Att; import org.kframework.attributes.Location; import org.kframework.attributes.Source; @@ -15,60 +22,75 @@ import org.kframework.utils.errorsystem.KException; import org.kframework.utils.errorsystem.KExceptionManager; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.immutable; -import static org.kframework.Collections.stream; -import static org.kframework.definition.Constructors.Module; - public record ResolveComm(KExceptionManager kem) { - - public Module resolve(Module m) { - // generate a duplicate simplification rule for symbols that are labeled as `comm` - // remove this attribute from the rules because the Haskell Backend has a different meaning for it - Set commSimpRules = stream(m.localSentences()) - .filter(s -> s instanceof Rule && s.att().contains(Att.SIMPLIFICATION()) && s.att().contains(Att.COMM())) - .collect(Collectors.toSet()); - Set commRulesToAdd = commSimpRules.stream() - .flatMap(s -> { - Rule r = (Rule) s; - K newBody = genCommRule(r.body(), m); - if (!newBody.equals(r.body())) - return Stream.of( - Rule.apply(newBody, r.requires(), r.ensures(), r.att().remove(Att.COMM())), - Rule.apply(r.body(), r.requires(), r.ensures(), r.att().remove(Att.COMM()))); - return Stream.of(Rule.apply(r.body(), r.requires(), r.ensures(), r.att().remove(Att.COMM()))); + public Module resolve(Module m) { + // generate a duplicate simplification rule for symbols that are labeled as `comm` + // remove this attribute from the rules because the Haskell Backend has a different meaning for + // it + Set commSimpRules = + stream(m.localSentences()) + .filter( + s -> + s instanceof Rule + && s.att().contains(Att.SIMPLIFICATION()) + && s.att().contains(Att.COMM())) + .collect(Collectors.toSet()); + Set commRulesToAdd = + commSimpRules.stream() + .flatMap( + s -> { + Rule r = (Rule) s; + K newBody = genCommRule(r.body(), m); + if (!newBody.equals(r.body())) + return Stream.of( + Rule.apply(newBody, r.requires(), r.ensures(), r.att().remove(Att.COMM())), + Rule.apply( + r.body(), r.requires(), r.ensures(), r.att().remove(Att.COMM()))); + return Stream.of( + Rule.apply(r.body(), r.requires(), r.ensures(), r.att().remove(Att.COMM()))); }) - .collect(Collectors.toSet()); - return Module(m.name(), m.imports(), m.localSentences().$minus$minus(immutable(commSimpRules)).$bar(immutable(commRulesToAdd)).seq(), m.att()); - } + .collect(Collectors.toSet()); + return Module( + m.name(), + m.imports(), + m.localSentences() + .$minus$minus(immutable(commSimpRules)) + .$bar(immutable(commRulesToAdd)) + .seq(), + m.att()); + } - public K genCommRule(K body, Module m) { - return new RewriteAwareTransformer(true) { - @Override - public K apply(KApply k) { - if (k.klabel().name().equals("#withConfig")) { - return super.apply(k); - } - if ((isRHS() && !isLHS()) || k.klabel() instanceof KVariable || !m.attributesFor().contains(k.klabel())) { - return k; - } - Att attributes = m.attributesFor().apply(k.klabel()); - if (attributes.contains(Att.COMM())) { - return KORE.KApply( - k.klabel(), - KORE.KList(Lists.newArrayList(k.klist().items().get(1), k.klist().items().get(0))), - k.att()); - } else - kem.addKException(new KException(KException.ExceptionType.ERROR, KException.KExceptionGroup.COMPILER, - "Used 'comm' attribute on simplification rule but " + k.klabel().name() + " is not comm.", - k.att().getOptional(Source.class).orElse(null), - k.att().getOptional(Location.class).orElse(null))); - return k; - } - }.apply(body); - } + public K genCommRule(K body, Module m) { + return new RewriteAwareTransformer(true) { + @Override + public K apply(KApply k) { + if (k.klabel().name().equals("#withConfig")) { + return super.apply(k); + } + if ((isRHS() && !isLHS()) + || k.klabel() instanceof KVariable + || !m.attributesFor().contains(k.klabel())) { + return k; + } + Att attributes = m.attributesFor().apply(k.klabel()); + if (attributes.contains(Att.COMM())) { + return KORE.KApply( + k.klabel(), + KORE.KList(Lists.newArrayList(k.klist().items().get(1), k.klist().items().get(0))), + k.att()); + } else + kem.addKException( + new KException( + KException.ExceptionType.ERROR, + KException.KExceptionGroup.COMPILER, + "Used 'comm' attribute on simplification rule but " + + k.klabel().name() + + " is not comm.", + k.att().getOptional(Source.class).orElse(null), + k.att().getOptional(Location.class).orElse(null))); + return k; + } + }.apply(body); + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveContexts.java b/kernel/src/main/java/org/kframework/compile/ResolveContexts.java index ba21995981b..f4dabc8edae 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveContexts.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveContexts.java @@ -1,6 +1,19 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; @@ -19,307 +32,320 @@ import org.kframework.kore.KLabel; import org.kframework.kore.KRewrite; import org.kframework.kore.KVariable; -import org.kframework.kore.VisitK; import org.kframework.kore.TransformK; +import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - public class ResolveContexts { - private final KompileOptions kompileOptions; - - public ResolveContexts(KompileOptions kompileOptions) { - this.kompileOptions = kompileOptions; - } - - public Definition resolve(Definition d) { - klabels = new HashSet<>(); - Module transformedMainModule = resolve(d.mainModule()); - return Definition.apply(transformedMainModule, add(transformedMainModule, minus(d.mainModule(), d.entryModules())), d.att()); + private final KompileOptions kompileOptions; + + public ResolveContexts(KompileOptions kompileOptions) { + this.kompileOptions = kompileOptions; + } + + public Definition resolve(Definition d) { + klabels = new HashSet<>(); + Module transformedMainModule = resolve(d.mainModule()); + return Definition.apply( + transformedMainModule, + add(transformedMainModule, minus(d.mainModule(), d.entryModules())), + d.att()); + } + + public Module resolve(Module input) { + Set rulesToAdd = + stream(input.sentences()) + .filter(s -> s instanceof Context) + .map(s -> (Context) s) + .flatMap(c -> this.resolve(c, input)) + .collect(Collectors.toCollection(HashSet::new)); + if (!rulesToAdd.isEmpty()) { + rulesToAdd.add(SyntaxSort(Seq(), Sorts.K())); } - - public Module resolve(Module input) { - Set rulesToAdd = stream(input.sentences()) - .filter(s -> s instanceof Context) - .map(s -> (Context) s) - .flatMap(c -> this.resolve(c, input)).collect(Collectors.toCollection(HashSet::new)); - if (!rulesToAdd.isEmpty()) { - rulesToAdd.add(SyntaxSort(Seq(), Sorts.K())); - } - return Module(input.name(), input.imports(), (scala.collection.Set) stream(input.localSentences()).filter(s -> !(s instanceof Context)).collect(Collections.toSet()).$bar(immutable(rulesToAdd)), input.att()); + return Module( + input.name(), + input.imports(), + (scala.collection.Set) + stream(input.localSentences()) + .filter(s -> !(s instanceof Context)) + .collect(Collections.toSet()) + .$bar(immutable(rulesToAdd)), + input.att()); + } + + private Set klabels; + + private KLabel getUniqueFreezerLabel(Module input, String nameHint) { + if (klabels.isEmpty()) { + klabels.addAll(mutable(input.definedKLabels())); } - - private Set klabels; - - private KLabel getUniqueFreezerLabel(Module input, String nameHint) { - if (klabels.isEmpty()) { - klabels.addAll(mutable(input.definedKLabels())); - } - int counter = 0; - KLabel freezer; - do { - freezer = KLabel("#freezer" + nameHint + "_" + (counter++ == 0 ? "" : counter)); - } while (klabels.contains(freezer)); - klabels.add(freezer); - return freezer; + int counter = 0; + KLabel freezer; + do { + freezer = KLabel("#freezer" + nameHint + "_" + (counter++ == 0 ? "" : counter)); + } while (klabels.contains(freezer)); + klabels.add(freezer); + return freezer; + } + + private Att addSuffixToLabel(Att a, String suffix) { + if (!a.contains(Att.LABEL())) { + return a; } - - private Att addSuffixToLabel(Att a, String suffix) { - if (!a.contains(Att.LABEL())) { - return a; - } - return a.add(Att.LABEL(), a.get(Att.LABEL()) + suffix); - } - - private Stream resolve(Context context, Module input) { - checkContextValidity(context); - final SortedMap vars = new TreeMap<>((v1, v2) -> v1.name().compareTo(v2.name())); - K body = context.body(); - K requiresHeat = context.requires(); - K requiresCool = BooleanUtils.TRUE; - - int[] currentHolePosition = new int[] { 0 }; - int[] finalHolePosition = new int[] { 0 }; - // does this context have a main cell? - boolean hasMainCell = new FoldK() { - @Override - public Boolean apply(KApply k) { - if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { - return true; - } - return super.apply(k); + return a.add(Att.LABEL(), a.get(Att.LABEL()) + suffix); + } + + private Stream resolve(Context context, Module input) { + checkContextValidity(context); + final SortedMap vars = new TreeMap<>((v1, v2) -> v1.name().compareTo(v2.name())); + K body = context.body(); + K requiresHeat = context.requires(); + K requiresCool = BooleanUtils.TRUE; + + int[] currentHolePosition = new int[] {0}; + int[] finalHolePosition = new int[] {0}; + // does this context have a main cell? + boolean hasMainCell = + new FoldK() { + @Override + public Boolean apply(KApply k) { + if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { + return true; } + return super.apply(k); + } - @Override - public Boolean unit() { - return false; - } + @Override + public Boolean unit() { + return false; + } - @Override - public Boolean merge(Boolean a, Boolean b) { - return a || b; - } + @Override + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } }.apply(body); - // Find a heated hole - // e.g., context ++(HOLE => lvalue(HOLE)) - K heated = new VisitK() { - K heated; - KVariable holeVar; - boolean inMainCell = false; - - public K process(K k) { - apply(k); - if (heated != null) - return heated; - else - return holeVar; - } + // Find a heated hole + // e.g., context ++(HOLE => lvalue(HOLE)) + K heated = + new VisitK() { + K heated; + KVariable holeVar; + boolean inMainCell = false; + + public K process(K k) { + apply(k); + if (heated != null) return heated; + else return holeVar; + } - @Override - public void apply(KRewrite k) { - heated = k.right(); - super.apply(k); - } + @Override + public void apply(KRewrite k) { + heated = k.right(); + super.apply(k); + } - @Override - public void apply(KVariable k) { - if (inMainCell || !hasMainCell) { - if (!k.name().equals("HOLE")) { - vars.put(k, k); - currentHolePosition[0]++; - } else { - holeVar = k; - finalHolePosition[0] = currentHolePosition[0]; - } - } - super.apply(k); + @Override + public void apply(KVariable k) { + if (inMainCell || !hasMainCell) { + if (!k.name().equals("HOLE")) { + vars.put(k, k); + currentHolePosition[0]++; + } else { + holeVar = k; + finalHolePosition[0] = currentHolePosition[0]; + } } + super.apply(k); + } - @Override - public void apply(KApply k) { - if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { - inMainCell = true; - } - if (k.klabel() instanceof KVariable && (inMainCell || !hasMainCell)) - vars.put((KVariable) k.klabel(), InjectedKLabel(k.klabel())); - super.apply(k); - if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { - inMainCell = false; - } + @Override + public void apply(KApply k) { + if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { + inMainCell = true; } - }.process(body); - K cooled = new VisitK() { - K cooled; - public K process(K k) { - apply(k); - if (cooled != null) - return cooled; - else - return k; + if (k.klabel() instanceof KVariable && (inMainCell || !hasMainCell)) + vars.put((KVariable) k.klabel(), InjectedKLabel(k.klabel())); + super.apply(k); + if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { + inMainCell = false; } + } + }.process(body); + K cooled = + new VisitK() { + K cooled; + + public K process(K k) { + apply(k); + if (cooled != null) return cooled; + else return k; + } - @Override - public void apply(KApply k) { - if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { - cooled = k.items().get(1); - } - super.apply(k); + @Override + public void apply(KApply k) { + if (input.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { + cooled = k.items().get(1); } + super.apply(k); + } }.process(RewriteToTop.toLeft(body)); - // TODO(dwightguth): generate freezers better for pretty-printing purposes - List items = new ArrayList<>(); - KLabel freezerLabel; - if (cooled instanceof KApply kApply) { - String name = kApply.klabel().name(); - if (name.equals("#SemanticCastToK")) { - K firstArg = kApply.klist().items().get(0); - if (firstArg instanceof KApply) - name = ((KApply)firstArg).klabel().name(); - } - freezerLabel = getUniqueFreezerLabel(input, name + finalHolePosition[0]); - } else { - freezerLabel = getUniqueFreezerLabel(input, ""); - } - items.add(Terminal(freezerLabel.name())); - items.add(Terminal("(")); - for (int i = 0; i < vars.size(); i++) { - items.add(NonTerminal(Sorts.K())); - items.add(Terminal(",")); - } - if (vars.size() > 0) { - items.remove(items.size() - 1); - } - items.add(Terminal(")")); - Production freezer = Production(freezerLabel, Sorts.KItem(), immutable(items), Att()); - K frozen = KApply(freezerLabel, vars.values().stream().collect(Collections.toList())); - - Att heatAtt = addSuffixToLabel(context.att().add(Att.HEAT()), "-heat"); - Att coolAtt = addSuffixToLabel(context.att().add(Att.COOL()), "-cool"); - - Function throwException = label -> { - Sentence loc = input.labeled().get(label).get().head(); - throw KEMException.compilerError("The generated label for a context rule conflicts with a user-defined label at " - + loc.source().get() + " and " - + loc.location().get() + ". Please consider renaming.", context); + // TODO(dwightguth): generate freezers better for pretty-printing purposes + List items = new ArrayList<>(); + KLabel freezerLabel; + if (cooled instanceof KApply kApply) { + String name = kApply.klabel().name(); + if (name.equals("#SemanticCastToK")) { + K firstArg = kApply.klist().items().get(0); + if (firstArg instanceof KApply) name = ((KApply) firstArg).klabel().name(); + } + freezerLabel = getUniqueFreezerLabel(input, name + finalHolePosition[0]); + } else { + freezerLabel = getUniqueFreezerLabel(input, ""); + } + items.add(Terminal(freezerLabel.name())); + items.add(Terminal("(")); + for (int i = 0; i < vars.size(); i++) { + items.add(NonTerminal(Sorts.K())); + items.add(Terminal(",")); + } + if (vars.size() > 0) { + items.remove(items.size() - 1); + } + items.add(Terminal(")")); + Production freezer = Production(freezerLabel, Sorts.KItem(), immutable(items), Att()); + K frozen = KApply(freezerLabel, vars.values().stream().collect(Collections.toList())); + + Att heatAtt = addSuffixToLabel(context.att().add(Att.HEAT()), "-heat"); + Att coolAtt = addSuffixToLabel(context.att().add(Att.COOL()), "-cool"); + + Function throwException = + label -> { + Sentence loc = input.labeled().get(label).get().head(); + throw KEMException.compilerError( + "The generated label for a context rule conflicts with a user-defined label at " + + loc.source().get() + + " and " + + loc.location().get() + + ". Please consider renaming.", + context); }; - if (heatAtt.contains(Att.LABEL())) { - String label = heatAtt.get(Att.LABEL()); - if (input.labeled().contains(label)) { - throwException.apply(label); - } - } - - if (coolAtt.contains(Att.LABEL())) { - String label = coolAtt.get(Att.LABEL()); - if (input.labeled().contains(label)) { - throwException.apply(label); - } - } - - - return Stream.of(freezer, - Rule(insert(body, KRewrite(cooled, KSequence(heated, frozen)), input), requiresHeat, BooleanUtils.TRUE, heatAtt), - Rule(insert(body, KRewrite(KSequence(heated, frozen), cooled), input), requiresCool, BooleanUtils.TRUE, coolAtt)); + if (heatAtt.contains(Att.LABEL())) { + String label = heatAtt.get(Att.LABEL()); + if (input.labeled().contains(label)) { + throwException.apply(label); + } } - private K insert(K body, K rewrite, Module mod) { - class Holder { - boolean found = false; + if (coolAtt.contains(Att.LABEL())) { + String label = coolAtt.get(Att.LABEL()); + if (input.labeled().contains(label)) { + throwException.apply(label); } - Holder h = new Holder(); - K inserted = new TransformK() { + } + + return Stream.of( + freezer, + Rule( + insert(body, KRewrite(cooled, KSequence(heated, frozen)), input), + requiresHeat, + BooleanUtils.TRUE, + heatAtt), + Rule( + insert(body, KRewrite(KSequence(heated, frozen), cooled), input), + requiresCool, + BooleanUtils.TRUE, + coolAtt)); + } + + private K insert(K body, K rewrite, Module mod) { + class Holder { + boolean found = false; + } + Holder h = new Holder(); + K inserted = + new TransformK() { @Override public K apply(KApply k) { - if (mod.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { - h.found = true; - return KApply(k.klabel(), k.items().get(0), rewrite, k.items().get(2)); - } - return super.apply(k); + if (mod.attributesFor().getOrElse(k.klabel(), () -> Att()).contains(Att.MAINCELL())) { + h.found = true; + return KApply(k.klabel(), k.items().get(0), rewrite, k.items().get(2)); + } + return super.apply(k); } - }.apply(body); - if (h.found) { - return inserted; - } else { - return rewrite; - } + }.apply(body); + if (h.found) { + return inserted; + } else { + return rewrite; } - - /** - * Check validity of context. - *

- * Currently the following conditions are checked: - * - Contexts must have at least one HOLE. - * - Contexts must have a single rewrite. - * - Only the HOLE can be rewritten in a context definition. - * - * @param context to be checked - */ - public static void checkContextValidity(Context context) { - K body = context.body(); - - int cntHoles = new FindK() { - @Override - public scala.collection.Set apply(KVariable k) { - if (k.name().equals("HOLE")) { - return org.kframework.Collections.Set(k); - } else { - return super.apply(k); - } + } + + /** + * Check validity of context. + * + *

Currently the following conditions are checked: - Contexts must have at least one HOLE. - + * Contexts must have a single rewrite. - Only the HOLE can be rewritten in a context definition. + * + * @param context to be checked + */ + public static void checkContextValidity(Context context) { + K body = context.body(); + + int cntHoles = + new FindK() { + @Override + public scala.collection.Set apply(KVariable k) { + if (k.name().equals("HOLE")) { + return org.kframework.Collections.Set(k); + } else { + return super.apply(k); } + } }.apply(body).size(); - if (cntHoles < 1) { - throw KEMException.compilerError("Contexts must have at least one HOLE.", context); - } + if (cntHoles < 1) { + throw KEMException.compilerError("Contexts must have at least one HOLE.", context); + } - int cntRewrites = new FindK() { - @Override - public scala.collection.Set apply(KRewrite k) { - return this.merge(org.kframework.Collections.Set(k), super.apply(k)); - } + int cntRewrites = + new FindK() { + @Override + public scala.collection.Set apply(KRewrite k) { + return this.merge(org.kframework.Collections.Set(k), super.apply(k)); + } }.apply(body).size(); - if (cntRewrites > 1) { - throw KEMException.compilerError("Cannot compile a context with multiple rewrites.", context); - } + if (cntRewrites > 1) { + throw KEMException.compilerError("Cannot compile a context with multiple rewrites.", context); + } - new VisitK() { - @Override - public void apply(KRewrite k) { - if (!isHOLE(k.left())) { - throw KEMException.compilerError("Only the HOLE can be rewritten in a context definition", context); - } - super.apply(k); - } + new VisitK() { + @Override + public void apply(KRewrite k) { + if (!isHOLE(k.left())) { + throw KEMException.compilerError( + "Only the HOLE can be rewritten in a context definition", context); + } + super.apply(k); + } - // return true when k is either HOLE or #SemanticCastToX(HOLE) - private boolean isHOLE(K k) { - if (k instanceof KApply kapp) { - return kapp.klabel().name().startsWith("#SemanticCastTo") && - kapp.klist().size() == 1 && - isHOLEVar(kapp.klist().items().get(0)); - } else { - return isHOLEVar(k); - } - } + // return true when k is either HOLE or #SemanticCastToX(HOLE) + private boolean isHOLE(K k) { + if (k instanceof KApply kapp) { + return kapp.klabel().name().startsWith("#SemanticCastTo") + && kapp.klist().size() == 1 + && isHOLEVar(kapp.klist().items().get(0)); + } else { + return isHOLEVar(k); + } + } - private boolean isHOLEVar(K k) { - return k instanceof KVariable && ((KVariable) k).name().equals("HOLE"); - } - }.apply(body); - } + private boolean isHOLEVar(K k) { + return k instanceof KVariable && ((KVariable) k).name().equals("HOLE"); + } + }.apply(body); + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveFreshConfigConstants.java b/kernel/src/main/java/org/kframework/compile/ResolveFreshConfigConstants.java index 8f90f346b9c..60e1ebff8e2 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveFreshConfigConstants.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveFreshConfigConstants.java @@ -1,6 +1,10 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.HashMap; +import java.util.Map; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; @@ -15,76 +19,72 @@ import org.kframework.kore.TransformK; import org.kframework.utils.errorsystem.KEMException; -import java.util.HashMap; -import java.util.Map; - -import static org.kframework.kore.KORE.*; - public class ResolveFreshConfigConstants { - private int currentFresh = 0; - private final Map freshMap = new HashMap<>(); + private int currentFresh = 0; + private final Map freshMap = new HashMap<>(); - /** - * Replaces fresh variables in the RHS of cell initializer rules with a fresh constant. - * - * There is a question of whether fresh config variables with the same name but in - * different modules should generate different constants. For the sake of simplicity, and - * to allow the use case, no distinction is made between different modules. - * - * @param r The rule that initializes the cell - * @param body The KRewrite for the rule - * @return The body is returned with any fresh variables in the RHS replaced with a - * fresh constant - */ - private K transform(RuleOrClaim r, K body) { - if (!(r instanceof Rule rule)) { - return body; - } + /** + * Replaces fresh variables in the RHS of cell initializer rules with a fresh constant. + * + *

There is a question of whether fresh config variables with the same name but in different + * modules should generate different constants. For the sake of simplicity, and to allow the use + * case, no distinction is made between different modules. + * + * @param r The rule that initializes the cell + * @param body The KRewrite for the rule + * @return The body is returned with any fresh variables in the RHS replaced with a fresh constant + */ + private K transform(RuleOrClaim r, K body) { + if (!(r instanceof Rule rule)) { + return body; + } - if (!rule.att().contains(Att.INITIALIZER())) { - return body; - } + if (!rule.att().contains(Att.INITIALIZER())) { + return body; + } - return new TransformK() { - @Override - public K apply(KVariable k) { - if (k.name().startsWith("!")) { - if (!k.att().get(Sort.class).equals(Sorts.Int())) { - throw KEMException.compilerError("Can't resolve fresh configuration variable not of sort Int", k); - } - if (k.att().contains(Att.ANONYMOUS())) { - return KToken(Integer.toString(currentFresh++), Sorts.Int()); - } - if (!freshMap.containsKey(k)) { - freshMap.put(k, currentFresh++); - } - return KToken(Integer.toString(freshMap.get(k)), Sorts.Int()); - } - return k; - } + return new TransformK() { + @Override + public K apply(KVariable k) { + if (k.name().startsWith("!")) { + if (!k.att().get(Sort.class).equals(Sorts.Int())) { + throw KEMException.compilerError( + "Can't resolve fresh configuration variable not of sort Int", k); + } + if (k.att().contains(Att.ANONYMOUS())) { + return KToken(Integer.toString(currentFresh++), Sorts.Int()); + } + if (!freshMap.containsKey(k)) { + freshMap.put(k, currentFresh++); + } + return KToken(Integer.toString(freshMap.get(k)), Sorts.Int()); + } + return k; + } - @Override - public K apply(KRewrite k) { - return KRewrite(k.left(), apply(k.right()), k.att()); - } - }.apply(body); - } + @Override + public K apply(KRewrite k) { + return KRewrite(k.left(), apply(k.right()), k.att()); + } + }.apply(body); + } - public Module resolve(Module m) { - return ModuleTransformer.fromRuleBodyTransformerWithRule((r, body) -> transform(r, body), "Resolve fresh variables in cell initializers").apply(m); - } + public Module resolve(Module m) { + return ModuleTransformer.fromRuleBodyTransformerWithRule( + (r, body) -> transform(r, body), "Resolve fresh variables in cell initializers") + .apply(m); + } - /** - * Gets the number of fresh constants that were generated. - * - * This is used in the next stage of the pipeline where the generatedCounter cell is added - * to the configuration. The initializer rule for the generatedCounter will use this value - * so any fresh values during execution do not conflict with the values in the initial - * configuration. - * - * @return What the generatedCounter should be initialized to. - */ - public int getCurrentFresh() { - return currentFresh; - } + /** + * Gets the number of fresh constants that were generated. + * + *

This is used in the next stage of the pipeline where the generatedCounter cell is added to + * the configuration. The initializer rule for the generatedCounter will use this value so any + * fresh values during execution do not conflict with the values in the initial configuration. + * + * @return What the generatedCounter should be initialized to. + */ + public int getCurrentFresh() { + return currentFresh; + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveFreshConstants.java b/kernel/src/main/java/org/kframework/compile/ResolveFreshConstants.java index 41b6de448f0..aea8af8c32b 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveFreshConstants.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveFreshConstants.java @@ -1,13 +1,23 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; import org.kframework.definition.Context; import org.kframework.definition.Definition; -import org.kframework.definition.Import; import org.kframework.definition.Module; import org.kframework.definition.NonTerminal; import org.kframework.definition.Production; @@ -25,255 +35,299 @@ import org.kframework.parser.inner.ParseInModule; import org.kframework.parser.inner.RuleGrammarGenerator; import org.kframework.parser.outer.Outer; -import org.kframework.utils.StringUtil; -import org.kframework.utils.file.FileUtil; import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.file.FileUtil; +import scala.Option; import scala.collection.JavaConverters; import scala.collection.Set; -import scala.Option; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; public class ResolveFreshConstants { - private final Definition def; - private final FileUtil files; - private Module m; - private final java.util.Set freshVars = new HashSet<>(); - private final Map offsets = new HashMap<>(); - private final String manualTopCell; - private final int initialFresh; + private final Definition def; + private final FileUtil files; + private Module m; + private final java.util.Set freshVars = new HashSet<>(); + private final Map offsets = new HashMap<>(); + private final String manualTopCell; + private final int initialFresh; - private void reset() { - freshVars.clear(); - offsets.clear(); - } + private void reset() { + freshVars.clear(); + offsets.clear(); + } - private Rule resolve(Rule rule) { - reset(); - analyze(rule.body()); - analyze(rule.requires()); - analyze(rule.ensures()); - finishAnalysis(); - Rule withFresh = Rule( - addFreshCell(transform(rule.body())), - transform(rule.requires()), - transform(rule.ensures()), - rule.att()); - if (rule.att().contains(Att.INITIALIZER())) { - K left = RewriteToTop.toLeft(withFresh.body()); - if (left instanceof KApply kapp) { - if (kapp.klabel().equals(KLabels.INIT_GENERATED_TOP_CELL)) { - KApply right = (KApply)RewriteToTop.toRight(withFresh.body()); - KApply cells = (KApply)right.items().get(1); - List items = new ArrayList<>(cells.items()); - items.add(KApply(KLabels.INIT_GENERATED_COUNTER_CELL)); - KApply newCells = KApply(cells.klabel(), immutable(items)); - List rightItems = new ArrayList<>(right.items()); - rightItems.set(1, newCells); - return Rule( - KRewrite(left, KApply(right.klabel(), immutable(rightItems))), - withFresh.requires(), - withFresh.ensures(), - withFresh.att()); - } - } - } - K left = RewriteToTop.toLeft(rule.body()); - if (left instanceof KApply kapp) { - if (kapp.klabel().name().equals("#withConfig")) { - left = kapp.items().get(0); - } - if (left instanceof KApply) { - kapp = (KApply)left; - if (m.attributesFor().get(kapp.klabel()).getOrElse(() -> Att()).contains(Att.FUNCTION())) { - return rule; - } - } + private Rule resolve(Rule rule) { + reset(); + analyze(rule.body()); + analyze(rule.requires()); + analyze(rule.ensures()); + finishAnalysis(); + Rule withFresh = + Rule( + addFreshCell(transform(rule.body())), + transform(rule.requires()), + transform(rule.ensures()), + rule.att()); + if (rule.att().contains(Att.INITIALIZER())) { + K left = RewriteToTop.toLeft(withFresh.body()); + if (left instanceof KApply kapp) { + if (kapp.klabel().equals(KLabels.INIT_GENERATED_TOP_CELL)) { + KApply right = (KApply) RewriteToTop.toRight(withFresh.body()); + KApply cells = (KApply) right.items().get(1); + List items = new ArrayList<>(cells.items()); + items.add(KApply(KLabels.INIT_GENERATED_COUNTER_CELL)); + KApply newCells = KApply(cells.klabel(), immutable(items)); + List rightItems = new ArrayList<>(right.items()); + rightItems.set(1, newCells); + return Rule( + KRewrite(left, KApply(right.klabel(), immutable(rightItems))), + withFresh.requires(), + withFresh.ensures(), + withFresh.att()); } - return withFresh; + } } - - private void analyze(K term) { - new VisitK() { - @Override - public void apply(KVariable k) { - if (k.name().startsWith("!")) { - freshVars.add(k); - } - super.apply(k); - } - }.apply(term); - } - - private void finishAnalysis() { - int i = 0; - for (KVariable v : freshVars) { - offsets.put(v, i++); + K left = RewriteToTop.toLeft(rule.body()); + if (left instanceof KApply kapp) { + if (kapp.klabel().name().equals("#withConfig")) { + left = kapp.items().get(0); + } + if (left instanceof KApply) { + kapp = (KApply) left; + if (m.attributesFor().get(kapp.klabel()).getOrElse(() -> Att()).contains(Att.FUNCTION())) { + return rule; } + } } + return withFresh; + } - private static final KVariable FRESH = KVariable("#Fresh", Att.empty().add(Sort.class, Sorts.Int())); + private void analyze(K term) { + new VisitK() { + @Override + public void apply(KVariable k) { + if (k.name().startsWith("!")) { + freshVars.add(k); + } + super.apply(k); + } + }.apply(term); + } - private K transform(K term) { - return new TransformK() { - @Override - public K apply(KVariable k) { - if (freshVars.contains(k)) { - Optional s = k.att().getOptional(Sort.class); - if (!s.isPresent()) { - throw KEMException.compilerError("Fresh constant used without a declared sort.", k); - } - Option lbl = m.freshFunctionFor().get(s.get()); - if (!lbl.isDefined()) { - throw KEMException.compilerError("No fresh generator defined for sort " + s, k); - } - return KApply(lbl.get(), KApply(KLabel("_+Int_"), FRESH, KToken(offsets.get(k).toString(), Sorts.Int()))); - } - return super.apply(k); - } - }.apply(term); + private void finishAnalysis() { + int i = 0; + for (KVariable v : freshVars) { + offsets.put(v, i++); } + } + + private static final KVariable FRESH = + KVariable("#Fresh", Att.empty().add(Sort.class, Sorts.Int())); - private K addFreshCell(K body) { - if (freshVars.size() == 0) { - return body; + private K transform(K term) { + return new TransformK() { + @Override + public K apply(KVariable k) { + if (freshVars.contains(k)) { + Optional s = k.att().getOptional(Sort.class); + if (!s.isPresent()) { + throw KEMException.compilerError("Fresh constant used without a declared sort.", k); + } + Option lbl = m.freshFunctionFor().get(s.get()); + if (!lbl.isDefined()) { + throw KEMException.compilerError("No fresh generator defined for sort " + s, k); + } + return KApply( + lbl.get(), + KApply(KLabel("_+Int_"), FRESH, KToken(offsets.get(k).toString(), Sorts.Int()))); } - KApply cellTerm = IncompleteCellUtils.make(KLabels.GENERATED_COUNTER_CELL, false, KRewrite(FRESH, KApply(KLabel("_+Int_"), FRESH, KToken(Integer.toString(freshVars.size()), Sorts.Int()))), false); - return KApply(KLabels.CELLS, body, cellTerm); - } + return super.apply(k); + } + }.apply(term); + } - private Context resolve(Context context) { - reset(); - analyze(context.body()); - analyze(context.requires()); - finishAnalysis(); - return new Context( - addFreshCell(transform(context.body())), - transform(context.requires()), - context.att()); + private K addFreshCell(K body) { + if (freshVars.size() == 0) { + return body; } + KApply cellTerm = + IncompleteCellUtils.make( + KLabels.GENERATED_COUNTER_CELL, + false, + KRewrite( + FRESH, + KApply( + KLabel("_+Int_"), + FRESH, + KToken(Integer.toString(freshVars.size()), Sorts.Int()))), + false); + return KApply(KLabels.CELLS, body, cellTerm); + } - private Production resolve(Production prod) { - if (prod.klabel().isDefined() && prod.klabel().get().equals(KLabels.GENERATED_TOP_CELL)) { - List pis = stream(prod.items()).collect(Collectors.toCollection(ArrayList::new)); - // expecting a production of the form C1 C2 Cx.. - // insert the GeneratedCounterCell as the last cell - pis.add(prod.items().size() - 1, NonTerminal(Sorts.GeneratedCounterCell())); - return Production(prod.klabel().get(), prod.sort(), immutable(pis), prod.att()); - } - return prod; - } + private Context resolve(Context context) { + reset(); + analyze(context.body()); + analyze(context.requires()); + finishAnalysis(); + return new Context( + addFreshCell(transform(context.body())), transform(context.requires()), context.att()); + } - private Sentence resolve(Sentence s) { - if (s instanceof Rule) { - return resolve((Rule) s); - } else if (s instanceof Context) { - return resolve((Context) s); - } else if (s instanceof Production) { - return resolve((Production) s); - } - return s; + private Production resolve(Production prod) { + if (prod.klabel().isDefined() && prod.klabel().get().equals(KLabels.GENERATED_TOP_CELL)) { + List pis = + stream(prod.items()).collect(Collectors.toCollection(ArrayList::new)); + // expecting a production of the form C1 C2 Cx.. + // insert the GeneratedCounterCell as the last cell + pis.add(prod.items().size() - 1, NonTerminal(Sorts.GeneratedCounterCell())); + return Production(prod.klabel().get(), prod.sort(), immutable(pis), prod.att()); } + return prod; + } - public ResolveFreshConstants(Definition def, String manualTopCell, FileUtil files) { - this(def, manualTopCell, files, 0); + private Sentence resolve(Sentence s) { + if (s instanceof Rule) { + return resolve((Rule) s); + } else if (s instanceof Context) { + return resolve((Context) s); + } else if (s instanceof Production) { + return resolve((Production) s); } + return s; + } - public ResolveFreshConstants(Definition def, String manualTopCell, FileUtil files, int initialFresh) { - this.def = def; - this.manualTopCell = manualTopCell; - this.files = files; - this.initialFresh = initialFresh; - } + public ResolveFreshConstants(Definition def, String manualTopCell, FileUtil files) { + this(def, manualTopCell, files, 0); + } - public Module resolve(Module m) { - this.m = m; - Set sentences = map(this::resolve, m.localSentences()); - KToken counterCellLabel = KToken("generatedCounter", Sort("#CellName")); - KApply freshCell = KApply(KLabel("#configCell"), counterCellLabel, KApply(KLabel("#cellPropertyListTerminator")), KToken(Integer.toString(initialFresh), Sorts.Int()), counterCellLabel); + public ResolveFreshConstants( + Definition def, String manualTopCell, FileUtil files, int initialFresh) { + this.def = def; + this.manualTopCell = manualTopCell; + this.files = files; + this.initialFresh = initialFresh; + } - java.util.Set counterSentences = new HashSet<>(); - counterSentences.add(Production(KLabel("getGeneratedCounterCell"), Sorts.GeneratedCounterCell(), Seq(Terminal("getGeneratedCounterCell"), Terminal("("), NonTerminal(Sorts.GeneratedTopCell()), Terminal(")")), Att.empty().add(Att.FUNCTION()))); - counterSentences.add(Rule(KRewrite(KApply(KLabel("getGeneratedCounterCell"), IncompleteCellUtils.make(KLabels.GENERATED_TOP_CELL, true, KVariable("Cell", Att.empty().add(Sort.class, Sorts.GeneratedCounterCell())), true)), KVariable("Cell", Att.empty().add(Sort.class, Sorts.GeneratedCounterCell()))), BooleanUtils.TRUE, BooleanUtils.TRUE)); + public Module resolve(Module m) { + this.m = m; + Set sentences = map(this::resolve, m.localSentences()); + KToken counterCellLabel = KToken("generatedCounter", Sort("#CellName")); + KApply freshCell = + KApply( + KLabel("#configCell"), + counterCellLabel, + KApply(KLabel("#cellPropertyListTerminator")), + KToken(Integer.toString(initialFresh), Sorts.Int()), + counterCellLabel); - if (m.name().equals(def.mainModule().name())) { - if (!m.definedKLabels().contains(KLabels.GENERATED_TOP_CELL)) { - RuleGrammarGenerator gen = new RuleGrammarGenerator(def); - ParseInModule mod = RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(m), true, files); - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(m); - Sort topCellSort; - try { - topCellSort = configInfo.getRootCell(); - } catch (KEMException e) { - if (manualTopCell != null) { - topCellSort = Outer.parseSort(manualTopCell); - } else { - throw e; - } - } - KLabel topCellLabel = configInfo.getCellLabel(topCellSort); - Production prod = m.productionsFor().apply(topCellLabel).head(); - KToken cellName = KToken(prod.att().get(Att.CELL_NAME()), Sort("#CellName")); + java.util.Set counterSentences = new HashSet<>(); + counterSentences.add( + Production( + KLabel("getGeneratedCounterCell"), + Sorts.GeneratedCounterCell(), + Seq( + Terminal("getGeneratedCounterCell"), + Terminal("("), + NonTerminal(Sorts.GeneratedTopCell()), + Terminal(")")), + Att.empty().add(Att.FUNCTION()))); + counterSentences.add( + Rule( + KRewrite( + KApply( + KLabel("getGeneratedCounterCell"), + IncompleteCellUtils.make( + KLabels.GENERATED_TOP_CELL, + true, + KVariable( + "Cell", Att.empty().add(Sort.class, Sorts.GeneratedCounterCell())), + true)), + KVariable("Cell", Att.empty().add(Sort.class, Sorts.GeneratedCounterCell()))), + BooleanUtils.TRUE, + BooleanUtils.TRUE)); - KToken topCellToken = KToken(KLabels.GENERATED_TOP_CELL_NAME, Sort("#CellName")); - K generatedTop = KApply(KLabel("#configCell"), topCellToken, KApply(KLabel("#cellPropertyListTerminator")), KApply(KLabels.CELLS, KApply(KLabel("#externalCell"), cellName), freshCell), topCellToken); - Set newSentences = GenerateSentencesFromConfigDecl.gen(generatedTop, BooleanUtils.TRUE, Att.empty(), mod.getExtensionModule()); - sentences = (Set) sentences.$bar(newSentences); - sentences = (Set) sentences.$bar(immutable(counterSentences)); - } - } - if (m.localKLabels().contains(KLabels.GENERATED_TOP_CELL)) { - RuleGrammarGenerator gen = new RuleGrammarGenerator(def); - ParseInModule mod = RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(m), true, files); - Set newSentences = GenerateSentencesFromConfigDecl.gen(freshCell, BooleanUtils.TRUE, Att.empty(), mod.getExtensionModule()); - sentences = (Set) sentences.$bar(newSentences); - sentences = (Set) sentences.$bar(immutable(counterSentences)); - } - if (sentences.equals(m.localSentences())) { - return m; + if (m.name().equals(def.mainModule().name())) { + if (!m.definedKLabels().contains(KLabels.GENERATED_TOP_CELL)) { + RuleGrammarGenerator gen = new RuleGrammarGenerator(def); + ParseInModule mod = + RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(m), true, files); + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(m); + Sort topCellSort; + try { + topCellSort = configInfo.getRootCell(); + } catch (KEMException e) { + if (manualTopCell != null) { + topCellSort = Outer.parseSort(manualTopCell); + } else { + throw e; + } } - // fix the format after inserting the GeneratedCounterCell - sentences = immutable(stream(sentences).map(s -> s instanceof Production ? fixFormat((Production) s) : s).collect(Collectors.toSet())); - return Module(m.name(), m.imports(), sentences, m.att()); + KLabel topCellLabel = configInfo.getCellLabel(topCellSort); + Production prod = m.productionsFor().apply(topCellLabel).head(); + KToken cellName = KToken(prod.att().get(Att.CELL_NAME()), Sort("#CellName")); + + KToken topCellToken = KToken(KLabels.GENERATED_TOP_CELL_NAME, Sort("#CellName")); + K generatedTop = + KApply( + KLabel("#configCell"), + topCellToken, + KApply(KLabel("#cellPropertyListTerminator")), + KApply(KLabels.CELLS, KApply(KLabel("#externalCell"), cellName), freshCell), + topCellToken); + Set newSentences = + GenerateSentencesFromConfigDecl.gen( + generatedTop, BooleanUtils.TRUE, Att.empty(), mod.getExtensionModule()); + sentences = (Set) sentences.$bar(newSentences); + sentences = (Set) sentences.$bar(immutable(counterSentences)); + } + } + if (m.localKLabels().contains(KLabels.GENERATED_TOP_CELL)) { + RuleGrammarGenerator gen = new RuleGrammarGenerator(def); + ParseInModule mod = + RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(m), true, files); + Set newSentences = + GenerateSentencesFromConfigDecl.gen( + freshCell, BooleanUtils.TRUE, Att.empty(), mod.getExtensionModule()); + sentences = (Set) sentences.$bar(newSentences); + sentences = (Set) sentences.$bar(immutable(counterSentences)); + } + if (sentences.equals(m.localSentences())) { + return m; } + // fix the format after inserting the GeneratedCounterCell + sentences = + immutable( + stream(sentences) + .map(s -> s instanceof Production ? fixFormat((Production) s) : s) + .collect(Collectors.toSet())); + return Module(m.name(), m.imports(), sentences, m.att()); + } - private static Production fixFormat(Production prod) { - if (prod.klabel().isDefined() && prod.klabel().get().equals(KLabels.GENERATED_TOP_CELL)) { - List cellPositions = new ArrayList(); - int i = 1; - for (ProductionItem p: JavaConverters.seqAsJavaList(prod.items())) { - if (p instanceof NonTerminal nt) { - if (! nt.sort().equals(Sorts.GeneratedCounterCell())) { - cellPositions.add(i); - } - } - i++; - } - StringBuilder format = new StringBuilder(); - if (cellPositions.size() == 1) { - format.append("%").append(cellPositions.get(0)); - } else { - format.append("%1%i"); - int j; - for (j = 0; j < cellPositions.size(); j++) { - format.append("%n%").append(cellPositions.get(j)); - } - format.append("%d%n%").append(cellPositions.get(j - 1) + 2); - } - return prod.withAtt(prod.att().add(Att.FORMAT(), format.toString())); + private static Production fixFormat(Production prod) { + if (prod.klabel().isDefined() && prod.klabel().get().equals(KLabels.GENERATED_TOP_CELL)) { + List cellPositions = new ArrayList(); + int i = 1; + for (ProductionItem p : JavaConverters.seqAsJavaList(prod.items())) { + if (p instanceof NonTerminal nt) { + if (!nt.sort().equals(Sorts.GeneratedCounterCell())) { + cellPositions.add(i); + } } - return prod; + i++; + } + StringBuilder format = new StringBuilder(); + if (cellPositions.size() == 1) { + format.append("%").append(cellPositions.get(0)); + } else { + format.append("%1%i"); + int j; + for (j = 0; j < cellPositions.size(); j++) { + format.append("%n%").append(cellPositions.get(j)); + } + format.append("%d%n%").append(cellPositions.get(j - 1) + 2); + } + return prod.withAtt(prod.att().add(Att.FORMAT(), format.toString())); } + return prod; + } } - diff --git a/kernel/src/main/java/org/kframework/compile/ResolveFun.java b/kernel/src/main/java/org/kframework/compile/ResolveFun.java index 9f0580a0d25..5b2dfdf7127 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveFun.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveFun.java @@ -1,10 +1,21 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.UnaryOperator; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; +import org.kframework.compile.checks.ComputeUnboundVariables; import org.kframework.definition.Context; import org.kframework.definition.ContextAlias; import org.kframework.definition.Module; @@ -23,234 +34,219 @@ import org.kframework.kore.KVariable; import org.kframework.kore.Sort; import org.kframework.kore.TransformK; -import org.kframework.compile.checks.ComputeUnboundVariables; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.UnaryOperator; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - /** * Resolves #fun KApplies. * - * The rule Ctx[#fun(Pattern)(Expression)] is equivalent to the following sentences assuming some completely unique KLabel #lambda1 not used in any token: + *

The rule Ctx[#fun(Pattern)(Expression)] is equivalent to the following sentences assuming some + * completely unique KLabel #lambda1 not used in any token: * - * rule Ctx[#lambda1(Expression)] - * syntax K ::= #lambda1(K) [function] - * rule #lambda1(LHS) => RHS + *

rule Ctx[#lambda1(Expression)] syntax K ::= #lambda1(K) [function] rule #lambda1(LHS) => RHS * - * Where LHS is the LHS of Pattern and RHS is the RHS of Pattern. + *

Where LHS is the LHS of Pattern and RHS is the RHS of Pattern. * - * Note that if a variable is used in the rhs of the fun expression which is not bound in its lhs, it is added as a - * closure parameter to the generated function. + *

Note that if a variable is used in the rhs of the fun expression which is not bound in its + * lhs, it is added as a closure parameter to the generated function. * - * We purposely resolve this construct as early as possible in the pipeline so that later stages which insert implicit - * side conditions into the rule insert them into the correct rule. + *

We purposely resolve this construct as early as possible in the pipeline so that later stages + * which insert implicit side conditions into the rule insert them into the correct rule. */ public class ResolveFun { - private final Set funProds = new HashSet<>(); - private final Set funRules = new HashSet<>(); - private Module module; - private AddSortInjections inj; - private final Set klabels = new HashSet<>(); - - private KLabel getUniqueLambdaLabel(String nameHint1, String nameHint2) { - if (klabels.isEmpty()) { - klabels.addAll(mutable(module.definedKLabels())); + private final Set funProds = new HashSet<>(); + private final Set funRules = new HashSet<>(); + private Module module; + private AddSortInjections inj; + private final Set klabels = new HashSet<>(); + + private KLabel getUniqueLambdaLabel(String nameHint1, String nameHint2) { + if (klabels.isEmpty()) { + klabels.addAll(mutable(module.definedKLabels())); + } + int counter = 0; + KLabel freezer; + do { + freezer = + KLabel("#lambda" + nameHint1 + "_" + nameHint2 + "_" + (counter++ == 0 ? "" : counter)); + } while (klabels.contains(freezer)); + klabels.add(freezer); + return freezer; + } + + private Rule resolve(Rule rule) { + return new Rule( + transform(rule.body()), transform(rule.requires()), transform(rule.ensures()), rule.att()); + } + + private K transform(K body) { + return new TransformK() { + @Override + public K apply(KApply k) { + KLabel lbl = k.klabel(); + if (!(lbl instanceof KVariable) && lbl.name().equals("#fun2") + || lbl.name().equals("#fun3") + || lbl.name().equals("#let") + || lbl.equals(KLabels.IN_K) + || lbl.equals(KLabels.NOT_IN_K)) { + String nameHint1 = "", nameHint2 = ""; + K arg, body; + if (lbl.name().equals("#fun3")) { + body = KRewrite(k.items().get(0), k.items().get(1)); + arg = k.items().get(2); + } else if (lbl.name().equals("#let")) { + body = KRewrite(k.items().get(0), k.items().get(2)); + arg = k.items().get(1); + } else { + body = k.items().get(0); + arg = k.items().get(1); + } + if (arg instanceof KVariable) { + nameHint1 = ((KVariable) arg).name(); + } else if (arg instanceof KApply + && ((KApply) arg).klabel().name().startsWith("#SemanticCastTo") + && ((KApply) arg).items().get(0) instanceof KVariable) { + nameHint1 = ((KVariable) ((KApply) arg).items().get(0)).name(); + } + if (body instanceof KApply) { + nameHint2 = ((KApply) body).klabel().name(); + } + KLabel fun = getUniqueLambdaLabel(nameHint1, nameHint2); + Sort lhsSort = sort(RewriteToTop.toLeft(body)); + Sort argSort = sort(arg); + Sort lubSort = AddSortInjections.lubSort(lhsSort, argSort, null, body, module); + if (lbl.name().equals("#fun3") + || lbl.name().equals("#fun2") + || lbl.name().equals("#let")) { + funProds.add(funProd(fun, body, lubSort)); + funRules.add(funRule(fun, body, k.att())); + } else { + funProds.add(predProd(fun, body, lubSort)); + funRules.add(predRule(fun, body, k.att())); + funRules.add(owiseRule(fun, body, lubSort, k.att())); + } + List klist = new ArrayList<>(); + klist.add(apply(arg)); + klist.addAll(closure(body)); + K funCall = KApply(fun, KList(klist)); + if (lbl.equals(KLabels.NOT_IN_K)) { + return BooleanUtils.not(funCall); + } + return funCall; } - int counter = 0; - KLabel freezer; - do { - freezer = KLabel("#lambda" + nameHint1 + "_" + nameHint2 + "_" + (counter++ == 0 ? "" : counter)); - } while (klabels.contains(freezer)); - klabels.add(freezer); - return freezer; - } - - private Rule resolve(Rule rule) { - return new Rule( - transform(rule.body()), - transform(rule.requires()), - transform(rule.ensures()), - rule.att()); - } - - private K transform(K body) { - return new TransformK() { - @Override - public K apply(KApply k) { - KLabel lbl = k.klabel(); - if (!(lbl instanceof KVariable) && lbl.name().equals("#fun2") || lbl.name().equals("#fun3") || lbl.name().equals("#let") || lbl.equals(KLabels.IN_K) || lbl.equals(KLabels.NOT_IN_K)) { - String nameHint1 = "", nameHint2 = ""; - K arg, body; - if (lbl.name().equals("#fun3")) { - body = KRewrite(k.items().get(0), k.items().get(1)); - arg = k.items().get(2); - } else if (lbl.name().equals("#let")) { - body = KRewrite(k.items().get(0), k.items().get(2)); - arg = k.items().get(1); - } else { - body = k.items().get(0); - arg = k.items().get(1); - } - if (arg instanceof KVariable) { - nameHint1 = ((KVariable) arg).name(); - } else if (arg instanceof KApply - && ((KApply) arg).klabel().name().startsWith("#SemanticCastTo") - && ((KApply) arg).items().get(0) instanceof KVariable) { - nameHint1 = ((KVariable) ((KApply) arg).items().get(0)).name(); - } - if (body instanceof KApply) { - nameHint2 = ((KApply) body).klabel().name(); - } - KLabel fun = getUniqueLambdaLabel(nameHint1, nameHint2); - Sort lhsSort = sort(RewriteToTop.toLeft(body)); - Sort argSort = sort(arg); - Sort lubSort = AddSortInjections.lubSort(lhsSort, argSort, null, body, module); - if (lbl.name().equals("#fun3") || lbl.name().equals("#fun2") || lbl.name().equals("#let")) { - funProds.add(funProd(fun, body, lubSort)); - funRules.add(funRule(fun, body, k.att())); - } else { - funProds.add(predProd(fun, body, lubSort)); - funRules.add(predRule(fun, body, k.att())); - funRules.add(owiseRule(fun, body, lubSort, k.att())); - } - List klist = new ArrayList<>(); - klist.add(apply(arg)); - klist.addAll(closure(body)); - K funCall = KApply(fun, KList(klist)); - if (lbl.equals(KLabels.NOT_IN_K)) { - return BooleanUtils.not(funCall); - } - return funCall; - } - return super.apply(k); - } - }.apply(body); - } - - private Rule funRule(KLabel fun, K k, Att att) { - return lambdaRule(fun, k, k, att, RewriteToTop::toRight); - } - - private Rule predRule(KLabel fun, K k, Att att) { - return lambdaRule(fun, k, k, att, x -> BooleanUtils.TRUE); - } - - private Rule owiseRule(KLabel fun, K k, Sort arg, Att att) { - return lambdaRule(fun, KApply(KLabel("#SemanticCastTo" + arg.toString()), KVariable("#Owise")), k, att.add(Att.OWISE()), x -> BooleanUtils.FALSE); - } - - private Rule lambdaRule(KLabel fun, K body, K closure, Att att, UnaryOperator getRHS) { - K resolved = transform(body); - K withAnonVars = new ResolveAnonVar().resolveK(resolved); - List klist = new ArrayList<>(); - klist.add(RewriteToTop.toLeft(withAnonVars)); - klist.addAll(closure(closure)); - K rewrite = KRewrite(KApply(fun, KList(klist)), getRHS.apply(withAnonVars)); - K renamed = new TransformK() { - public K apply(KVariable k) { - if (k.name().startsWith("!")) { - return KVariable("#_" + k.name().substring(1), k.att()); - } - return k; + return super.apply(k); + } + }.apply(body); + } + + private Rule funRule(KLabel fun, K k, Att att) { + return lambdaRule(fun, k, k, att, RewriteToTop::toRight); + } + + private Rule predRule(KLabel fun, K k, Att att) { + return lambdaRule(fun, k, k, att, x -> BooleanUtils.TRUE); + } + + private Rule owiseRule(KLabel fun, K k, Sort arg, Att att) { + return lambdaRule( + fun, + KApply(KLabel("#SemanticCastTo" + arg.toString()), KVariable("#Owise")), + k, + att.add(Att.OWISE()), + x -> BooleanUtils.FALSE); + } + + private Rule lambdaRule(KLabel fun, K body, K closure, Att att, UnaryOperator getRHS) { + K resolved = transform(body); + K withAnonVars = new ResolveAnonVar().resolveK(resolved); + List klist = new ArrayList<>(); + klist.add(RewriteToTop.toLeft(withAnonVars)); + klist.addAll(closure(closure)); + K rewrite = KRewrite(KApply(fun, KList(klist)), getRHS.apply(withAnonVars)); + K renamed = + new TransformK() { + public K apply(KVariable k) { + if (k.name().startsWith("!")) { + return KVariable("#_" + k.name().substring(1), k.att()); } + return k; + } }.apply(rewrite); - return Rule(renamed, - BooleanUtils.TRUE, BooleanUtils.TRUE, att); - } - - private List closure(K k) { - Set errors = new HashSet<>(); - Set vars = new HashSet<>(); - List result = new ArrayList<>(); - new GatherVarsVisitor(true, errors, vars, false).apply(k); - new ComputeUnboundVariables(true, true, errors, vars, result::add).apply(k); - return result; - } - - private Production funProd(KLabel fun, K k, Sort arg) { - return lambdaProd(fun, k, arg, sort(RewriteToTop.toRight(k))); - } - - private Production predProd(KLabel fun, K k, Sort arg) { - return lambdaProd(fun, k, arg, Sorts.Bool()); - } - - private Production lambdaProd(KLabel fun, K k, Sort arg, Sort rhs) { - List pis = new ArrayList<>(); - pis.add(Terminal(fun.name())); - pis.add(Terminal("(")); - pis.add(NonTerminal(arg)); - for (KVariable var : closure(k)) { - pis.add(Terminal(",")); - pis.add(NonTerminal(var.att().getOptional(Sort.class).orElse(Sorts.K()))); - } - pis.add(Terminal(")")); - return Production(fun, rhs, - immutable(pis), - Att().add(Att.FUNCTION())); - } - - private Sort sort(K k) { - if (k instanceof KSequence) - return Sorts.K(); - if (k instanceof KAs) - return sort(((KAs) k).pattern()); - if (k instanceof InjectedKLabel) - return Sorts.KItem(); - if (k instanceof KToken) - return ((KToken) k).sort(); - if (k instanceof KApply) { - return inj.sort(k, Sorts.K()); - } - if (k instanceof KVariable) - return Sorts.K(); - throw KEMException.compilerError("Could not compute sort of term", k); - } - - private Context resolve(Context context) { - return new Context( - transform(context.body()), - transform(context.requires()), - context.att()); - } - - private ContextAlias resolve(ContextAlias context) { - return new ContextAlias( - transform(context.body()), - transform(context.requires()), - context.att()); - } - - public Sentence resolve(Sentence s) { - if (s instanceof Rule) { - return resolve((Rule) s); - } else if (s instanceof Context) { - return resolve((Context) s); - } else if (s instanceof ContextAlias) { - return resolve((ContextAlias) s); - } else { - return s; - } - } - - public Module resolve(Module m) { - module = Kompile.subsortKItem(m); - inj = new AddSortInjections(module); - funProds.clear(); - funRules.clear(); - Set newSentences = stream(m.localSentences()).map(this::resolve).collect(Collectors.toSet()); - newSentences.addAll(funProds); - newSentences.addAll(funRules); - return Module(m.name(), m.imports(), immutable(newSentences), m.att()); - } + return Rule(renamed, BooleanUtils.TRUE, BooleanUtils.TRUE, att); + } + + private List closure(K k) { + Set errors = new HashSet<>(); + Set vars = new HashSet<>(); + List result = new ArrayList<>(); + new GatherVarsVisitor(true, errors, vars, false).apply(k); + new ComputeUnboundVariables(true, true, errors, vars, result::add).apply(k); + return result; + } + + private Production funProd(KLabel fun, K k, Sort arg) { + return lambdaProd(fun, k, arg, sort(RewriteToTop.toRight(k))); + } + + private Production predProd(KLabel fun, K k, Sort arg) { + return lambdaProd(fun, k, arg, Sorts.Bool()); + } + + private Production lambdaProd(KLabel fun, K k, Sort arg, Sort rhs) { + List pis = new ArrayList<>(); + pis.add(Terminal(fun.name())); + pis.add(Terminal("(")); + pis.add(NonTerminal(arg)); + for (KVariable var : closure(k)) { + pis.add(Terminal(",")); + pis.add(NonTerminal(var.att().getOptional(Sort.class).orElse(Sorts.K()))); + } + pis.add(Terminal(")")); + return Production(fun, rhs, immutable(pis), Att().add(Att.FUNCTION())); + } + + private Sort sort(K k) { + if (k instanceof KSequence) return Sorts.K(); + if (k instanceof KAs) return sort(((KAs) k).pattern()); + if (k instanceof InjectedKLabel) return Sorts.KItem(); + if (k instanceof KToken) return ((KToken) k).sort(); + if (k instanceof KApply) { + return inj.sort(k, Sorts.K()); + } + if (k instanceof KVariable) return Sorts.K(); + throw KEMException.compilerError("Could not compute sort of term", k); + } + + private Context resolve(Context context) { + return new Context(transform(context.body()), transform(context.requires()), context.att()); + } + + private ContextAlias resolve(ContextAlias context) { + return new ContextAlias( + transform(context.body()), transform(context.requires()), context.att()); + } + + public Sentence resolve(Sentence s) { + if (s instanceof Rule) { + return resolve((Rule) s); + } else if (s instanceof Context) { + return resolve((Context) s); + } else if (s instanceof ContextAlias) { + return resolve((ContextAlias) s); + } else { + return s; + } + } + + public Module resolve(Module m) { + module = Kompile.subsortKItem(m); + inj = new AddSortInjections(module); + funProds.clear(); + funRules.clear(); + Set newSentences = + stream(m.localSentences()).map(this::resolve).collect(Collectors.toSet()); + newSentences.addAll(funProds); + newSentences.addAll(funRules); + return Module(m.name(), m.imports(), immutable(newSentences), m.att()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveFunctionWithConfig.java b/kernel/src/main/java/org/kframework/compile/ResolveFunctionWithConfig.java index 4d438c92cff..6111413625b 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveFunctionWithConfig.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveFunctionWithConfig.java @@ -1,6 +1,14 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.builtin.KLabels; @@ -14,226 +22,245 @@ import org.kframework.definition.Rule; import org.kframework.definition.RuleOrClaim; import org.kframework.definition.Sentence; +import org.kframework.kore.FoldK; import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KLabel; import org.kframework.kore.KRewrite; import org.kframework.kore.KVariable; import org.kframework.kore.Sort; -import org.kframework.kore.FoldK; import org.kframework.kore.TransformK; import org.kframework.utils.errorsystem.KEMException; - -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import scala.collection.immutable.List; -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - public class ResolveFunctionWithConfig { - private final Set withConfigFunctions = new HashSet<>(); - private final Sort topCell; - private final KLabel topCellLabel; + private final Set withConfigFunctions = new HashSet<>(); + private final Sort topCell; + private final KLabel topCellLabel; - public ResolveFunctionWithConfig(Definition d) { - this(d.mainModule()); - } + public ResolveFunctionWithConfig(Definition d) { + this(d.mainModule()); + } - public ResolveFunctionWithConfig(Module mod) { - ComputeTransitiveFunctionDependencies deps = new ComputeTransitiveFunctionDependencies(mod); - Set functions = stream(mod.productions()).filter(p -> p.att().contains(Att.FUNCTION())).map(p -> p.klabel().get()).collect(Collectors.toSet()); - withConfigFunctions.addAll(functions.stream().filter(f -> stream(mod.rulesFor().getOrElse(f, () -> Collections.Set())).anyMatch(r -> ruleNeedsConfig(r))).collect(Collectors.toSet())); - withConfigFunctions.addAll(deps.ancestors(withConfigFunctions)); - ConfigurationInfoFromModule info = new ConfigurationInfoFromModule(mod); - topCell = Sorts.GeneratedTopCell(); - topCellLabel = KLabels.GENERATED_TOP_CELL; - CONFIG_VAR = KVariable("#Configuration", Att().add(Sort.class, topCell).add(Att.WITH_CONFIG())); + public ResolveFunctionWithConfig(Module mod) { + ComputeTransitiveFunctionDependencies deps = new ComputeTransitiveFunctionDependencies(mod); + Set functions = + stream(mod.productions()) + .filter(p -> p.att().contains(Att.FUNCTION())) + .map(p -> p.klabel().get()) + .collect(Collectors.toSet()); + withConfigFunctions.addAll( + functions.stream() + .filter( + f -> + stream(mod.rulesFor().getOrElse(f, () -> Collections.Set())) + .anyMatch(r -> ruleNeedsConfig(r))) + .collect(Collectors.toSet())); + withConfigFunctions.addAll(deps.ancestors(withConfigFunctions)); + ConfigurationInfoFromModule info = new ConfigurationInfoFromModule(mod); + topCell = Sorts.GeneratedTopCell(); + topCellLabel = KLabels.GENERATED_TOP_CELL; + CONFIG_VAR = KVariable("#Configuration", Att().add(Sort.class, topCell).add(Att.WITH_CONFIG())); + } + + private boolean ruleNeedsConfig(RuleOrClaim r) { + if (r.body() instanceof KApply && ((KApply) r.body()).klabel().name().equals("#withConfig")) { + return true; } + FoldK hasVarNeedsConfig = + new FoldK() { + @Override + public Boolean unit() { + return false; + } - private boolean ruleNeedsConfig(RuleOrClaim r) { - if (r.body() instanceof KApply && ((KApply)r.body()).klabel().name().equals("#withConfig")) { - return true; - } - FoldK hasVarNeedsConfig = new FoldK() { - @Override - public Boolean unit() { - return false; - } - - @Override - public Boolean merge(Boolean a, Boolean b) { - return a || b; - } - - @Override - public Boolean apply(KVariable k) { - return k.name().startsWith("!") || k.name().equals("#Configuration"); - } + @Override + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } + + @Override + public Boolean apply(KVariable k) { + return k.name().startsWith("!") || k.name().equals("#Configuration"); + } }; - return hasVarNeedsConfig.apply(RewriteToTop.toRight(r.body())) || hasVarNeedsConfig.apply(r.requires()) || hasVarNeedsConfig.apply(r.ensures()); - } + return hasVarNeedsConfig.apply(RewriteToTop.toRight(r.body())) + || hasVarNeedsConfig.apply(r.requires()) + || hasVarNeedsConfig.apply(r.ensures()); + } - public RuleOrClaim resolve(RuleOrClaim rule, Module m) { - return rule.newInstance( - transform(resolve(rule.body(), m), m), - transform(rule.requires(), m), - transform(rule.ensures(), m), - rule.att()); - } + public RuleOrClaim resolve(RuleOrClaim rule, Module m) { + return rule.newInstance( + transform(resolve(rule.body(), m), m), + transform(rule.requires(), m), + transform(rule.ensures(), m), + rule.att()); + } - public Context resolve(Context context, Module m) { - return new Context( - transform(context.body(), m), - transform(context.requires(), m), - context.att()); - } + public Context resolve(Context context, Module m) { + return new Context( + transform(context.body(), m), transform(context.requires(), m), context.att()); + } - public ContextAlias resolve(ContextAlias context, Module m) { - return new ContextAlias( - transform(context.body(), m), - transform(context.requires(), m), - context.att()); - } + public ContextAlias resolve(ContextAlias context, Module m) { + return new ContextAlias( + transform(context.body(), m), transform(context.requires(), m), context.att()); + } - public final KVariable CONFIG_VAR; + public final KVariable CONFIG_VAR; - private K transform(K term, Module module) { - return new TransformK() { - @Override - public K apply(KApply kapp) { - if (!kapp.items().isEmpty() && kapp.items().get(kapp.items().size() - 1).att().contains(Att.WITH_CONFIG())) { - return super.apply(kapp); - } - if (withConfigFunctions.contains(kapp.klabel())) { - return KApply(kapp.klabel(), KList(Stream.concat(kapp.items().stream().map(this::apply), Stream.of(CONFIG_VAR)).collect(Collections.toList())), kapp.att()); - } + private K transform(K term, Module module) { + return new TransformK() { + @Override + public K apply(KApply kapp) { + if (!kapp.items().isEmpty() + && kapp.items().get(kapp.items().size() - 1).att().contains(Att.WITH_CONFIG())) { return super.apply(kapp); } - }.apply(term); - } + if (withConfigFunctions.contains(kapp.klabel())) { + return KApply( + kapp.klabel(), + KList( + Stream.concat(kapp.items().stream().map(this::apply), Stream.of(CONFIG_VAR)) + .collect(Collections.toList())), + kapp.att()); + } + return super.apply(kapp); + } + }.apply(term); + } - private K resolve(K body, Module module) { - if (body instanceof KApply kapp) { - if (kapp.klabel().name().equals("#withConfig")) { - K fun = kapp.items().get(0); - K cell = kapp.items().get(1); - K rhs = null; - KRewrite rew = null; - if (fun instanceof KRewrite) { - rew = (KRewrite)fun; - fun = rew.left(); - rhs = rew.right(); - } - if (!(fun instanceof KApply funKApp)) { - throw KEMException.compilerError("Found term that is not a cell or a function at the top of a rule.", fun); - } - if (!module.attributesFor().apply(funKApp.klabel()).contains(Att.FUNCTION())) { - throw KEMException.compilerError("Found term that is not a cell or a function at the top of a rule.", fun); - } - if (!(cell instanceof KApply cellKApp)) { - throw KEMException.compilerError("Found term that is not a cell in the context of a function rule.", cell); - } - K secondChild; - if (cellKApp.klabel().equals(topCellLabel)) { - secondChild = cell; - } else { - secondChild = IncompleteCellUtils.make(topCellLabel, true, cell, true); - } - List items = Stream.concat(funKApp.items().stream(), Stream.of(KAs(secondChild, CONFIG_VAR, Att().add(Att.WITH_CONFIG())))).collect(Collections.toList()); - K result = KApply(funKApp.klabel(), KList(items), funKApp.att()); - if (rhs == null) { - return result; - } else { - return KRewrite(result, rhs, rew.att()); - } + private K resolve(K body, Module module) { + if (body instanceof KApply kapp) { + if (kapp.klabel().name().equals("#withConfig")) { + K fun = kapp.items().get(0); + K cell = kapp.items().get(1); + K rhs = null; + KRewrite rew = null; + if (fun instanceof KRewrite) { + rew = (KRewrite) fun; + fun = rew.left(); + rhs = rew.right(); + } + if (!(fun instanceof KApply funKApp)) { + throw KEMException.compilerError( + "Found term that is not a cell or a function at the top of a rule.", fun); + } + if (!module.attributesFor().apply(funKApp.klabel()).contains(Att.FUNCTION())) { + throw KEMException.compilerError( + "Found term that is not a cell or a function at the top of a rule.", fun); + } + if (!(cell instanceof KApply cellKApp)) { + throw KEMException.compilerError( + "Found term that is not a cell in the context of a function rule.", cell); + } + K secondChild; + if (cellKApp.klabel().equals(topCellLabel)) { + secondChild = cell; + } else { + secondChild = IncompleteCellUtils.make(topCellLabel, true, cell, true); + } + List items = + Stream.concat( + funKApp.items().stream(), + Stream.of(KAs(secondChild, CONFIG_VAR, Att().add(Att.WITH_CONFIG())))) + .collect(Collections.toList()); + K result = KApply(funKApp.klabel(), KList(items), funKApp.att()); + if (rhs == null) { + return result; + } else { + return KRewrite(result, rhs, rew.att()); } } - return body; } + return body; + } - private Production resolve(Production prod) { - if (prod.klabel().isDefined() && withConfigFunctions.contains(prod.klabel().get())) { - List pis = Stream.concat(stream(prod.items()), Stream.of(NonTerminal(topCell))).collect(Collections.toList()); - return Production(prod.klabel(), prod.params(), prod.sort(), pis, prod.att()); - } - return prod; + private Production resolve(Production prod) { + if (prod.klabel().isDefined() && withConfigFunctions.contains(prod.klabel().get())) { + List pis = + Stream.concat(stream(prod.items()), Stream.of(NonTerminal(topCell))) + .collect(Collections.toList()); + return Production(prod.klabel(), prod.params(), prod.sort(), pis, prod.att()); } + return prod; + } - public K resolveConfigVar(K body, K requires, K ensures) { - FoldK hasConfig = new FoldK() { + public K resolveConfigVar(K body, K requires, K ensures) { + FoldK hasConfig = + new FoldK() { @Override public Boolean unit() { - return false; + return false; } @Override public Boolean apply(KVariable k) { - return k.name().equals("#Configuration"); + return k.name().equals("#Configuration"); } @Override public Boolean merge(Boolean a, Boolean b) { - return a || b; + return a || b; + } + }; + if (new FoldK() { + @Override + public Boolean unit() { + return false; + } + + @Override + public Boolean apply(KRewrite k) { + return true; } - }; - if (new FoldK() { - @Override - public Boolean unit() { - return false; - } - - @Override - public Boolean apply(KRewrite k) { - return true; - } - - @Override - public Boolean merge(Boolean a, Boolean b) { - return a || b; - } - }.apply(body) && (hasConfig.apply(body) || hasConfig.apply(requires) || hasConfig.apply(ensures))) { - K left = RewriteToTop.toLeft(body); - if (left instanceof KApply && ((KApply)left).klabel().equals(topCellLabel)) { - body = KRewrite(KAs(RewriteToTop.toLeft(body), CONFIG_VAR), RewriteToTop.toRight(body)); - } - } - return body; - } - public Sentence resolveConfigVar(Sentence s) { - if (s instanceof RuleOrClaim r) { - return r.newInstance(resolveConfigVar(r.body(), r.requires(), r.ensures()), r.requires(), r.ensures(), r.att()); + @Override + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } + }.apply(body) + && (hasConfig.apply(body) || hasConfig.apply(requires) || hasConfig.apply(ensures))) { + K left = RewriteToTop.toLeft(body); + if (left instanceof KApply && ((KApply) left).klabel().equals(topCellLabel)) { + body = KRewrite(KAs(RewriteToTop.toLeft(body), CONFIG_VAR), RewriteToTop.toRight(body)); } - return s; } + return body; + } - public Module moduleResolve(Module m) { - Set newSentences = new HashSet<>(); - for (Sentence s : mutable(m.localSentences())) { - if (s instanceof RuleOrClaim) { - newSentences.add(resolve((RuleOrClaim) s, m)); - } else if (s instanceof Context) { - newSentences.add(resolve((Context) s, m)); - } else if (s instanceof ContextAlias) { - newSentences.add(resolve((ContextAlias) s, m)); - } else if (s instanceof Production) { - Production prd = resolve((Production) s); - newSentences.add(prd); - // topCell introduces a new sort. Make sure it's declared - if (!prd.equals(s) && !m.definedSorts().contains(topCell.head())) - newSentences.add(SyntaxSort(Seq(), topCell)); - } else { - newSentences.add(s); - } - } - if (newSentences.equals(mutable(m.localSentences()))) - return m; - return Module.apply(m.name(), m.imports(), immutable(newSentences), m.att()); + public Sentence resolveConfigVar(Sentence s) { + if (s instanceof RuleOrClaim r) { + return r.newInstance( + resolveConfigVar(r.body(), r.requires(), r.ensures()), + r.requires(), + r.ensures(), + r.att()); + } + return s; + } + + public Module moduleResolve(Module m) { + Set newSentences = new HashSet<>(); + for (Sentence s : mutable(m.localSentences())) { + if (s instanceof RuleOrClaim) { + newSentences.add(resolve((RuleOrClaim) s, m)); + } else if (s instanceof Context) { + newSentences.add(resolve((Context) s, m)); + } else if (s instanceof ContextAlias) { + newSentences.add(resolve((ContextAlias) s, m)); + } else if (s instanceof Production) { + Production prd = resolve((Production) s); + newSentences.add(prd); + // topCell introduces a new sort. Make sure it's declared + if (!prd.equals(s) && !m.definedSorts().contains(topCell.head())) + newSentences.add(SyntaxSort(Seq(), topCell)); + } else { + newSentences.add(s); + } } + if (newSentences.equals(mutable(m.localSentences()))) return m; + return Module.apply(m.name(), m.imports(), immutable(newSentences), m.att()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveHeatCoolAttribute.java b/kernel/src/main/java/org/kframework/compile/ResolveHeatCoolAttribute.java index 7c26aa291f7..e1f41dba853 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveHeatCoolAttribute.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveHeatCoolAttribute.java @@ -1,6 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.Optional; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.definition.Context; @@ -12,63 +18,59 @@ import org.kframework.kore.KLabel; import org.kframework.utils.errorsystem.KEMException; -import java.util.Optional; -import java.util.Set; +public record ResolveHeatCoolAttribute(Set unrestrictedRules) { -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; + private Rule resolve(Module m, Rule rule) { + return Rule(rule.body(), transform(m, rule.requires(), rule.att()), rule.ensures(), rule.att()); + } -public record ResolveHeatCoolAttribute(Set unrestrictedRules) { + private Context resolve(Module m, Context context) { + return new Context( + context.body(), transform(m, context.requires(), context.att()), context.att()); + } - private Rule resolve(Module m, Rule rule) { - return Rule( - rule.body(), - transform(m, rule.requires(), rule.att()), - rule.ensures(), - rule.att()); + private K transform(Module m, K requires, Att att) { + String sort = att.getOptional(Att.RESULT()).orElse("KResult"); + KLabel lbl = KLabel("is" + sort); + if (!m.productionsFor().contains(lbl) + && stream(m.allSorts()).noneMatch(s -> s.toString().equals(sort))) { + throw KEMException.compilerError( + "Definition is missing function " + + lbl.name() + + " required for strictness. Please either declare sort " + + sort + + " or declare 'syntax Bool ::= " + + lbl.name() + + "(K) [symbol, function]'", + requires); } - - private Context resolve(Module m, Context context) { - return new Context( - context.body(), - transform(m, context.requires(), context.att()), - context.att()); + KApply predicate = KApply(lbl, KVariable("HOLE")); + if (att.contains(Att.HEAT())) { + return BooleanUtils.and(requires, BooleanUtils.not(predicate)); } - - private K transform(Module m, K requires, Att att) { - String sort = att.getOptional(Att.RESULT()).orElse("KResult"); - KLabel lbl = KLabel("is" + sort); - if (!m.productionsFor().contains(lbl) && stream(m.allSorts()).noneMatch(s -> s.toString().equals(sort))) { - throw KEMException.compilerError("Definition is missing function " + lbl.name() + - " required for strictness. Please either declare sort " + sort + - " or declare 'syntax Bool ::= " + lbl.name() + "(K) [symbol, function]'", requires); - } - KApply predicate = KApply(lbl, KVariable("HOLE")); - if (att.contains(Att.HEAT())) { - return BooleanUtils.and(requires, BooleanUtils.not(predicate)); - } - if (att.contains(Att.COOL())) { - if (unrestrictedRules.stream() - .map(Att::getUserGroupOptional).flatMap(Optional::stream).anyMatch(att::contains)) { - return requires; - } - return BooleanUtils.and(requires, predicate); - } - throw new AssertionError("Called ResolveHeatCoolAttribute::transform on rule without " + - "heat or cool attribute"); + if (att.contains(Att.COOL())) { + if (unrestrictedRules.stream() + .map(Att::getUserGroupOptional) + .flatMap(Optional::stream) + .anyMatch(att::contains)) { + return requires; + } + return BooleanUtils.and(requires, predicate); } + throw new AssertionError( + "Called ResolveHeatCoolAttribute::transform on rule without " + "heat or cool attribute"); + } - public Sentence resolve(Module m, Sentence s) { - if (!s.att().contains(Att.HEAT()) && !s.att().contains(Att.COOL())) { - return s; - } - if (s instanceof Rule r) { - return resolve(m, r); - } else if (s instanceof Context c) { - return resolve(m, c); - } else { - return s; - } + public Sentence resolve(Module m, Sentence s) { + if (!s.att().contains(Att.HEAT()) && !s.att().contains(Att.COOL())) { + return s; + } + if (s instanceof Rule r) { + return resolve(m, r); + } else if (s instanceof Context c) { + return resolve(m, c); + } else { + return s; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveIOStreams.java b/kernel/src/main/java/org/kframework/compile/ResolveIOStreams.java index dbea035d9a9..f687e34214b 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveIOStreams.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveIOStreams.java @@ -1,6 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.attributes.Location; import org.kframework.builtin.KLabels; @@ -26,392 +33,419 @@ import scala.Tuple2; import scala.collection.Set; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - -/** - * Created by daejunpark on 9/6/15. - */ -public record ResolveIOStreams(Definition definition, - KExceptionManager kem) { - - /** - * Update modules that declare stream cells in configuration, - * by using builtin *-STREAM modules. - *

- * Steps: - * 1. Update the init rules of the stream cells. - * 2. Update rules that refer to 'stdin' stream. - * 3. Import rules from *-STREAM modules (with modification of cell names). - */ - public Module resolve(Module m) { - java.util.Set streamProductions = getStreamProductions(m.sentences()); - if (streamProductions.isEmpty()) { - return m; - } else { - java.util.Set sentences = mutable(m.localSentences()); - // NOTE: it may seem inefficient to have duplicated for-loops here, - // but such a duplication makes each step much simpler; - // moreover the number of `streamProductions` is at most two (or possibly three later on), - // so that the duplication effect is not that much. - // Step 1. - for (Production p : streamProductions) { - sentences = sentences.stream().map(s -> resolveInitRule(p, s)).collect(Collectors.toSet()); - } - // Step 2. - for (Production p : streamProductions) { - if (p.att().get(Att.STREAM()).equals("stdin")) { - sentences.addAll(getStdinStreamUnblockingRules(p, sentences)); - } - } - // Step 3. - if (!getStreamProductions(m.localSentences()).isEmpty()) { - for (Production p : streamProductions) { - sentences.addAll(getStreamModuleSentences(p)); - } - } - return Module(m.name(), (Set) m.imports(). - $bar(Set(Import(definition.getModule("K-IO").get(), true))). - $bar(Set(Import(definition.getModule("K-REFLECTION").get(), true))), - immutable(sentences), m.att()); - } - } - - // Collect productions that have 'stream' attribute - private java.util.Set getStreamProductions(Set sentences) { - java.util.Set productions = new HashSet<>(); - for (Sentence s : mutable(sentences)) { - if (s instanceof Production p) { - if (p.att().getOption(Att.STREAM()).isDefined()) { - checkStreamName(p.att().get(Att.STREAM())); - productions.add(p); - } - } - } - return productions; - } - - private void checkStreamName(String streamName) { - ArrayList streams = new ArrayList(); - streams.add("stdin"); - streams.add("stdout"); - - if (!streams.contains(streamName)) { - throw KEMException.compilerError("Make sure you give the correct stream names: " + streamName + - "\nIt should be one of " + streams); +/** Created by daejunpark on 9/6/15. */ +public record ResolveIOStreams(Definition definition, KExceptionManager kem) { + + /** + * Update modules that declare stream cells in configuration, by using builtin *-STREAM modules. + * Steps: + * + *

    + *
  1. Update the init rules of the stream cells. + *
  2. Update rules that refer to 'stdin' stream. + *
  3. Import rules from *-STREAM modules (with modification of cell names). + *
+ */ + public Module resolve(Module m) { + java.util.Set streamProductions = getStreamProductions(m.sentences()); + if (streamProductions.isEmpty()) { + return m; + } else { + java.util.Set sentences = mutable(m.localSentences()); + // NOTE: it may seem inefficient to have duplicated for-loops here, + // but such a duplication makes each step much simpler; + // moreover the number of `streamProductions` is at most two (or possibly three later + // on), + // so that the duplication effect is not that much. + // Step 1. + for (Production p : streamProductions) { + sentences = sentences.stream().map(s -> resolveInitRule(p, s)).collect(Collectors.toSet()); + } + // Step 2. + for (Production p : streamProductions) { + if (p.att().get(Att.STREAM()).equals("stdin")) { + sentences.addAll(getStdinStreamUnblockingRules(p, sentences)); } - } - - private Sentence resolveInitRule(Production p, Sentence s) { - if (s instanceof Rule) { - return resolveInitRule(p, (Rule) s); - } else { - return s; + } + // Step 3. + if (!getStreamProductions(m.localSentences()).isEmpty()) { + for (Production p : streamProductions) { + sentences.addAll(getStreamModuleSentences(p)); } + } + return Module( + m.name(), + (Set) + m.imports() + .$bar(Set(Import(definition.getModule("K-IO").get(), true))) + .$bar(Set(Import(definition.getModule("K-REFLECTION").get(), true))), + immutable(sentences), + m.att()); } - - // Step 1. - private Rule resolveInitRule(Production streamProduction, Rule rule) { - Sort streamSort = streamProduction.sort(); // InCell, OutCell - String initLabel = GenerateSentencesFromConfigDecl.getInitLabel(streamSort); // initInCell, initOutCell - KLabel cellLabel = streamProduction.klabel().get(); // , - - // rule initInCell(Init) => ... - if (isInitRule(initLabel, cellLabel.name(), rule)) { - KRewrite body = (KRewrite) rule.body(); - KApply right = (KApply) body.right(); - KList klist = getContentsOfInitRule(streamProduction); - right = KApply(right.klabel(), klist, right.att()); - body = KRewrite(body.left(), right, body.att()); - return Rule(body, rule.requires(), rule.ensures(), rule.att()); + } + + // Collect productions that have 'stream' attribute + private java.util.Set getStreamProductions(Set sentences) { + java.util.Set productions = new HashSet<>(); + for (Sentence s : mutable(sentences)) { + if (s instanceof Production p) { + if (p.att().getOption(Att.STREAM()).isDefined()) { + checkStreamName(p.att().get(Att.STREAM())); + productions.add(p); } - return rule; + } } - - // TODO(Daejun): rule should have contained an initializer attribute. - private boolean isInitRule(String initLabel, String cellLabel, Sentence s) { - try { - // rule initXCell(Init) => ... - KRewrite body = (KRewrite) ((Rule) s).body(); - KApply left = (KApply) body.left(); - KApply right = (KApply) body.right(); - return left.klabel().name().equals(initLabel) // initXCell - && right.klabel().name().equals(cellLabel); // - } catch (ClassCastException ignored) { - return false; - } + return productions; + } + + private void checkStreamName(String streamName) { + ArrayList streams = new ArrayList(); + streams.add("stdin"); + streams.add("stdout"); + + if (!streams.contains(streamName)) { + throw KEMException.compilerError( + "Make sure you give the correct stream names: " + + streamName + + "\nIt should be one of " + + streams); } + } - // Get an initializer rule from the built-in *-STREAM module - private KList getContentsOfInitRule(Production streamProduction) { - String streamName = streamProduction.att().get(Att.STREAM()); // stdin, stdout - String initLabel = GenerateSentencesFromConfigDecl.getInitLabel( - Sort(GenerateSentencesFromConfigDecl.getSortOfCell(streamName))); // initStdinCell, initStdoutCell - String cellLabel = "<" + streamName + ">"; // , - - java.util.List initRules = - stream(getStreamModule(streamName).localSentences()) - .filter(s -> isInitRule(initLabel, cellLabel, s)).toList(); - assert initRules.size() == 1; - Sentence initRule = initRules.get(0); - - // rule initXCell(Init) => ... - KRewrite body = (KRewrite) ((Rule) initRule).body(); - KApply right = (KApply) body.right(); - return right.klist(); + private Sentence resolveInitRule(Production p, Sentence s) { + if (s instanceof Rule) { + return resolveInitRule(p, (Rule) s); + } else { + return s; } - - // Step 3. - // get sentences from stream module: - // - productions whose sort is `Stream` - // - rules that have `stream` attribute, but changing cell names according to user-defined one. - private java.util.Set getStreamModuleSentences(Production streamProduction) { - String streamName = streamProduction.att().get(Att.STREAM()); // stdin, stdout - String builtinCellLabel = "<" + streamName + ">"; // , - KLabel userCellLabel = streamProduction.klabel().get(); // , - - java.util.Set sentences = new HashSet<>(); - for (Sentence s : mutable(getStreamModule(streamName).localSentences())) { - if (s instanceof Rule rule) { - if (rule.att().contains(Att.STREAM())) { - // Update cell names - K body = new TransformK() { - @Override - public K apply(KApply k) { - k = (KApply) super.apply(k); - return KApply(apply(k.klabel()), k.klist(), k.att()); - } - - private KLabel apply(KLabel klabel) { - if (klabel.name().equals(builtinCellLabel)) { - return userCellLabel; - } else { - return klabel; - } - } - }.apply(rule.body()); - - rule = Rule(body, rule.requires(), rule.ensures(), rule.att()); - sentences.add(rule); - } else if (rule.att().contains(Att.PROJECTION())) { - sentences.add(rule); - } - } else if (s instanceof Production production) { - if (production.sort().toString().equals("Stream") || production.att().contains(Att.PROJECTION())) { - sentences.add(production); - } - } - } - return sentences; + } + + // Step 1. + private Rule resolveInitRule(Production streamProduction, Rule rule) { + Sort streamSort = streamProduction.sort(); // InCell, OutCell + String initLabel = + GenerateSentencesFromConfigDecl.getInitLabel(streamSort); // initInCell, initOutCell + KLabel cellLabel = streamProduction.klabel().get(); // , + + // rule initInCell(Init) => ... + if (isInitRule(initLabel, cellLabel.name(), rule)) { + KRewrite body = (KRewrite) rule.body(); + KApply right = (KApply) body.right(); + KList klist = getContentsOfInitRule(streamProduction); + right = KApply(right.klabel(), klist, right.att()); + body = KRewrite(body.left(), right, body.att()); + return Rule(body, rule.requires(), rule.ensures(), rule.att()); } - - private Module getStreamModule(String streamName) { - // TODO(Daejun): fix hard-coded stream module naming convention - String moduleName = streamName.toUpperCase() + "-STREAM"; - Option module = definition.getModule(moduleName); - if (module.isDefined()) { - return module.get(); - } else { - throw KEMException.compilerError("no such module: " + moduleName); - } + return rule; + } + + // TODO(Daejun): rule should have contained an initializer attribute. + private boolean isInitRule(String initLabel, String cellLabel, Sentence s) { + try { + // rule initXCell(Init) => ... + KRewrite body = (KRewrite) ((Rule) s).body(); + KApply left = (KApply) body.left(); + KApply right = (KApply) body.right(); + return left.klabel().name().equals(initLabel) // initXCell + && right.klabel().name().equals(cellLabel); // + } catch (ClassCastException ignored) { + return false; } - - // Step 2. - /* - * From the following stdin stream reference rule: - * rule read() => V ... - * - * ListItem(V:Int) => .List - * ... - * - * - * Generate the following auxiliary rule: - * rule read() ... - * - * `.List => ListItem(#parseInput("Int", " \n\t\r"))` - * ListItem(#buffer(_:String)) - * ... - * - */ - private java.util.Set getStdinStreamUnblockingRules(Production streamProduction, - java.util.Set sentences) { - KLabel userCellLabel = streamProduction.klabel().get(); // - - // find rules with currently supported matching patterns - java.util.Set> rules = new HashSet<>(); - for (Sentence s : sentences) { - if (s instanceof Rule rule) { - java.util.List sorts = isSupportingRulePatternAndGetSortNameOfCast(streamProduction, rule); - assert sorts.size() <= 1; - if (sorts.size() == 1) { - rules.add(Tuple2.apply(rule, sorts.get(0))); - } - } - } - - // generate additional unblocking rules for each of the above rules - java.util.Set newSentences = new HashSet<>(); - for (Tuple2 r : rules) { - Rule rule = r._1(); - String sort = r._2(); - - K body = new TransformK() { + } + + // Get an initializer rule from the built-in *-STREAM module + private KList getContentsOfInitRule(Production streamProduction) { + String streamName = streamProduction.att().get(Att.STREAM()); // stdin, stdout + String initLabel = + GenerateSentencesFromConfigDecl.getInitLabel( + Sort( + GenerateSentencesFromConfigDecl.getSortOfCell( + streamName))); // initStdinCell, initStdoutCell + String cellLabel = "<" + streamName + ">"; // , + + java.util.List initRules = + stream(getStreamModule(streamName).localSentences()) + .filter(s -> isInitRule(initLabel, cellLabel, s)) + .toList(); + assert initRules.size() == 1; + Sentence initRule = initRules.get(0); + + // rule initXCell(Init) => ... + KRewrite body = (KRewrite) ((Rule) initRule).body(); + KApply right = (KApply) body.right(); + return right.klist(); + } + + // Step 3. + // get sentences from stream module: + // - productions whose sort is `Stream` + // - rules that have `stream` attribute, but changing cell names according to user-defined one. + private java.util.Set getStreamModuleSentences(Production streamProduction) { + String streamName = streamProduction.att().get(Att.STREAM()); // stdin, stdout + String builtinCellLabel = "<" + streamName + ">"; // , + KLabel userCellLabel = streamProduction.klabel().get(); // , + + java.util.Set sentences = new HashSet<>(); + for (Sentence s : mutable(getStreamModule(streamName).localSentences())) { + if (s instanceof Rule rule) { + if (rule.att().contains(Att.STREAM())) { + // Update cell names + K body = + new TransformK() { @Override public K apply(KApply k) { - if (k.klabel().name().equals(userCellLabel.name())) { - return getUnblockRuleBody(streamProduction, sort); - } else { - return super.apply(k); - } + k = (KApply) super.apply(k); + return KApply(apply(k.klabel()), k.klist(), k.att()); } - @Override - public K apply(KRewrite k) { - // drop rhs - return apply(k.left()); + private KLabel apply(KLabel klabel) { + if (klabel.name().equals(builtinCellLabel)) { + return userCellLabel; + } else { + return klabel; + } } - }.apply(rule.body()); + }.apply(rule.body()); - rule = Rule(body, rule.requires(), rule.ensures(), rule.att()); - newSentences.add(rule); + rule = Rule(body, rule.requires(), rule.ensures(), rule.att()); + sentences.add(rule); + } else if (rule.att().contains(Att.PROJECTION())) { + sentences.add(rule); } - - return newSentences; + } else if (s instanceof Production production) { + if (production.sort().toString().equals("Stream") + || production.att().contains(Att.PROJECTION())) { + sentences.add(production); + } + } + } + return sentences; + } + + private Module getStreamModule(String streamName) { + // TODO(Daejun): fix hard-coded stream module naming convention + String moduleName = streamName.toUpperCase() + "-STREAM"; + Option module = definition.getModule(moduleName); + if (module.isDefined()) { + return module.get(); + } else { + throw KEMException.compilerError("no such module: " + moduleName); + } + } + + // Step 2. + /* + * From the following stdin stream reference rule: + * rule read() => V ... + * + * ListItem(V:Int) => .List + * ... + * + * + * Generate the following auxiliary rule: + * rule read() ... + * + * `.List => ListItem(#parseInput("Int", " \n\t\r"))` + * ListItem(#buffer(_:String)) + * ... + * + */ + private java.util.Set getStdinStreamUnblockingRules( + Production streamProduction, java.util.Set sentences) { + KLabel userCellLabel = streamProduction.klabel().get(); // + + // find rules with currently supported matching patterns + java.util.Set> rules = new HashSet<>(); + for (Sentence s : sentences) { + if (s instanceof Rule rule) { + java.util.List sorts = + isSupportingRulePatternAndGetSortNameOfCast(streamProduction, rule); + assert sorts.size() <= 1; + if (sorts.size() == 1) { + rules.add(Tuple2.apply(rule, sorts.get(0))); + } + } } - // return (a list of) sort names of cast if the given rule has the supported pattern matching over input stream cell, - // otherwise return empty. - // currently, the list of sort names of cast should be a singleton. - /* - * Currently supported rule pattern is: - * rule read() => V ... - * - * ListItem(V:Int) => .List - * ... - * - */ - private java.util.List isSupportingRulePatternAndGetSortNameOfCast(Production streamProduction, Rule rule) { - KLabel userCellLabel = streamProduction.klabel().get(); // - - java.util.List sorts = new ArrayList<>(); - new VisitK() { + // generate additional unblocking rules for each of the above rules + java.util.Set newSentences = new HashSet<>(); + for (Tuple2 r : rules) { + Rule rule = r._1(); + String sort = r._2(); + + K body = + new TransformK() { @Override - public void apply(KApply k) { - if (k.klabel().name().equals(userCellLabel.name())) { - String sort = wellformedAndGetSortNameOfCast(k.klist()); - if (!sort.isEmpty()) { - sorts.add(sort); - } else { - if (k.att().getOption(Location.class).isDefined()) { // warning only for user-provided rules - throw KEMException.compilerError("Unsupported matching pattern in stdin stream cell." + - "\nThe currently supported pattern is: ListItem(V:Sort) => .List ... ", k); - } - } - } - super.apply(k); + public K apply(KApply k) { + if (k.klabel().name().equals(userCellLabel.name())) { + return getUnblockRuleBody(streamProduction, sort); + } else { + return super.apply(k); + } } - // TODO(Daejun): it support only pattern matching on the top of stream. - // more patterns need to be supported as well. - /* - * Return cast sort name if well formed, otherwise empty string. - * - * klist is well formed if it consists of: - * #noDots(.KList) - * ListItem(#SemanticCastToInt(V)) => .List - * #dots(.KList) - * - * which comes from, e.g.,: - * ListItem(V:Int) => .List ... - */ - private String wellformedAndGetSortNameOfCast(KList klist) { - try { - if (klist.size() == 3) { - KApply k1 = (KApply) klist.items().get(0); - KApply k3 = (KApply) klist.items().get(2); - if (KLabels.NO_DOTS.equals(k1.klabel()) && k1.klist().size() == 0 && - KLabels.DOTS.equals(k3.klabel()) && k3.klist().size() == 0) { - - KRewrite k2 = (KRewrite) klist.items().get(1); - KApply k2l = (KApply) k2.left(); - KApply k2r = (KApply) k2.right(); - if (k2l.klabel().name().equals("ListItem") && k2l.klist().size() == 1 && - k2r.klabel().name().equals(".List") && k2r.klist().size() == 0) { - - KApply k2li = (KApply) k2l.klist().items().get(0); - if (k2li.klabel().name().startsWith("#SemanticCastTo") && k2li.klist().size() == 1 && - k2li.klist().items().get(0) instanceof KVariable) { - return ResolveSemanticCasts.getSortNameOfCast(k2li); // k2li.klabel().name().substring("#SemanticCastTo".length()); - } - } - } - } - } catch (ClassCastException ignored) { - } - return ""; + @Override + public K apply(KRewrite k) { + // drop rhs + return apply(k.left()); } - }.apply(rule.body()); + }.apply(rule.body()); - return sorts; + rule = Rule(body, rule.requires(), rule.ensures(), rule.att()); + newSentences.add(rule); } - // get rule body of the `[unblock]` rule (it should exist an unique one), - // instantiating with proper `Sort` and `Delimiters` values. - // this method should be called with stdin stream production, not with stdout stream. - /* - * Currently supporting generated rule would be: - * rule read() ... - * - * `.List => ListItem(#parseInput("Int", " \n\t\r"))` - * ListItem(#buffer(_:String)) - * ... - * - */ - private K getUnblockRuleBody(Production streamProduction, String sort) { - String streamName = streamProduction.att().get(Att.STREAM()); - assert streamName.equals("stdin"); // stdin - String builtinCellLabel = "<" + streamName + ">"; // - KLabel userCellLabel = streamProduction.klabel().get(); // - - java.util.List unblockRules = stream(getStreamModule(streamName).localSentences()) - .filter(s -> s instanceof Rule && s.att().getOptional(Att.LABEL()).map(lbl -> lbl.equals("STDIN-STREAM.stdinUnblock")).orElse(false)).toList(); - assert unblockRules.size() == 1; - Rule unblockRule = (Rule) unblockRules.get(0); - - return new TransformK() { - @Override - public K apply(KApply k) { - if (k.klabel().name().equals("#SemanticCastToString") && k.klist().size() == 1) { - K i = k.klist().items().get(0); - if (i instanceof KVariable x) { - switch (x.name()) { - case "?Sort": - return KToken("\"" + sort + "\"", Sorts.String()); - case "?Delimiters": - // TODO(Daejun): support `delimiter` attribute in stream cell - return KToken("\" \\n\\t\\r\"", Sorts.String()); - default: - // fall through - } - } - } - k = (KApply) super.apply(k); - return KApply(apply(k.klabel()), k.klist(), k.att()); + return newSentences; + } + + // return (a list of) sort names of cast if the given rule has the supported pattern matching over + // input stream cell, + // otherwise return empty. + // currently, the list of sort names of cast should be a singleton. + /* + * Currently supported rule pattern is: + * rule read() => V ... + * + * ListItem(V:Int) => .List + * ... + * + */ + private java.util.List isSupportingRulePatternAndGetSortNameOfCast( + Production streamProduction, Rule rule) { + KLabel userCellLabel = streamProduction.klabel().get(); // + + java.util.List sorts = new ArrayList<>(); + new VisitK() { + @Override + public void apply(KApply k) { + if (k.klabel().name().equals(userCellLabel.name())) { + String sort = wellformedAndGetSortNameOfCast(k.klist()); + if (!sort.isEmpty()) { + sorts.add(sort); + } else { + if (k.att() + .getOption(Location.class) + .isDefined()) { // warning only for user-provided rules + throw KEMException.compilerError( + "Unsupported matching pattern in stdin stream cell.\n" + + "The currently supported pattern is: ListItem(V:Sort) => .List ..." + + " ", + k); } - - private KLabel apply(KLabel klabel) { - if (klabel.name().equals(builtinCellLabel)) { - return userCellLabel; - } else { - return klabel; + } + } + super.apply(k); + } + + // TODO(Daejun): it support only pattern matching on the top of stream. + // more patterns need to be supported as well. + /* + * Return cast sort name if well formed, otherwise empty string. + * + * klist is well formed if it consists of: + * #noDots(.KList) + * ListItem(#SemanticCastToInt(V)) => .List + * #dots(.KList) + * + * which comes from, e.g.,: + * ListItem(V:Int) => .List ... + */ + private String wellformedAndGetSortNameOfCast(KList klist) { + try { + if (klist.size() == 3) { + KApply k1 = (KApply) klist.items().get(0); + KApply k3 = (KApply) klist.items().get(2); + if (KLabels.NO_DOTS.equals(k1.klabel()) + && k1.klist().size() == 0 + && KLabels.DOTS.equals(k3.klabel()) + && k3.klist().size() == 0) { + + KRewrite k2 = (KRewrite) klist.items().get(1); + KApply k2l = (KApply) k2.left(); + KApply k2r = (KApply) k2.right(); + if (k2l.klabel().name().equals("ListItem") + && k2l.klist().size() == 1 + && k2r.klabel().name().equals(".List") + && k2r.klist().size() == 0) { + + KApply k2li = (KApply) k2l.klist().items().get(0); + if (k2li.klabel().name().startsWith("#SemanticCastTo") + && k2li.klist().size() == 1 + && k2li.klist().items().get(0) instanceof KVariable) { + return ResolveSemanticCasts.getSortNameOfCast( + k2li); // k2li.klabel().name().substring("#SemanticCastTo".length()); } + } } - }.apply(unblockRule.body()); - } + } + } catch (ClassCastException ignored) { + } + return ""; + } + }.apply(rule.body()); + + return sorts; + } + + // get rule body of the `[unblock]` rule (it should exist an unique one), + // instantiating with proper `Sort` and `Delimiters` values. + // this method should be called with stdin stream production, not with stdout stream. + /* + * Currently supporting generated rule would be: + * rule read() ... + * + * `.List => ListItem(#parseInput("Int", " \n\t\r"))` + * ListItem(#buffer(_:String)) + * ... + * + */ + private K getUnblockRuleBody(Production streamProduction, String sort) { + String streamName = streamProduction.att().get(Att.STREAM()); + assert streamName.equals("stdin"); // stdin + String builtinCellLabel = "<" + streamName + ">"; // + KLabel userCellLabel = streamProduction.klabel().get(); // + + java.util.List unblockRules = + stream(getStreamModule(streamName).localSentences()) + .filter( + s -> + s instanceof Rule + && s.att() + .getOptional(Att.LABEL()) + .map(lbl -> lbl.equals("STDIN-STREAM.stdinUnblock")) + .orElse(false)) + .toList(); + assert unblockRules.size() == 1; + Rule unblockRule = (Rule) unblockRules.get(0); + + return new TransformK() { + @Override + public K apply(KApply k) { + if (k.klabel().name().equals("#SemanticCastToString") && k.klist().size() == 1) { + K i = k.klist().items().get(0); + if (i instanceof KVariable x) { + switch (x.name()) { + case "?Sort": + return KToken("\"" + sort + "\"", Sorts.String()); + case "?Delimiters": + // TODO(Daejun): support `delimiter` attribute in stream cell + return KToken("\" \\n\\t\\r\"", Sorts.String()); + default: + // fall through + } + } + } + k = (KApply) super.apply(k); + return KApply(apply(k.klabel()), k.klist(), k.att()); + } + private KLabel apply(KLabel klabel) { + if (klabel.name().equals(builtinCellLabel)) { + return userCellLabel; + } else { + return klabel; + } + } + }.apply(unblockRule.body()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveSemanticCasts.java b/kernel/src/main/java/org/kframework/compile/ResolveSemanticCasts.java index abf21c3ab5a..ced3d3f2e5e 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveSemanticCasts.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveSemanticCasts.java @@ -1,153 +1,160 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; import org.kframework.builtin.BooleanUtils; import org.kframework.definition.Context; import org.kframework.definition.RuleOrClaim; import org.kframework.definition.Sentence; +import org.kframework.kore.AddAtt; import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KVariable; import org.kframework.kore.Sort; -import org.kframework.kore.AddAtt; import org.kframework.kore.TransformK; import org.kframework.kore.VisitK; import org.kframework.parser.outer.Outer; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - -/** - * Created by dwightguth on 4/17/15. - */ +/** Created by dwightguth on 4/17/15. */ public class ResolveSemanticCasts { - private final boolean skipSortPredicates; - private final Set casts = new HashSet<>(); - private final Map varToTypedVar = new HashMap<>(); - - public ResolveSemanticCasts(boolean skipSortPredicates) { - - this.skipSortPredicates = skipSortPredicates; - } - - void resetCasts() { - casts.clear(); - varToTypedVar.clear(); - } - - public K resolve(K k) { - resetCasts(); - gatherCasts(k); - return transform(k); - } - - private RuleOrClaim resolve(RuleOrClaim rule) { - resetCasts(); - gatherCasts(rule.body()); - gatherCasts(rule.requires()); - gatherCasts(rule.ensures()); - return rule.newInstance( - transform(rule.body()), - addSideCondition(transform(rule.requires()), ExpandMacros.isMacro(rule)), - transform(rule.ensures()), - rule.att()); - } - - private Context resolve(Context context) { - resetCasts(); - gatherCasts(context.body()); - gatherCasts(context.requires()); - return new Context( - transform(context.body()), - addSideCondition(transform(context.requires()), false), - context.att()); - } - - K addSideCondition(K requires, boolean macro) { - if (skipSortPredicates || macro) - return requires; - else { - Optional sideCondition = casts.stream().map(k -> { - return new TransformK() { - @Override - public K apply(KVariable k) { + private final boolean skipSortPredicates; + private final Set casts = new HashSet<>(); + private final Map varToTypedVar = new HashMap<>(); + + public ResolveSemanticCasts(boolean skipSortPredicates) { + + this.skipSortPredicates = skipSortPredicates; + } + + void resetCasts() { + casts.clear(); + varToTypedVar.clear(); + } + + public K resolve(K k) { + resetCasts(); + gatherCasts(k); + return transform(k); + } + + private RuleOrClaim resolve(RuleOrClaim rule) { + resetCasts(); + gatherCasts(rule.body()); + gatherCasts(rule.requires()); + gatherCasts(rule.ensures()); + return rule.newInstance( + transform(rule.body()), + addSideCondition(transform(rule.requires()), ExpandMacros.isMacro(rule)), + transform(rule.ensures()), + rule.att()); + } + + private Context resolve(Context context) { + resetCasts(); + gatherCasts(context.body()); + gatherCasts(context.requires()); + return new Context( + transform(context.body()), + addSideCondition(transform(context.requires()), false), + context.att()); + } + + K addSideCondition(K requires, boolean macro) { + if (skipSortPredicates || macro) return requires; + else { + Optional sideCondition = + casts.stream() + .map( + k -> { + return new TransformK() { + @Override + public K apply(KVariable k) { if (varToTypedVar.containsKey(k)) { - return varToTypedVar.get(k); + return varToTypedVar.get(k); } return k; - } - }.apply(k); - }).map(k -> KApply(KLabel("is" + getSortNameOfCast((KApply) k)), transform(k))).reduce(BooleanUtils::and); - if (!sideCondition.isPresent()) { - return requires; - } else if (requires.equals(BooleanUtils.TRUE) && sideCondition.isPresent()) { - return sideCondition.get(); - } else { - return BooleanUtils.and(sideCondition.get(), requires); - } - } + } + }.apply(k); + }) + .map(k -> KApply(KLabel("is" + getSortNameOfCast((KApply) k)), transform(k))) + .reduce(BooleanUtils::and); + if (!sideCondition.isPresent()) { + return requires; + } else if (requires.equals(BooleanUtils.TRUE) && sideCondition.isPresent()) { + return sideCondition.get(); + } else { + return BooleanUtils.and(sideCondition.get(), requires); + } } - - public static String getSortNameOfCast(KApply kapp) { - return kapp.klabel().name().substring("#SemanticCastTo".length()); - } - - void gatherCasts(K term) { - new VisitK() { - @Override - public void apply(KApply v) { - if (v.klabel().name().startsWith("#SemanticCastTo")) { - casts.add(v); - K child = v.klist().items().get(0); - if (child instanceof KVariable var) { - varToTypedVar.put(var, KVariable(var.name(), var.att().contains(Sort.class) ? var.att() : var.att().add(Sort.class, Outer.parseSort(getSortNameOfCast(v))))); - } - } - super.apply(v); - } - }.apply(term); - } - - K transform(K term) { - return new TransformK() { - private Sort sort; - - @Override - public K apply(K k) { - final Sort oldSort = sort; - K applied; - if (casts.contains(k)) { - KApply kapp = (KApply)k; - sort = Outer.parseSort(getSortNameOfCast(kapp)); - applied = apply(kapp.items().get(0)); - } else { - sort = null; - applied = super.apply(k); - } - if (oldSort != null) { - return new AddAtt(a -> a.add(Sort.class, oldSort)).apply(applied); - } - if (varToTypedVar.containsKey(applied)) { - return varToTypedVar.get(applied); - } - return applied; - } - }.apply(term); - } - - public synchronized Sentence resolve(Sentence s) { - if (s instanceof RuleOrClaim) { - return resolve((RuleOrClaim) s); - } else if (s instanceof Context) { - return resolve((Context) s); + } + + public static String getSortNameOfCast(KApply kapp) { + return kapp.klabel().name().substring("#SemanticCastTo".length()); + } + + void gatherCasts(K term) { + new VisitK() { + @Override + public void apply(KApply v) { + if (v.klabel().name().startsWith("#SemanticCastTo")) { + casts.add(v); + K child = v.klist().items().get(0); + if (child instanceof KVariable var) { + varToTypedVar.put( + var, + KVariable( + var.name(), + var.att().contains(Sort.class) + ? var.att() + : var.att().add(Sort.class, Outer.parseSort(getSortNameOfCast(v))))); + } + } + super.apply(v); + } + }.apply(term); + } + + K transform(K term) { + return new TransformK() { + private Sort sort; + + @Override + public K apply(K k) { + final Sort oldSort = sort; + K applied; + if (casts.contains(k)) { + KApply kapp = (KApply) k; + sort = Outer.parseSort(getSortNameOfCast(kapp)); + applied = apply(kapp.items().get(0)); } else { - return s; + sort = null; + applied = super.apply(k); + } + if (oldSort != null) { + return new AddAtt(a -> a.add(Sort.class, oldSort)).apply(applied); + } + if (varToTypedVar.containsKey(applied)) { + return varToTypedVar.get(applied); } + return applied; + } + }.apply(term); + } + + public synchronized Sentence resolve(Sentence s) { + if (s instanceof RuleOrClaim) { + return resolve((RuleOrClaim) s); + } else if (s instanceof Context) { + return resolve((Context) s); + } else { + return s; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/ResolveStrict.java b/kernel/src/main/java/org/kframework/compile/ResolveStrict.java index bda4d83e756..e626d1f33a8 100644 --- a/kernel/src/main/java/org/kframework/compile/ResolveStrict.java +++ b/kernel/src/main/java/org/kframework/compile/ResolveStrict.java @@ -1,10 +1,22 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.Hooks; -import org.kframework.builtin.Sorts; import org.kframework.definition.*; import org.kframework.definition.Module; import org.kframework.kompile.KompileOptions; @@ -17,234 +29,274 @@ import org.kframework.parser.outer.Outer; import org.kframework.utils.StringUtil; import org.kframework.utils.errorsystem.KEMException; -import org.kframework.Collections; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - import scala.Option; -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - public class ResolveStrict { - private final KompileOptions kompileOptions; - private final Definition d; + private final KompileOptions kompileOptions; + private final Definition d; - private Module currentModule; + private Module currentModule; - public ResolveStrict(KompileOptions kompileOptions, Definition d) { - this.kompileOptions = kompileOptions; - this.d = d; - } + public ResolveStrict(KompileOptions kompileOptions, Definition d) { + this.kompileOptions = kompileOptions; + this.d = d; + } - public Set resolve(Set strictProductions) { - Set sentences = new HashSet<>(); - for (Production prod : strictProductions) { - if (!prod.klabel().isDefined()) { - throw KEMException.compilerError("Only productions with a KLabel can be strict.", prod); - } - if (prod.att().contains(Att.STRICT())) { - sentences.addAll(resolve(prod, false)); - } - if (prod.att().contains(Att.SEQSTRICT())) { - sentences.addAll(resolve(prod, true)); - } - } - return sentences; + public Set resolve(Set strictProductions) { + Set sentences = new HashSet<>(); + for (Production prod : strictProductions) { + if (!prod.klabel().isDefined()) { + throw KEMException.compilerError("Only productions with a KLabel can be strict.", prod); + } + if (prod.att().contains(Att.STRICT())) { + sentences.addAll(resolve(prod, false)); + } + if (prod.att().contains(Att.SEQSTRICT())) { + sentences.addAll(resolve(prod, true)); + } } + return sentences; + } - private static KApply cast(Sort sort, K k) { - return KApply(KLabel("#SemanticCastTo" + sort.toString()), k); - } + private static KApply cast(Sort sort, K k) { + return KApply(KLabel("#SemanticCastTo" + sort.toString()), k); + } - public static void setPositions(String attribute, List strictnessPositions, long arity, Production loc) { - String[] strictAttrs = attribute.split(","); - for (String strictAttr : strictAttrs) { - try { - int pos = Integer.parseInt(strictAttr.trim()); - if (pos < 1 || pos > arity) - throw new IndexOutOfBoundsException(); - strictnessPositions.add(pos); - } catch (NumberFormatException | IndexOutOfBoundsException e) { - if (arity == 0) { - throw KEMException.compilerError("Cannot put a strict attribute on a production with no nonterminals", loc); - } else { - throw KEMException.compilerError( - "Expecting a number between 1 and " + arity + ", but found " + strictAttr + " as a" + - " strict position in " + Arrays.toString(strictAttrs), - loc); - } - } + public static void setPositions( + String attribute, List strictnessPositions, long arity, Production loc) { + String[] strictAttrs = attribute.split(","); + for (String strictAttr : strictAttrs) { + try { + int pos = Integer.parseInt(strictAttr.trim()); + if (pos < 1 || pos > arity) throw new IndexOutOfBoundsException(); + strictnessPositions.add(pos); + } catch (NumberFormatException | IndexOutOfBoundsException e) { + if (arity == 0) { + throw KEMException.compilerError( + "Cannot put a strict attribute on a production with no nonterminals", loc); + } else { + throw KEMException.compilerError( + "Expecting a number between 1 and " + + arity + + ", but found " + + strictAttr + + " as a" + + " strict position in " + + Arrays.toString(strictAttrs), + loc); } + } } + } - private void setAliases(String attribute, Set aliases, Production prod) { - String[] strictAttrs = attribute.split(","); - for (String strictAttr : strictAttrs) { - String label = strictAttr.trim(); - Option> ss = d.mainModule().labeled().get(label); - if (ss.isDefined()) { - for (Sentence s : iterable(ss.get())) { - if (s instanceof ContextAlias) { - aliases.add((ContextAlias)s); - } else { - throw KEMException.compilerError("Found rule label \"" + label + "\" in strictness attribute of production " + prod + " which does not refer to a context alias.", s); - } - } - } else { - throw KEMException.compilerError("Found rule label \"" + label + "\" in strictness attribute which did not refer to any sentence.", prod); - } + private void setAliases(String attribute, Set aliases, Production prod) { + String[] strictAttrs = attribute.split(","); + for (String strictAttr : strictAttrs) { + String label = strictAttr.trim(); + Option> ss = d.mainModule().labeled().get(label); + if (ss.isDefined()) { + for (Sentence s : iterable(ss.get())) { + if (s instanceof ContextAlias) { + aliases.add((ContextAlias) s); + } else { + throw KEMException.compilerError( + "Found rule label \"" + + label + + "\" in strictness attribute of production " + + prod + + " which does not refer to a context alias.", + s); + } } - + } else { + throw KEMException.compilerError( + "Found rule label \"" + + label + + "\" in strictness attribute which did not refer to any sentence.", + prod); + } } + } + + private static final ContextAlias DEFAULT_ALIAS = + ContextAlias(KVariable("HERE"), BooleanUtils.TRUE, Att.empty()); + + private void resolve( + boolean sequential, + Set sentences, + long arity, + List strictnessPositions, + List allPositions, + Set aliases, + Production production) { + for (int i = 0; i < strictnessPositions.size(); i++) { + List items = new ArrayList<>(); + for (int j = 0; j < arity; j++) { + // Preserve sort information of the production + items.add(cast(production.nonterminal(j).sort(), KVariable("K" + j))); + } + int strictnessPosition = strictnessPositions.get(i) - 1; + K hole; + // Preserve sort information of the production + hole = cast(production.nonterminal(strictnessPosition).sort(), KVariable("HOLE")); - private static final ContextAlias DEFAULT_ALIAS = ContextAlias(KVariable("HERE"), BooleanUtils.TRUE, Att.empty()); - - private void resolve(boolean sequential, Set sentences, long arity, List strictnessPositions, List allPositions, Set aliases, Production production) { - for (int i = 0; i < strictnessPositions.size(); i++) { - List items = new ArrayList<>(); - for (int j = 0; j < arity; j++) { - // Preserve sort information of the production - items.add(cast(production.nonterminal(j).sort(), KVariable("K" + j))); - } - int strictnessPosition = strictnessPositions.get(i) - 1; - K hole; - // Preserve sort information of the production - hole = cast(production.nonterminal(strictnessPosition).sort(), KVariable("HOLE")); - - for (ContextAlias alias : aliases) { - K body = new TransformK() { - @Override - public K apply(KVariable var) { - if (var.name().equals("HERE")) { - K thisHole = hole; - if (alias.att().contains(Att.CONTEXT())) { - KLabel contextLabel = KLabel(alias.att().get(Att.CONTEXT())); - thisHole = KRewrite(hole, KApply(contextLabel, hole)); - } - items.set(strictnessPosition, thisHole); - return KApply(production.klabel().get(), KList(items)); - } - return var; - } - }.apply(alias.body()); - - Sort result = Outer.parseSort(alias.att().getOptional(Att.RESULT()).orElse("KResult")); - - // is seqstrict the elements before the argument should be KResult - Optional sideCondition = Stream.concat(allPositions.stream(), strictnessPositions.subList(0, i).stream()).map(j -> KApply(KLabel("is" + result.toString()), KVariable("K" + (j - 1)))).reduce(BooleanUtils::and); - K requires; - if (!sideCondition.isPresent() || !sequential) { - requires = BooleanUtils.TRUE; - } else { - requires = sideCondition.get(); + for (ContextAlias alias : aliases) { + K body = + new TransformK() { + @Override + public K apply(KVariable var) { + if (var.name().equals("HERE")) { + K thisHole = hole; + if (alias.att().contains(Att.CONTEXT())) { + KLabel contextLabel = KLabel(alias.att().get(Att.CONTEXT())); + thisHole = KRewrite(hole, KApply(contextLabel, hole)); + } + items.set(strictnessPosition, thisHole); + return KApply(production.klabel().get(), KList(items)); } + return var; + } + }.apply(alias.body()); - String label = currentModule.name() + "." + production.klabelAtt().get().replace("`", "").replaceAll("\\s", "") + (strictnessPosition+1); + Sort result = Outer.parseSort(alias.att().getOptional(Att.RESULT()).orElse("KResult")); - Context ctx = Context(body, BooleanUtils.and(requires, alias.requires()), production.att().addAll(alias.att()).add(Att.LABEL(), label)); - sentences.add(ctx); - } + // is seqstrict the elements before the argument should be KResult + Optional sideCondition = + Stream.concat(allPositions.stream(), strictnessPositions.subList(0, i).stream()) + .map(j -> KApply(KLabel("is" + result.toString()), KVariable("K" + (j - 1)))) + .reduce(BooleanUtils::and); + K requires; + if (!sideCondition.isPresent() || !sequential) { + requires = BooleanUtils.TRUE; + } else { + requires = sideCondition.get(); } + + String label = + currentModule.name() + + "." + + production.klabelAtt().get().replace("`", "").replaceAll("\\s", "") + + (strictnessPosition + 1); + + Context ctx = + Context( + body, + BooleanUtils.and(requires, alias.requires()), + production.att().addAll(alias.att()).add(Att.LABEL(), label)); + sentences.add(ctx); + } } + } - public Set resolve(Production production, boolean sequential) { - long arity = production.nonterminals().size(); - List strictnessPositions = new ArrayList<>(); - List allPositions = new ArrayList<>(); - Set aliases = new HashSet<>(); - String attribute; - Set sentences = new HashSet<>(); - if (sequential) { - attribute = production.att().get(Att.SEQSTRICT()); + public Set resolve(Production production, boolean sequential) { + long arity = production.nonterminals().size(); + List strictnessPositions = new ArrayList<>(); + List allPositions = new ArrayList<>(); + Set aliases = new HashSet<>(); + String attribute; + Set sentences = new HashSet<>(); + if (sequential) { + attribute = production.att().get(Att.SEQSTRICT()); + } else { + attribute = production.att().get(Att.STRICT()); + } + if (attribute.isEmpty()) { + for (int i = 1; i <= arity; i++) { + strictnessPositions.add(i); + } + aliases.add(DEFAULT_ALIAS); + resolve(sequential, sentences, arity, strictnessPositions, allPositions, aliases, production); + allPositions.addAll(strictnessPositions); + } else { + String[] components = attribute.split(";"); + if (components.length == 1) { + if (Character.isDigit(components[0].trim().charAt(0))) { + aliases.add(DEFAULT_ALIAS); + setPositions(components[0].trim(), strictnessPositions, arity, production); } else { - attribute = production.att().get(Att.STRICT()); + for (int i = 1; i <= arity; i++) { + strictnessPositions.add(i); + } + setAliases(components[0].trim(), aliases, production); } - if (attribute.isEmpty()) { - for (int i = 1; i <= arity; i++) { - strictnessPositions.add(i); - } - aliases.add(DEFAULT_ALIAS); - resolve(sequential, sentences, arity, strictnessPositions, allPositions, aliases, production); - allPositions.addAll(strictnessPositions); - } else { - String[] components = attribute.split(";"); - if (components.length == 1) { - if (Character.isDigit(components[0].trim().charAt(0))) { - aliases.add(DEFAULT_ALIAS); - setPositions(components[0].trim(), strictnessPositions, arity, production); - } else { - for (int i = 1; i <= arity; i++) { - strictnessPositions.add(i); - } - setAliases(components[0].trim(), aliases, production); - } - resolve(sequential, sentences, arity, strictnessPositions, allPositions, aliases, production); - allPositions.addAll(strictnessPositions); - } else if (components.length % 2 == 0) { - for (int i = 0; i < components.length; i+=2) { - setAliases(components[i].trim(), aliases, production); - setPositions(components[i+1].trim(), strictnessPositions, arity, production); - resolve(sequential, sentences, arity, strictnessPositions, allPositions, aliases, production); - aliases.clear(); - allPositions.addAll(strictnessPositions); - strictnessPositions.clear(); - } - } else { - throw KEMException.compilerError("Invalid strict attribute containing multiple semicolons.", production); - } + resolve( + sequential, sentences, arity, strictnessPositions, allPositions, aliases, production); + allPositions.addAll(strictnessPositions); + } else if (components.length % 2 == 0) { + for (int i = 0; i < components.length; i += 2) { + setAliases(components[i].trim(), aliases, production); + setPositions(components[i + 1].trim(), strictnessPositions, arity, production); + resolve( + sequential, sentences, arity, strictnessPositions, allPositions, aliases, production); + aliases.clear(); + allPositions.addAll(strictnessPositions); + strictnessPositions.clear(); } + } else { + throw KEMException.compilerError( + "Invalid strict attribute containing multiple semicolons.", production); + } + } - if (production.att().contains(Att.HYBRID())) { - List results = new ArrayList<>(); - if (!production.att().get(Att.HYBRID()).equals("")) { - String[] sorts = StringUtil.splitOneDimensionalAtt(production.att().get(Att.HYBRID())); - for (String sort : sorts) { - results.add(KLabel("is" + sort)); - } - } else { - results.add(KLabel("isKResult")); - } - for (KLabel result : results) { - List items = new ArrayList<>(); - for (int j = 0; j < arity; j++) { - // Preserve sort information of the production - items.add(cast(production.nonterminal(j).sort(), KVariable("K" + j))); - } - K term = KApply(production.klabel().get(), KList(items)); - Optional sideCondition = allPositions.stream().map(j -> KApply(result, KVariable("K" + (j - 1)))).reduce(BooleanUtils::and); - K requires; - if (!sideCondition.isPresent()) { - requires = BooleanUtils.TRUE; - } else { - requires = sideCondition.get(); - } - Rule hybrid = Rule(KRewrite(KApply(result, term), BooleanUtils.TRUE), requires, BooleanUtils.TRUE); - sentences.add(hybrid); - } + if (production.att().contains(Att.HYBRID())) { + List results = new ArrayList<>(); + if (!production.att().get(Att.HYBRID()).equals("")) { + String[] sorts = StringUtil.splitOneDimensionalAtt(production.att().get(Att.HYBRID())); + for (String sort : sorts) { + results.add(KLabel("is" + sort)); + } + } else { + results.add(KLabel("isKResult")); + } + for (KLabel result : results) { + List items = new ArrayList<>(); + for (int j = 0; j < arity; j++) { + // Preserve sort information of the production + items.add(cast(production.nonterminal(j).sort(), KVariable("K" + j))); } - return sentences; + K term = KApply(production.klabel().get(), KList(items)); + Optional sideCondition = + allPositions.stream() + .map(j -> KApply(result, KVariable("K" + (j - 1)))) + .reduce(BooleanUtils::and); + K requires; + if (!sideCondition.isPresent()) { + requires = BooleanUtils.TRUE; + } else { + requires = sideCondition.get(); + } + Rule hybrid = + Rule(KRewrite(KApply(result, term), BooleanUtils.TRUE), requires, BooleanUtils.TRUE); + sentences.add(hybrid); + } } + return sentences; + } - public Module resolve(Module input) { - currentModule = input; - Set contextsToAdd = resolve(stream(input.localSentences()) + public Module resolve(Module input) { + currentModule = input; + Set contextsToAdd = + resolve( + stream(input.localSentences()) .filter(s -> s instanceof Production) .map(s -> (Production) s) - .filter(p -> p.att().contains(Att.STRICT()) || p.att().contains(Att.SEQSTRICT())).collect(Collectors.toSet())); - scala.collection.Set imports = input.imports(); - // strictness makes use _andBool_ found in the BOOL module. Make sure it's imported - if (!contextsToAdd.isEmpty() && !input.importedModuleNames().contains(Hooks.BOOL)) - imports = (scala.collection.Set) Set(Import.apply(d.getModule(Hooks.BOOL).get(), false)).$bar(imports); - return Module(input.name(), imports, (scala.collection.Set) stream(input.localSentences()).filter(s -> !(s instanceof ContextAlias)).collect(Collections.toSet()).$bar(immutable(contextsToAdd)), input.att()); - } + .filter(p -> p.att().contains(Att.STRICT()) || p.att().contains(Att.SEQSTRICT())) + .collect(Collectors.toSet())); + scala.collection.Set imports = input.imports(); + // strictness makes use _andBool_ found in the BOOL module. Make sure it's imported + if (!contextsToAdd.isEmpty() && !input.importedModuleNames().contains(Hooks.BOOL)) + imports = + (scala.collection.Set) + Set(Import.apply(d.getModule(Hooks.BOOL).get(), false)).$bar(imports); + return Module( + input.name(), + imports, + (scala.collection.Set) + stream(input.localSentences()) + .filter(s -> !(s instanceof ContextAlias)) + .collect(Collections.toSet()) + .$bar(immutable(contextsToAdd)), + input.att()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/RewriteAwareTransformer.java b/kernel/src/main/java/org/kframework/compile/RewriteAwareTransformer.java index a4e90e08dfe..3e1301113c7 100644 --- a/kernel/src/main/java/org/kframework/compile/RewriteAwareTransformer.java +++ b/kernel/src/main/java/org/kframework/compile/RewriteAwareTransformer.java @@ -1,55 +1,55 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import org.kframework.kore.K; import org.kframework.kore.KRewrite; import org.kframework.kore.TransformK; -import static org.kframework.kore.KORE.*; - /** - * A visitor designed to track whether we are currently in the left hand side or right hand side of a term. + * A visitor designed to track whether we are currently in the left hand side or right hand side of + * a term. * - * This visitor provides two boolean methods, isRHS() and isLHS(). Outside of a rewrite, both are true, signifying - * that the term being visited is part of both the LHS and the RHS. Inside a rewrite, only one is true. It is an error - * for both to be false. + *

This visitor provides two boolean methods, isRHS() and isLHS(). Outside of a rewrite, both are + * true, signifying that the term being visited is part of both the LHS and the RHS. Inside a + * rewrite, only one is true. It is an error for both to be false. */ public class RewriteAwareTransformer extends TransformK { - public RewriteAwareTransformer(boolean isBody) { - if (isBody) { - isRHS = true; - isLHS = true; - } else { - isRHS = true; - isLHS = false; - } + public RewriteAwareTransformer(boolean isBody) { + if (isBody) { + isRHS = true; + isLHS = true; + } else { + isRHS = true; + isLHS = false; } - - - private boolean isRHS; - private boolean isLHS; - - public boolean isLHS() { - return isLHS; - } - - public boolean isRHS() { - return isRHS; - } - - @Override - public K apply(KRewrite k) { - isRHS = false; - K left = apply(k.left()); - isRHS = true; - isLHS = false; - K right = apply(k.right()); - isLHS = true; - if (left != k.left() || right != k.right()) { - return KRewrite(left, right, k.att()); - } else { - return k; - } + } + + private boolean isRHS; + private boolean isLHS; + + public boolean isLHS() { + return isLHS; + } + + public boolean isRHS() { + return isRHS; + } + + @Override + public K apply(KRewrite k) { + isRHS = false; + K left = apply(k.left()); + isRHS = true; + isLHS = false; + K right = apply(k.right()); + isLHS = true; + if (left != k.left() || right != k.right()) { + return KRewrite(left, right, k.att()); + } else { + return k; } + } } diff --git a/kernel/src/main/java/org/kframework/compile/RewriteAwareVisitor.java b/kernel/src/main/java/org/kframework/compile/RewriteAwareVisitor.java index 06b1269af05..72045be9dd1 100644 --- a/kernel/src/main/java/org/kframework/compile/RewriteAwareVisitor.java +++ b/kernel/src/main/java/org/kframework/compile/RewriteAwareVisitor.java @@ -1,86 +1,90 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.Set; import org.kframework.kore.KApply; import org.kframework.kore.KRewrite; import org.kframework.kore.KVariable; import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - /** - * A visitor designed to track whether we are currently in the left hand side or right hand side of a term. + * A visitor designed to track whether we are currently in the left hand side or right hand side of + * a term. * - * This visitor provides two boolean methods, isRHS() and isLHS(). Outside of a rewrite, both are true, signifying - * that the term being visited is part of both the LHS and the RHS. Inside a rewrite, only one is true. It is an error - * for both to be false. + *

This visitor provides two boolean methods, isRHS() and isLHS(). Outside of a rewrite, both are + * true, signifying that the term being visited is part of both the LHS and the RHS. Inside a + * rewrite, only one is true. It is an error for both to be false. */ public class RewriteAwareVisitor extends VisitK { - private final Set errors; - public RewriteAwareVisitor(boolean isBody, Set errors) { - this.errors = errors; - if (isBody) { - isRHS = true; - isLHS = true; - } else { - isRHS = true; - isLHS = false; - } + private final Set errors; + + public RewriteAwareVisitor(boolean isBody, Set errors) { + this.errors = errors; + if (isBody) { + isRHS = true; + isLHS = true; + } else { + isRHS = true; + isLHS = false; } + } + private boolean isRHS; + private boolean isLHS; - private boolean isRHS; - private boolean isLHS; + public boolean isLHS() { + return isLHS; + } - public boolean isLHS() { - return isLHS; - } + public boolean isRHS() { + return isRHS; + } - public boolean isRHS() { - return isRHS; - } + @Override + public void apply(KRewrite k) { + isRHS = false; + apply(k.left()); + isRHS = true; + isLHS = false; + apply(k.right()); + isLHS = true; + } - @Override - public void apply(KRewrite k) { + @Override + public void apply(KApply k) { + if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#fun2") + || k.klabel().name().equals("#fun3") + || k.klabel().name().equals("#let")) { + boolean wasRHS = isRHS; + boolean wasLHS = isLHS; + if (k.klabel().name().equals("#fun2")) { + isRHS = true; + isLHS = true; + apply(k.items().get(0)); + // in well formed programs this should always reset to true and false, but we want to make + // sure we don't + // create spurious reports if this constraint was violated by the user. + isRHS = wasRHS; + isLHS = wasLHS; + apply(k.items().get(1)); + } else { isRHS = false; - apply(k.left()); + isLHS = true; + apply(k.items().get(0)); isRHS = true; isLHS = false; - apply(k.right()); - isLHS = true; - } - - @Override - public void apply(KApply k) { - if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#fun2") || k.klabel().name().equals("#fun3") || k.klabel().name().equals("#let")) { - boolean wasRHS = isRHS; - boolean wasLHS = isLHS; - if (k.klabel().name().equals("#fun2")) { - isRHS = true; - isLHS = true; - apply(k.items().get(0)); - // in well formed programs this should always reset to true and false, but we want to make sure we don't - // create spurious reports if this constraint was violated by the user. - isRHS = wasRHS; - isLHS = wasLHS; - apply(k.items().get(1)); - } else { - isRHS = false; - isLHS = true; - apply(k.items().get(0)); - isRHS = true; - isLHS = false; - apply(k.items().get(1)); - // in well formed programs this should always reset to true and false, but we want to make sure we don't - // create spurious reports if this constraint was violated by the user. - isRHS = wasRHS; - isLHS = wasLHS; - apply(k.items().get(2)); - } - } else { - super.apply(k); - } + apply(k.items().get(1)); + // in well formed programs this should always reset to true and false, but we want to make + // sure we don't + // create spurious reports if this constraint was violated by the user. + isRHS = wasRHS; + isLHS = wasLHS; + apply(k.items().get(2)); + } + } else { + super.apply(k); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/SortCells.java b/kernel/src/main/java/org/kframework/compile/SortCells.java index faaffb962ec..a5aff6766d2 100644 --- a/kernel/src/main/java/org/kframework/compile/SortCells.java +++ b/kernel/src/main/java/org/kframework/compile/SortCells.java @@ -1,9 +1,24 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nonnull; import org.kframework.attributes.Att; import org.kframework.builtin.BooleanUtils; import org.kframework.builtin.Sorts; @@ -25,859 +40,910 @@ import scala.collection.JavaConversions; import scala.collection.Seq; -import javax.annotation.Nonnull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - /** - * Arrange cell contents and variables to match the klabels declared for cells. - * In Full K, cell contents can be written in any order, and variables can - * be written that match multiple cells. - *

- * In the input to this pass, parent cells are represented by appling the label directly - * to a klist of all the children, variables, and rewrites under the cell. - * Left cells should already be in their final form. - * In the output each cell will be represented by using the cell labels in agreement - * with the production declaring it, so parent cells will have a fixed arity with separate + * Arrange cell contents and variables to match the klabels declared for cells. In Full K, cell + * contents can be written in any order, and variables can be written that match multiple cells. + * + *

In the input to this pass, parent cells are represented by appling the label directly to a + * klist of all the children, variables, and rewrites under the cell. Left cells should already be + * in their final form. In the output each cell will be represented by using the cell labels in + * agreement with the production declaring it, so parent cells will have a fixed arity with separate * argument positions reserved for different types of child cell. - *

- * The most complicated part of the transformation is dealing with variables - * in cells. An occurrence in a cell that might match child cells of different - * sorts has to be split into several variables in different arguments, and any - * occurrence of the variable outside of a cell replaced by a suitable - * expression involving the split variables, using the cell fragment productions + * + *

The most complicated part of the transformation is dealing with variables in cells. An + * occurrence in a cell that might match child cells of different sorts has to be split into several + * variables in different arguments, and any occurrence of the variable outside of a cell replaced + * by a suitable expression involving the split variables, using the cell fragment productions * introduced along with the cell labels. */ public class SortCells { - private final ConcretizationInfo cfg; - private final LabelInfo labelInfo; - private final Module module; - public SortCells(ConfigurationInfo cfgInfo, LabelInfo labelInfo, Module module) { - this.cfg = new ConcretizationInfo(cfgInfo, labelInfo); - this.labelInfo = labelInfo; - this.module = module; - } - public SortCells(ConfigurationInfo cfgInfo, LabelInfo labelInfo) { - this.cfg = new ConcretizationInfo(cfgInfo, labelInfo); - this.labelInfo = labelInfo; - this.module = null; + private final ConcretizationInfo cfg; + private final LabelInfo labelInfo; + private final Module module; + + public SortCells(ConfigurationInfo cfgInfo, LabelInfo labelInfo, Module module) { + this.cfg = new ConcretizationInfo(cfgInfo, labelInfo); + this.labelInfo = labelInfo; + this.module = module; + } + + public SortCells(ConfigurationInfo cfgInfo, LabelInfo labelInfo) { + this.cfg = new ConcretizationInfo(cfgInfo, labelInfo); + this.labelInfo = labelInfo; + this.module = null; + } + + public synchronized K sortCells(K term) { + resetVars(); + analyzeVars(term); + return processVars(term); + } + + private RuleOrClaim sortCells(RuleOrClaim rule) { + resetVars(); + analyzeVars(rule.body()); + analyzeVars(rule.requires()); + analyzeVars(rule.ensures()); + rule = + rule.newInstance( + processVars(rule.body()), + processVars(rule.requires()), + processVars(rule.ensures()), + rule.att()); + rule = + rule.newInstance( + resolveIncompleteCellFragment(rule.body()), + resolveIncompleteCellFragment(rule.requires()), + resolveIncompleteCellFragment(rule.ensures()), + rule.att()); + return rule; + } + + private Context sortCells(Context context) { + resetVars(); + analyzeVars(context.body()); + analyzeVars(context.requires()); + return new Context(processVars(context.body()), processVars(context.requires()), context.att()); + } + + public synchronized Sentence sortCells(Sentence s) { + if (s instanceof RuleOrClaim) { + return sortCells((RuleOrClaim) s); + } else if (s instanceof Context) { + return sortCells((Context) s); + } else { + return s; } - - public synchronized K sortCells(K term) { - resetVars(); - analyzeVars(term); - return processVars(term); - + } + + // Information on uses of a particular cell fragment variable + private class VarInfo { + KVariable var; + KLabel parentCell; + LinkedHashSet remainingCells; + Map split; + + void addOccurances(KLabel cell, KVariable var, List items) { + assert split == null; // need to add all occurances before getting any split. + this.var = var; + if (parentCell == null) { + parentCell = cell; + } else if (!parentCell.equals(cell)) { + throw KEMException.criticalError( + "Cell variable " + var + " used under two cells, " + parentCell + " and " + cell); + } + if (remainingCells == null) { + remainingCells = new LinkedHashSet<>(cfg.getChildren(cell)); + } + if (var.att().contains(Sort.class)) { + Sort sort = var.att().get(Sort.class); + if (cfg.cfg().isCell(sort)) { + remainingCells.removeIf(s -> !s.equals(sort)); + } + } + for (K item : items) { + if (item instanceof KApply kApply) { + Sort s = cfg.getCellSort(kApply.klabel()); + if (s != null && cfg.getMultiplicity(s) != Multiplicity.STAR) { + remainingCells.remove(s); + } + } else if (item instanceof KVariable && !item.equals(var)) { + if (item.att().contains(Sort.class)) { + Sort sort = item.att().get(Sort.class); + remainingCells.remove(sort); + } + } + } } - private RuleOrClaim sortCells(RuleOrClaim rule) { - resetVars(); - analyzeVars(rule.body()); - analyzeVars(rule.requires()); - analyzeVars(rule.ensures()); - rule = rule.newInstance( - processVars(rule.body()), - processVars(rule.requires()), - processVars(rule.ensures()), - rule.att()); - rule = rule.newInstance( - resolveIncompleteCellFragment(rule.body()), - resolveIncompleteCellFragment(rule.requires()), - resolveIncompleteCellFragment(rule.ensures()), - rule.att()); - return rule; + K replacementTerm() { + getSplit(var); + KLabel fragmentLabel = cfg.getCellFragmentLabel(parentCell); + if (fragmentLabel == null) { + throw KEMException.compilerError( + "Unsupported cell fragment with types: " + remainingCells, var); + } + List children = cfg.getChildren(parentCell); + List arguments = new ArrayList<>(children.size()); + for (Sort child : children) { + K arg = split.get(child); + if (arg == null) { + if (cfg.getMultiplicity(child) == Multiplicity.ONE) { + arg = cfg.getCellAbsentTerm(child); + } else { + arg = cfg.cfg().getUnit(child); + } + } + assert arg != null; + arguments.add(arg); + } + return KApply(fragmentLabel, immutable(arguments)); } - private Context sortCells(Context context) { - resetVars(); - analyzeVars(context.body()); - analyzeVars(context.requires()); - return new Context( - processVars(context.body()), - processVars(context.requires()), - context.att()); + Map getSplit(KVariable var) { + if (split != null) { + return split; + } + if (remainingCells.size() == 0) { + split = Collections.emptyMap(); + } else if (remainingCells.size() == 1) { + Sort s = Iterables.getOnlyElement(remainingCells); + if (cfg.getMultiplicity(s) == Multiplicity.STAR) { + split = + ImmutableMap.of( + s, KVariable(var.name(), var.att().add(Sort.class, getPredicateSort(s)))); + } else { + split = + ImmutableMap.of( + s, KVariable(var.name(), var.att().add(Sort.class, s).add(Att.CELL_SORT()))); + } + } else { + split = new HashMap<>(); + for (Sort cell : remainingCells) { + split.put(cell, newDotVariable(var.att().add(Sort.class, cell).add(Att.CELL_SORT()))); + } + } + return split; } + } + + private int counter = 0; + + KVariable newDotVariable(Att att) { + KVariable newLabel; + do { + newLabel = KVariable("_Gen" + (counter++), att); + } while (variables.containsKey(newLabel) || previousVars.contains(newLabel)); + variables.put(newLabel, null); + return newLabel; + } + + private final Map variables = new HashMap<>(); + private final Map cellVariables = new HashMap<>(); + private final Set previousVars = new HashSet<>(); + + private void resetVars() { + variables.clear(); + cellVariables.clear(); + previousVars.clear(); + counter = 0; + } + + private void analyzeVars(K term) { + new VisitK() { + private boolean inRewrite = false; + private boolean inRhs = false; + + private Stream streamCells(K term) { + return IncompleteCellUtils.flattenCells(term).stream(); + } - public synchronized Sentence sortCells(Sentence s) { - if (s instanceof RuleOrClaim) { - return sortCells((RuleOrClaim) s); - } else if (s instanceof Context) { - return sortCells((Context) s); + private K left(K term) { + if (term instanceof KRewrite) { + return ((KRewrite) term).left(); } else { - return s; + return term; } - } + } - // Information on uses of a particular cell fragment variable - private class VarInfo { - KVariable var; - KLabel parentCell; - LinkedHashSet remainingCells; - Map split; - - void addOccurances(KLabel cell, KVariable var, List items) { - assert split == null; // need to add all occurances before getting any split. - this.var = var; - if (parentCell == null) { - parentCell = cell; - } else if (!parentCell.equals(cell)) { - throw KEMException.criticalError("Cell variable "+var+" used under two cells, " - + parentCell + " and " + cell); - } - if (remainingCells == null) { - remainingCells = new LinkedHashSet<>(cfg.getChildren(cell)); - } - if (var.att().contains(Sort.class)) { - Sort sort = var.att().get(Sort.class); - if (cfg.cfg().isCell(sort)) { - remainingCells.removeIf(s -> !s.equals(sort)); - } - } - for (K item : items) { - if (item instanceof KApply kApply) { - Sort s = cfg.getCellSort(kApply.klabel()); - if (s != null && cfg.getMultiplicity(s) != Multiplicity.STAR) { - remainingCells.remove(s); - } - } else if (item instanceof KVariable && !item.equals(var)) { - if (item.att().contains(Sort.class)) { - Sort sort = item.att().get(Sort.class); - remainingCells.remove(sort); - } - } - } + private K right(K term) { + if (term instanceof KRewrite) { + return ((KRewrite) term).right(); + } else { + return term; } + } - K replacementTerm() { - getSplit(var); - KLabel fragmentLabel = cfg.getCellFragmentLabel(parentCell); - if (fragmentLabel == null) { - throw KEMException.compilerError("Unsupported cell fragment with types: " + remainingCells, var); - } - List children = cfg.getChildren(parentCell); - List arguments = new ArrayList<>(children.size()); - for (Sort child : children) { - K arg = split.get(child); - if (arg == null) { - if (cfg.getMultiplicity(child) == Multiplicity.ONE) { - arg = cfg.getCellAbsentTerm(child); - } else { - arg = cfg.cfg().getUnit(child); - } - } - assert arg != null; - arguments.add(arg); - } - return KApply(fragmentLabel, immutable(arguments)); + @Override + public void apply(KApply k) { + if (cfg.isParentCell(k.klabel())) { + if (inRewrite) { + processSide( + k, + inRhs, + k.klist().stream().flatMap(this::streamCells).collect(Collectors.toList())); + } else { + processSide( + k, + false, + k.klist().stream() + .flatMap(this::streamCells) + .map(this::left) + .flatMap(this::streamCells) + .collect(Collectors.toList())); + + processSide( + k, + true, + k.klist().stream() + .flatMap(this::streamCells) + .map(this::right) + .flatMap(this::streamCells) + .collect(Collectors.toList())); + } } + super.apply(k); + } - Map getSplit(KVariable var) { - if(split != null) { - return split; - } - if (remainingCells.size() == 0) { - split = Collections.emptyMap(); - } else if (remainingCells.size() == 1) { - Sort s = Iterables.getOnlyElement(remainingCells); - if (cfg.getMultiplicity(s) == Multiplicity.STAR) { - split = ImmutableMap.of(s, KVariable( - var.name(), - var.att().add(Sort.class, getPredicateSort(s)))); - } else { - split = ImmutableMap.of(s, KVariable(var.name(), var.att().add(Sort.class, s).add(Att.CELL_SORT()))); + private void processSide(KApply parentCell, boolean allowRhs, List items) { + List bagVars = new ArrayList<>(); + for (K item : items) { + if (item instanceof KVariable var) { + if (var.att().contains(Sort.class)) { + Sort sort = var.att().get(Sort.class); + if (cfg.cfg().isCell(sort)) { + if (!cellVariables.getOrDefault(var, sort).equals(sort)) { + Sort prevSort = cellVariables.get(var); + throw KEMException.compilerError( + "Variable " + + var + + " occurs annotated as multiple cell sorts, " + + sort + + " and " + + prevSort, + item); } - } else { - split = new HashMap<>(); - for (Sort cell : remainingCells) { - split.put(cell, newDotVariable(var.att().add(Sort.class, cell).add(Att.CELL_SORT()))); + if (variables.containsKey(var)) { + throw KEMException.compilerError( + "Variable " + + var + + " occurs with cell sort " + + sort + + " after occurance without cell sort annotation"); + } + cellVariables.put(var, sort); + continue; + } else { + if (cellVariables.containsKey(var)) { + throw KEMException.compilerError( + "Variable " + + var + + " occurs annotated as non-cell sort " + + sort + + " after appearing as cell sort " + + cellVariables.get(var), + item); } + } } - return split; + if (cellVariables.containsKey(var)) { + throw KEMException.compilerError( + "Variable " + + var + + " occurs without sort annotation after appearing as cell sort " + + cellVariables.get(var), + item); + } + bagVars.add(var); + } } - } + if (!allowRhs && bagVars.size() > 1) { + throw KEMException.compilerError( + "AC matching of multiple cell variables not yet supported. " + + "encountered variables " + + bagVars + + " in cell " + + parentCell.klabel(), + parentCell); + } + for (KVariable var : bagVars) { + if (!variables.containsKey(var)) { + variables.put(var, new VarInfo()); + } + variables.get(var).addOccurances(parentCell.klabel(), var, items); + } + } + @Override + public void apply(KRewrite k) { + assert !inRewrite; + inRewrite = true; + apply(k.left()); + inRhs = true; + apply(k.right()); + inRhs = false; + inRewrite = false; + } - private int counter = 0; - KVariable newDotVariable(Att att) { - KVariable newLabel; - do { - newLabel = KVariable("_Gen" + (counter++), att); - } while (variables.containsKey(newLabel) || previousVars.contains(newLabel)); - variables.put(newLabel, null); - return newLabel; + @Override + public void apply(KVariable k) { + previousVars.add(k); + } + }.apply(term); + } + + private Sort getPredicateSort(Sort s) { + if (cfg.getMultiplicity(s) == Multiplicity.STAR) { + scala.collection.Set sorts = cfg.cfg().getCellBagSortsOfCell(s); + if (sorts.size() != 1) { + throw KEMException.compilerError( + "Expected exactly one cell collection sort for the sort " + s + "; found " + sorts); + } + return stream(sorts).findFirst().get(); } - - private final Map variables = new HashMap<>(); - private final Map cellVariables = new HashMap<>(); - private final Set previousVars = new HashSet<>(); - - private void resetVars() { - variables.clear(); cellVariables.clear(); previousVars.clear(); counter = 0; + return s; + } + + private boolean isCellFragmentTest(KApply app) { + if (app.klist().size() != 1) return false; + K argument = app.klist().items().get(0); + if (!(argument instanceof KVariable)) return false; + VarInfo info = variables.get((KVariable) argument); + if (info == null) return false; + KLabel expectedPredicate = + KLabel("is" + cfg.getCellSort(info.parentCell).toString() + "Fragment"); + return app.klabel().equals(expectedPredicate); + } + + private int indexOf(List l, Sort o, KApply loc) { + int idx = l.indexOf(o); + if (idx == -1) { + throw KEMException.compilerError( + "Expected to find sort " + + o.toString() + + " in the children of cell with klabel " + + loc.klabel(), + loc); } - - private void analyzeVars(K term) { - new VisitK() { - private boolean inRewrite = false; - private boolean inRhs = false; - - private Stream streamCells(K term) { - return IncompleteCellUtils.flattenCells(term).stream(); + return idx; + } + + /** + * Expand away cell fragment variables, and correctly order the children of cells. There are three + * significnat contexts for expanding cell fragments - as an argument to a parent cell it splits + * into separate arguments for each of the variables in most other uses, it expands into a term + * applying the appropriate {@code -fragment} label to the split variables, except that + * applications of an {@code isCellFragment} sort predicate to a cell fragment variable decomposes + * into a conjunction of sort predicate tests on the split variables. + */ + private K processVars(K term) { + return new TransformK() { + @Override + public K apply(KApply k) { + if (!cfg.isParentCell(k.klabel())) { + if (isCellFragmentTest(k)) { + return getSplit(k.klist().items().get(0)).entrySet().stream() + .map(e -> (K) KApply(KLabel("is" + getPredicateSort(e.getKey())), e.getValue())) + .reduce(BooleanUtils.TRUE, BooleanUtils::and); + } else if (k.klabel().name().equals("isBag") + && k.klist().size() == 1 + && k.klist().items().get(0) instanceof KVariable var) { + VarInfo info = variables.get(var); + if (info != null) { + return info.getSplit(var).entrySet().stream() + .map(e -> (K) KApply(KLabel("is" + getPredicateSort(e.getKey())), e.getValue())) + .reduce(BooleanUtils.TRUE, BooleanUtils::and); } - - private K left(K term) { - if (term instanceof KRewrite) { - return ((KRewrite)term).left(); - } else { - return term; - } - } - private K right(K term) { - if (term instanceof KRewrite) { - return ((KRewrite)term).right(); - } else { - return term; - } + } + return super.apply(k); + } else { + List order = cfg.getChildren(k.klabel()); + ArrayList ordered = new ArrayList(Collections.nCopies(order.size(), null)); + for (K item : k.klist().items()) { + Map split = getSplit(item); + for (Map.Entry e : split.entrySet()) { + int idx = indexOf(order, e.getKey(), k); + if (ordered.get(idx) != null) { + ordered.set( + idx, + concatenateStarCells( + e.getKey(), Arrays.asList(ordered.get(idx), e.getValue()))); + } else { + ordered.set(idx, e.getValue()); + } } - - @Override - public void apply(KApply k) { - if (cfg.isParentCell(k.klabel())) { - if (inRewrite) { - processSide(k, inRhs, k.klist().stream() - .flatMap(this::streamCells) - .collect(Collectors.toList())); + } + order.stream() + .filter(s -> ordered.get(indexOf(order, s, k)) == null) + .forEach( + sort -> { + if (cfg.getMultiplicity(sort) == Multiplicity.ONE) { + throw KEMException.compilerError( + "Missing cell of multiplicity=\"1\": " + sort, k); } else { - processSide(k, false, k.klist().stream() - .flatMap(this::streamCells).map(this::left).flatMap(this::streamCells) - .collect(Collectors.toList())); - - processSide(k, true, k.klist().stream() - .flatMap(this::streamCells).map(this::right).flatMap(this::streamCells) - .collect(Collectors.toList())); + ordered.set(indexOf(order, sort, k), cfg.cfg().getUnit(sort)); } - } - super.apply(k); - } - - private void processSide(KApply parentCell, boolean allowRhs, List items) { - List bagVars = new ArrayList<>(); - for (K item : items) { - if (item instanceof KVariable var) { - if (var.att().contains(Sort.class)) { - Sort sort = var.att().get(Sort.class); - if (cfg.cfg().isCell(sort)) { - if (!cellVariables.getOrDefault(var, sort).equals(sort)) { - Sort prevSort = cellVariables.get(var); - throw KEMException.compilerError("Variable "+var+" occurs annotated as multiple cell sorts, "+sort+" and "+prevSort, - item); - } - if (variables.containsKey(var)) { - throw KEMException.compilerError("Variable "+var+" occurs with cell sort "+sort+" after occurance without cell sort annotation"); - } - cellVariables.put(var,sort); - continue; - } else { - if (cellVariables.containsKey(var)) { - throw KEMException.compilerError("Variable "+var+" occurs annotated as non-cell sort "+sort+" after appearing as cell sort "+cellVariables.get(var),item); - } - } - } - if (cellVariables.containsKey(var)) { - throw KEMException.compilerError("Variable "+var+" occurs without sort annotation after appearing as cell sort "+cellVariables.get(var),item); - } - bagVars.add(var); - } - } - if (!allowRhs && bagVars.size() > 1) { - throw KEMException.compilerError( - "AC matching of multiple cell variables not yet supported. " - + "encountered variables " + bagVars + " in cell " + parentCell.klabel(), parentCell); - } - for (KVariable var : bagVars) { - if (!variables.containsKey(var)) { - variables.put(var, new VarInfo()); - } - variables.get(var).addOccurances(parentCell.klabel(), var, items); - } - } + }); + return KApply(k.klabel(), KList(ordered), k.att()); + } + } - @Override - public void apply(KRewrite k) { - assert !inRewrite; - inRewrite = true; - apply(k.left()); - inRhs = true; - apply(k.right()); - inRhs = false; - inRewrite = false; + @Nonnull + private Map getSplit(K item) { + if (item instanceof KVariable) { + VarInfo info = variables.get(item); + if (info == null) { + Sort cellSort = cellVariables.get(item); + if (cellSort == null) { + throw new IllegalArgumentException("Unknown variable " + item); + } else { + return ImmutableMap.of(cellSort, item); } - - @Override - public void apply(KVariable k) { - previousVars.add(k); + } + return info.getSplit((KVariable) item); + } else if (item instanceof KApply) { + List children = IncompleteCellUtils.flattenCells(item); + if (children.size() == 1 && children.get(0) == item) { + final KLabel label = ((KApply) item).klabel(); + Sort s = cfg.getCellSort(label); + if (s == null) { + s = cfg.getCellCollectionCell(label); + if (s == null) { + throw KEMException.compilerError("Attempting to split non-cell term " + item, item); + } } - }.apply(term); - } - - private Sort getPredicateSort(Sort s) { - if (cfg.getMultiplicity(s) == Multiplicity.STAR) { - scala.collection.Set sorts = cfg.cfg().getCellBagSortsOfCell(s); - if (sorts.size() != 1) { - throw KEMException.compilerError("Expected exactly one cell collection sort for the sort " + s + "; found " + sorts); - } - return stream(sorts).findFirst().get(); + return Collections.singletonMap(s, apply(item)); + } + // flatten the List> into a Map> + Map> multiMap = + children.stream() + .flatMap(e -> getSplit(e).entrySet().stream()) + .collect( + Collectors.groupingBy( + Map.Entry::getKey, + Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); + return multiMap.entrySet().stream() + .filter(e -> e.getValue().size() > 0) + .collect( + Collectors.toMap( + e -> e.getKey(), + e -> { + if (e.getValue().size() == 1) { + return e.getValue().get(0); + } else { + return concatenateStarCells(e.getKey(), e.getValue()); + } + })); + } else if (item instanceof KRewrite rw) { + Map splitLeft = new HashMap<>(getSplit(rw.left())); + Map splitRight = new HashMap<>(getSplit(rw.right())); + addDefaultCells(item, splitLeft, splitRight); + addDefaultCells(item, splitRight, splitLeft); + assert splitLeft.keySet().equals(splitRight.keySet()); + return splitLeft.keySet().stream() + .collect( + Collectors.toMap( + sort -> sort, + sort -> KRewrite(splitLeft.get(sort), splitRight.get(sort), rw.att()))); + } else { + throw KEMException.compilerError( + "Unexpected kind of term found in cell. Expected variable, " + + "apply, or rewrite; found " + + item.getClass().getSimpleName(), + item); } - return s; - } + } - private boolean isCellFragmentTest(KApply app) { - if (app.klist().size() != 1) return false; - K argument = app.klist().items().get(0); - if (!(argument instanceof KVariable)) return false; - VarInfo info = variables.get((KVariable)argument); - if (info == null) return false; - KLabel expectedPredicate = KLabel("is"+cfg.getCellSort(info.parentCell).toString()+"Fragment"); - return app.klabel().equals(expectedPredicate); - } + private K concatenateStarCells(Sort sort, List children) { + if (cfg.getMultiplicity(sort) != Multiplicity.STAR) { + throw KEMException.compilerError( + "Attempting to concatenate cells not of multiplicity=\"*\" " + + "into a cell collection.", + children.iterator().next()); + } + if (children.size() == 0) { + return cfg.cfg().getUnit(sort); + } + KLabel concat = cfg.cfg().getConcat(sort); + int ix = children.size(); + K result = children.get(--ix); + while (ix > 0) { + result = KApply(concat, children.get(--ix), result); + } + return result; + } - private int indexOf(List l, Sort o, KApply loc) { - int idx = l.indexOf(o); - if (idx == -1) { - throw KEMException.compilerError("Expected to find sort " + o.toString() + " in the children of cell with klabel " + loc.klabel(), loc); + private void addDefaultCells(K item, Map splitLeft, Map splitRight) { + for (Sort s : Sets.difference(splitLeft.keySet(), splitRight.keySet())) { + if (cfg.getMultiplicity(s) == Multiplicity.ONE) { + throw KEMException.compilerError( + "Cannot rewrite a multiplicity=\"1\" cell to or from the cell unit.", item); + } else { + splitRight.put(s, cfg.cfg().getUnit(s)); + } + } } - return idx; - } - /** - * Expand away cell fragment variables, and correctly order the children of cells. - * There are three significnat contexts for expanding cell fragments - - * as an argument to a parent cell it splits into separate arguments for each of the variables - * in most other uses, it expands into a term applying the appropriate {@code -fragment} label - * to the split variables, except that applications of an {@code isCellFragment} sort predicate - * to a cell fragment variable decomposes into a conjunction of sort predicate tests on the split - * variables. - */ - private K processVars(K term) { - return new TransformK() { - @Override - public K apply(KApply k) { - if (!cfg.isParentCell(k.klabel())) { - if (isCellFragmentTest(k)) { - return getSplit(k.klist().items().get(0)).entrySet().stream() - .map(e -> (K) KApply(KLabel("is" + getPredicateSort(e.getKey())), e.getValue())) - .reduce(BooleanUtils.TRUE, BooleanUtils::and); - } else if(k.klabel().name().equals("isBag") - && k.klist().size() == 1 - && k.klist().items().get(0) instanceof KVariable var) { - VarInfo info = variables.get(var); - if (info != null) { - return info.getSplit(var).entrySet().stream() - .map(e -> (K) KApply(KLabel("is" + getPredicateSort(e.getKey())), e.getValue())) - .reduce(BooleanUtils.TRUE, BooleanUtils::and); - } + @Override + public K apply(KVariable v) { + VarInfo info = variables.get(v); + if (info != null) { + return info.replacementTerm(); + } else { + return v; + } + } + }.apply(term); + } + + /** + * processVars handles a cell fragment variable when it appears solely in a normal term, e.g, rule + * run => foo(X) ... X:XCellFragment _ but not when it appears with + * other cells, e.g., rule run => foo(X C) ... X:XCellFragment C + * resolveIncompleteCellFragment handles such cases, after processVars is done. An idea is to fix + * invalid cell fragment terms. For example, processVars translates the term `foo(X)` into: + * foo(-fragment A B -fragment C) then resolveIncompleteCellFragment fixes the term + * as: foo(-fragment A B C -fragment) + * + *

Another example: When a cell fragment term consists of only individual cells, processVars + * does nothing. rule run => foo(B C) ... _ B:BCell C:CCell In this + * case, resolveIncompleteCellFragment fixes the term `foo(B C)` into: foo(-fragment noACell B + * C -fragment) + * + *

Another example: When a cell fragment variable appears only in a normal term, but never in + * cells, processVars does nothing. rule foo( _ X:XCellFragment) => bar( 2 X) In + * this case, the cell fragment term in LHS is temporarily decorated by dummy cell label, + * before processVars, which triggers processVars to split the cell fragment variable. Then + * resolveIncompleteCellFragment comes in. After resolveIncompleteCellFragment, the dummy cell + * label is replaced by the corresponding cell fragment label. The pre-/post-processing is done by + * preprocess/prostprocess. + * + *

Potential issue: In the above example, if X has no sort casting, it is considered as + * XCellFragment by default, which may be different with an user's intention. + * + *

Another potential issue: Currently, one cannot represent a fully filled cell fragment term. + * e.g., rule foo(X) => .K ... _ => X The above rule replaces the entire cell + * with the cell fragment term X, but doesn't have a side condition saying that X should be + * fully decorated. It means that X is given by a partially decorated cell fragment, cell + * becomes invalid. e.g., foo(-fragment 1 noBCell noCCell -fragment) results in an + * invalid cell: 1 noBCell noCCell Note that this issue is not specifically + * about resolveIncompleteCellFragment. + */ + private K resolveIncompleteCellFragment(K term) { + return new TransformK() { + @Override + public K apply(KApply k0) { + if (!hasCells(k0)) return super.apply(k0); + + ArrayList klist0 = new ArrayList(Collections.nCopies(k0.klist().size(), null)); + for (int idx = 0; idx < k0.klist().size(); idx++) { + K item0 = k0.klist().items().get(idx); + klist0.set(idx, item0); + if (item0 instanceof KApply k) { + + // incomplete cells remain as #cells(...) after processVars + if (k.klabel().name().equals("#cells")) { + + Sort cellFragmentSort = nthArgSort(k0.klabel(), idx); + if (cellFragmentSort == null) { + throw new IllegalArgumentException( + "Not found " + idx + "th argument sort of " + k0.klabel()); + } + + // a cell fragment term + if (cellFragmentSort.name().endsWith("Fragment")) { + + Sort cellSort = + Sort( + cellFragmentSort + .name() + .substring(0, cellFragmentSort.name().indexOf("Fragment"))); + KLabel cellLabel = cfg.cfg().getCellLabel(cellSort); + + List subcellSorts = cfg.getChildren(cellLabel); + + /* + fix an invalid cell fragment term, e.g., + + Case 1. + from + foo(-fragment A B -fragment C) + into + foo(-fragment A B C -fragment) + + Case 2. + from + foo(B C) + into + foo(-fragment noACell B C -fragment) + */ + + // fill individual cells first, starting with empty + KApply cellFragment = null; + ArrayList klist = + new ArrayList(Collections.nCopies(subcellSorts.size(), null)); + for (K item : + IncompleteCellUtils.flattenCells(k)) { // #cells(#cells(x,y),z) => [x,y,z] + if (item instanceof KApply kapp) { + if (cfg.cfg().isCellLabel(kapp.klabel())) { + Sort sort = cfg.getCellSort(kapp.klabel()); + if (!subcellSorts.contains(sort)) { + throw new IllegalArgumentException( + "No such sub-cell " + sort + " in the cell " + cellLabel); + } + klist.set(subcellSorts.indexOf(sort), item); + } else if (kapp.klabel().name().endsWith("-fragment")) { + cellFragment = kapp; + assert cellFragment.klist().size() == subcellSorts.size(); + assert cellFragment.klabel().name().equals(cellLabel.name() + "-fragment"); + } else { + throw KEMException.compilerError("Unsupported cell fragment element.", item); } - return super.apply(k); - } else { - List order = cfg.getChildren(k.klabel()); - ArrayList ordered = new ArrayList(Collections.nCopies(order.size(), null)); - for (K item : k.klist().items()) { - Map split = getSplit(item); - for (Map.Entry e : split.entrySet()) { - int idx = indexOf(order, e.getKey(), k); - if (ordered.get(idx) != null) { - ordered.set(idx, concatenateStarCells(e.getKey(), Arrays.asList(ordered.get(idx), e.getValue()))); - } else { - ordered.set(idx, e.getValue()); - } - } + } else if (item instanceof KVariable var) { + VarInfo varinfo = null; + if (variables.containsKey(var)) { + varinfo = variables.get(var); } - order.stream().filter(s -> ordered.get(indexOf(order, s, k)) == null).forEach(sort -> { - if (cfg.getMultiplicity(sort) == Multiplicity.ONE) { - throw KEMException.compilerError("Missing cell of multiplicity=\"1\": " + sort, k); - } else { - ordered.set(indexOf(order, sort, k), cfg.cfg().getUnit(sort)); - } - }); - return KApply(k.klabel(), KList(ordered), k.att()); - } - } - - @Nonnull - private Map getSplit(K item) { - if (item instanceof KVariable) { - VarInfo info = variables.get(item); - if (info == null) { - Sort cellSort = cellVariables.get(item); - if (cellSort == null) { - throw new IllegalArgumentException("Unknown variable " + item); - } else { - return ImmutableMap.of(cellSort,item); - } + if (!var.att().contains(Sort.class) && varinfo != null) { + if (varinfo.var != null) var = varinfo.var; } - return info.getSplit((KVariable) item); - } else if (item instanceof KApply) { - List children = IncompleteCellUtils.flattenCells(item); - if(children.size() == 1 && children.get(0) == item) { - final KLabel label = ((KApply) item).klabel(); - Sort s = cfg.getCellSort(label); - if (s == null) { - s = cfg.getCellCollectionCell(label); - if (s == null) { - throw KEMException.compilerError("Attempting to split non-cell term " + item, item); + if (var.att().contains(Sort.class)) { + Sort sort = var.att().get(Sort.class); + if (cfg.cfg().isCell(sort)) { + if (!subcellSorts.contains(sort)) { + throw new IllegalArgumentException( + "No such sub-cell " + sort + " in the cell " + cellLabel); + } + klist.set(subcellSorts.indexOf(sort), item); + } else { + // if the variable is not explicitly sort-casted, then its sort information + // should be found in other places + if (varinfo != null + && varinfo.remainingCells != null + && varinfo.remainingCells.size() == 1) { + Sort s = Iterables.getOnlyElement(varinfo.remainingCells); + if (cfg.cfg().isCell(s)) { + if (!subcellSorts.contains(s)) { + throw new IllegalArgumentException( + "No such sub-cell " + s + " in the cell " + cellLabel); } + klist.set(subcellSorts.indexOf(s), item); + continue; + } } - return Collections.singletonMap(s, apply(item)); + throw KEMException.compilerError( + "Unsupported cell fragment element. Not found sort info.", item); + } + } else { + throw KEMException.compilerError( + "Unsupported cell fragment element. Not found sort info.", item); } - // flatten the List> into a Map> - Map> multiMap = children.stream().flatMap(e -> getSplit(e).entrySet().stream()).collect( - Collectors.groupingBy(Map.Entry::getKey, - Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); - return multiMap.entrySet().stream().filter(e -> e.getValue().size() > 0).collect(Collectors.toMap(e -> e.getKey(), e -> { - if (e.getValue().size() == 1) { - return e.getValue().get(0); - } else { - return concatenateStarCells(e.getKey(), e.getValue()); - } - })); - } else if (item instanceof KRewrite rw) { - Map splitLeft = new HashMap<>(getSplit(rw.left())); - Map splitRight = new HashMap<>(getSplit(rw.right())); - addDefaultCells(item, splitLeft, splitRight); - addDefaultCells(item, splitRight, splitLeft); - assert splitLeft.keySet().equals(splitRight.keySet()); - return splitLeft.keySet().stream().collect(Collectors.toMap(sort -> sort, - sort -> KRewrite(splitLeft.get(sort), splitRight.get(sort), rw.att()))); - } else { - throw KEMException.compilerError("Unexpected kind of term found in cell. Expected variable, " - + "apply, or rewrite; found " + item.getClass().getSimpleName(), item); - } - } - - private K concatenateStarCells(Sort sort, List children) { - if (cfg.getMultiplicity(sort) != Multiplicity.STAR) { - throw KEMException.compilerError("Attempting to concatenate cells not of multiplicity=\"*\" " - + "into a cell collection.", children.iterator().next()); - } - if (children.size() == 0) { - return cfg.cfg().getUnit(sort); - } - KLabel concat = cfg.cfg().getConcat(sort); - int ix = children.size(); - K result = children.get(--ix); - while (ix > 0) { - result = KApply(concat,children.get(--ix),result); + } else { + // TODO: support when item instanceof KRewrite + throw KEMException.compilerError("Unsupported cell fragment element.", item); + } } - return result; - } - private void addDefaultCells(K item, Map splitLeft, Map splitRight) { - for (Sort s : Sets.difference(splitLeft.keySet(), splitRight.keySet())) { - if (cfg.getMultiplicity(s) == Multiplicity.ONE) { - throw KEMException.compilerError("Cannot rewrite a multiplicity=\"1\" cell to or from the cell unit.", item); + // fill remaining cells, considering a split cell fragment variable if any + for (int i = 0; i < subcellSorts.size(); i++) { + if (klist.get(i) == null) { + if (cellFragment != null) { + klist.set(i, cellFragment.klist().items().get(i)); } else { - splitRight.put(s, cfg.cfg().getUnit(s)); + if (cfg.getMultiplicity(subcellSorts.get(i)) == Multiplicity.ONE) { + klist.set(i, cfg.getCellAbsentTerm(subcellSorts.get(i))); + } else { // Multiplicity.OPTIONAL || Multiplicity.STAR + klist.set(i, cfg.cfg().getUnit(subcellSorts.get(i))); + } } + } } - } - @Override - public K apply(KVariable v) { - VarInfo info = variables.get(v); - if (info != null) { - return info.replacementTerm(); - } else { - return v; - } + klist0.set(idx, KApply(KLabel(cellLabel.name() + "-fragment"), KList(klist))); + } } - }.apply(term); + } + } + return KApply(k0.klabel(), KList(klist0), k0.att()); + } + }.apply(term); + } + + /** Pre-process terms before processVar */ + public synchronized Sentence preprocess(Sentence s) { + if (s instanceof RuleOrClaim) { + return preprocess((RuleOrClaim) s); + } else { + return s; } - - - /** - * processVars handles a cell fragment variable when it appears solely in a normal term, e.g, - * rule run => foo(X) ... - * - * X:XCellFragment - * _ - * - * but not when it appears with other cells, e.g., - * rule run => foo(X C) ... - * - * X:XCellFragment - * C - * - * resolveIncompleteCellFragment handles such cases, after processVars is done. - * An idea is to fix invalid cell fragment terms. For example, processVars translates the term `foo(X)` into: - * foo(-fragment A B -fragment C) - * then resolveIncompleteCellFragment fixes the term as: - * foo(-fragment A B C -fragment) - * - * Another example: - * When a cell fragment term consists of only individual cells, processVars does nothing. - * rule run => foo(B C) ... - * - * _ - * B:BCell - * C:CCell - * - * In this case, resolveIncompleteCellFragment fixes the term `foo(B C)` into: - * foo(-fragment noACell B C -fragment) - * - * Another example: - * When a cell fragment variable appears only in a normal term, but never in cells, processVars does nothing. - * rule foo( _ X:XCellFragment) => bar( 2 X) - * In this case, the cell fragment term in LHS is temporarily decorated by dummy cell label, before processVars, - * which triggers processVars to split the cell fragment variable. Then resolveIncompleteCellFragment comes in. - * After resolveIncompleteCellFragment, the dummy cell label is replaced by the corresponding cell fragment label. - * The pre-/post-processing is done by preprocess/prostprocess. - * - * Potential issue: - * In the above example, if X has no sort casting, it is considered as XCellFragment by default, - * which may be different with an user's intention. - * - * Another potential issue: - * Currently, one cannot represent a fully filled cell fragment term. e.g., - * rule foo(X) => .K ... - * _ => X - * The above rule replaces the entire cell with the cell fragment term X, but doesn't have a side condition - * saying that X should be fully decorated. It means that X is given by a partially decorated cell fragment, - * cell becomes invalid. e.g., - * foo(-fragment 1 noBCell noCCell -fragment) - * results in an invalid cell: - * 1 noBCell noCCell - * Note that this issue is not specifically about resolveIncompleteCellFragment. - */ - private K resolveIncompleteCellFragment(K term) { - return new TransformK() { - @Override - public K apply(KApply k0) { - if (!hasCells(k0)) return super.apply(k0); - - ArrayList klist0 = new ArrayList(Collections.nCopies(k0.klist().size(), null)); - for (int idx = 0; idx < k0.klist().size(); idx++) { - K item0 = k0.klist().items().get(idx); - klist0.set(idx, item0); - if (item0 instanceof KApply k) { - - // incomplete cells remain as #cells(...) after processVars - if (k.klabel().name().equals("#cells")) { - - Sort cellFragmentSort = nthArgSort(k0.klabel(), idx); - if (cellFragmentSort == null) { - throw new IllegalArgumentException("Not found " + idx + "th argument sort of " + k0.klabel()); - } - - // a cell fragment term - if (cellFragmentSort.name().endsWith("Fragment")) { - - Sort cellSort = Sort(cellFragmentSort.name().substring(0,cellFragmentSort.name().indexOf("Fragment"))); - KLabel cellLabel = cfg.cfg().getCellLabel(cellSort); - - List subcellSorts = cfg.getChildren(cellLabel); - - /* - fix an invalid cell fragment term, e.g., - - Case 1. - from - foo(-fragment A B -fragment C) - into - foo(-fragment A B C -fragment) - - Case 2. - from - foo(B C) - into - foo(-fragment noACell B C -fragment) - */ - - // fill individual cells first, starting with empty - KApply cellFragment = null; - ArrayList klist = new ArrayList(Collections.nCopies(subcellSorts.size(), null)); - for (K item : IncompleteCellUtils.flattenCells(k)) { // #cells(#cells(x,y),z) => [x,y,z] - if (item instanceof KApply kapp) { - if (cfg.cfg().isCellLabel(kapp.klabel())) { - Sort sort = cfg.getCellSort(kapp.klabel()); - if (!subcellSorts.contains(sort)) { - throw new IllegalArgumentException("No such sub-cell " + sort + " in the cell " + cellLabel); - } - klist.set(subcellSorts.indexOf(sort), item); - } else if (kapp.klabel().name().endsWith("-fragment")) { - cellFragment = kapp; - assert cellFragment.klist().size() == subcellSorts.size(); - assert cellFragment.klabel().name().equals(cellLabel.name() + "-fragment"); - } else { - throw KEMException.compilerError("Unsupported cell fragment element.", item); - } - } else if (item instanceof KVariable var) { - VarInfo varinfo = null; - if (variables.containsKey(var)) { - varinfo = variables.get(var); - } - if (!var.att().contains(Sort.class) && varinfo != null) { - if (varinfo.var != null) - var = varinfo.var; - } - if (var.att().contains(Sort.class)) { - Sort sort = var.att().get(Sort.class); - if (cfg.cfg().isCell(sort)) { - if (!subcellSorts.contains(sort)) { - throw new IllegalArgumentException("No such sub-cell " + sort + " in the cell " + cellLabel); - } - klist.set(subcellSorts.indexOf(sort), item); - } else { - // if the variable is not explicitly sort-casted, then its sort information should be found in other places - if (varinfo != null && varinfo.remainingCells != null && varinfo.remainingCells.size() == 1) { - Sort s = Iterables.getOnlyElement(varinfo.remainingCells); - if (cfg.cfg().isCell(s)) { - if (!subcellSorts.contains(s)) { - throw new IllegalArgumentException("No such sub-cell " + s + " in the cell " + cellLabel); - } - klist.set(subcellSorts.indexOf(s), item); - continue; - } - } - throw KEMException.compilerError("Unsupported cell fragment element. Not found sort info.", item); - } - } else { - throw KEMException.compilerError("Unsupported cell fragment element. Not found sort info.", item); - } - } else { - // TODO: support when item instanceof KRewrite - throw KEMException.compilerError("Unsupported cell fragment element.", item); - } - } - - // fill remaining cells, considering a split cell fragment variable if any - for (int i = 0; i < subcellSorts.size(); i++) { - if (klist.get(i) == null) { - if (cellFragment != null) { - klist.set(i, cellFragment.klist().items().get(i)); - } else { - if (cfg.getMultiplicity(subcellSorts.get(i)) == Multiplicity.ONE) { - klist.set(i, cfg.getCellAbsentTerm(subcellSorts.get(i))); - } else { // Multiplicity.OPTIONAL || Multiplicity.STAR - klist.set(i, cfg.cfg().getUnit(subcellSorts.get(i))); - } - } - - } - } - - klist0.set(idx, KApply(KLabel(cellLabel.name() + "-fragment"), KList(klist))); - } - } + } + + /** Post-process terms after processVar */ + public synchronized Sentence postprocess(Sentence s) { + if (s instanceof RuleOrClaim) { + return postprocess((RuleOrClaim) s); + } else { + return s; + } + } + + private RuleOrClaim preprocess(RuleOrClaim rule) { + return rule.newInstance( + preprocess(rule.body()), + preprocess(rule.requires()), + preprocess(rule.ensures()), + rule.att()); + } + + private RuleOrClaim postprocess(RuleOrClaim rule) { + return rule.newInstance( + postprocess(rule.body()), + postprocess(rule.requires()), + postprocess(rule.ensures()), + rule.att()); + } + + /** + * When a cell fragment variable appears only in cell, e.g., rule foo( _ + * X:XCellFragment) => bar( 2 X) preprocess temporarily arguments the cell fragment term + * in LHS using its parent cell label, e.g., rule foo( _ X:XCellFragment ) => + * bar( 2 X) Now, the cell fragment variable X will be split by processVars. + */ + private K preprocess(K term) { + // find all of cell fragment variables + HashMap> cellFragmentVars = new HashMap<>(); + new VisitK() { + @Override + public void apply(KApply k) { + if (k.klabel().name().equals("#cells")) { + for (int i = 0; i < k.klist().size(); i++) { + K item = k.klist().items().get(i); + if (item instanceof KVariable var) { + if (var.att().contains(Sort.class)) { + Sort sort = var.att().get(Sort.class); + if (!cfg.cfg().isCell(sort)) { + if (!cellFragmentVars.containsKey(var)) { + cellFragmentVars.put(var, new HashSet<>()); + } + cellFragmentVars.get(var).add(k); + } + } else { + if (!cellFragmentVars.containsKey(var)) { + cellFragmentVars.put(var, new HashSet<>()); } + cellFragmentVars.get(var).add(k); + } } - return KApply(k0.klabel(), KList(klist0), k0.att()); + } + } else { + super.apply(k); } - }.apply(term); + } + }.apply(term); + + if (cellFragmentVars.isEmpty()) { + return term; } - /** - * Pre-process terms before processVar - */ - public synchronized Sentence preprocess(Sentence s) { - if (s instanceof RuleOrClaim) { - return preprocess((RuleOrClaim) s); - } else { - return s; + // drop cell fragment variables that appear outside cell, in non-function rules + if (!labelInfo.isFunction(term)) { + new VisitK() { + private boolean inKCell = false; + + @Override + public void apply(KApply k) { + if (k.klabel().name().equals("")) { + assert !inKCell; + inKCell = true; + super.apply(k); + inKCell = false; + } else { + super.apply(k); + } } - } - /** - * Post-process terms after processVar - */ - public synchronized Sentence postprocess(Sentence s) { - if (s instanceof RuleOrClaim) { - return postprocess((RuleOrClaim) s); - } else { - return s; + @Override + public void apply(KVariable var) { + if (!inKCell) { + cellFragmentVars.remove(var); + } } + }.apply(term); } - private RuleOrClaim preprocess(RuleOrClaim rule) { - return rule.newInstance( - preprocess(rule.body()), - preprocess(rule.requires()), - preprocess(rule.ensures()), - rule.att()); + if (cellFragmentVars.isEmpty()) { + return term; } - private RuleOrClaim postprocess(RuleOrClaim rule) { - return rule.newInstance( - postprocess(rule.body()), - postprocess(rule.requires()), - postprocess(rule.ensures()), - rule.att()); + HashSet cellFragmentVarsCell = new HashSet<>(); + for (HashSet cells : cellFragmentVars.values()) { + cellFragmentVarsCell.addAll(cells); } - /** - * When a cell fragment variable appears only in cell, e.g., - * rule foo( _ X:XCellFragment) => bar( 2 X) - * preprocess temporarily arguments the cell fragment term in LHS using its parent cell label, e.g., - * rule foo( _ X:XCellFragment ) => bar( 2 X) - * Now, the cell fragment variable X will be split by processVars. - */ - private K preprocess(K term) { - // find all of cell fragment variables - HashMap> cellFragmentVars = new HashMap<>(); - new VisitK() { - @Override - public void apply(KApply k) { - if (k.klabel().name().equals("#cells")) { - for (int i = 0; i < k.klist().size(); i++) { - K item = k.klist().items().get(i); - if (item instanceof KVariable var) { - if (var.att().contains(Sort.class)) { - Sort sort = var.att().get(Sort.class); - if (!cfg.cfg().isCell(sort)) { - if (!cellFragmentVars.containsKey(var)) { - cellFragmentVars.put(var, new HashSet<>()); - } - cellFragmentVars.get(var).add(k); - } - } else { - if (!cellFragmentVars.containsKey(var)) { - cellFragmentVars.put(var, new HashSet<>()); - } - cellFragmentVars.get(var).add(k); - } - } - } - } else { - super.apply(k); + // decorate such cell fragment terms with their parent cell label + return new TransformK() { + @Override + public K apply(KApply k0) { + if (hasCells(k0)) { + ArrayList klist0 = new ArrayList(Collections.nCopies(k0.klist().size(), null)); + for (int idx = 0; idx < k0.klist().size(); idx++) { + K item0 = k0.klist().items().get(idx); + klist0.set(idx, item0); + if (item0 instanceof KApply k) { + if (k.klabel().name().equals("#cells")) { + if (cellFragmentVarsCell.contains(k)) { + Sort cellFragmentSort = nthArgSort(k0.klabel(), idx); + if (cellFragmentSort == null) { + throw new IllegalArgumentException( + "Not found " + idx + "th argument sort of " + k0.klabel()); + } + if (cellFragmentSort.name().endsWith("Fragment")) { + Sort cellSort = + Sort( + cellFragmentSort + .name() + .substring(0, cellFragmentSort.name().indexOf("Fragment"))); + KLabel cellLabel = cfg.cfg().getCellLabel(cellSort); + klist0.set(idx, KApply(cellLabel, KList(item0), Att().add(Att.DUMMY_CELL()))); + } } + } } - }.apply(term); - - if (cellFragmentVars.isEmpty()) { - return term; - } - - // drop cell fragment variables that appear outside cell, in non-function rules - if (!labelInfo.isFunction(term)) { - new VisitK() { - private boolean inKCell = false; - @Override - public void apply(KApply k) { - if (k.klabel().name().equals("")) { - assert !inKCell; - inKCell = true; - super.apply(k); - inKCell = false; - } else { - super.apply(k); - } - } - @Override - public void apply(KVariable var) { - if (!inKCell) { - cellFragmentVars.remove(var); - } - } - }.apply(term); - } - - if (cellFragmentVars.isEmpty()) { - return term; + } + return KApply(k0.klabel(), KList(klist0), k0.att()); } + return super.apply(k0); + } - HashSet cellFragmentVarsCell = new HashSet<>(); - for (HashSet cells : cellFragmentVars.values()) { - cellFragmentVarsCell.addAll(cells); + @Override + public K apply(KRewrite k) { + K left = super.apply(k.left()); + return KRewrite(left, k.right(), k.att()); + } + }.apply(term); + } + + // remove the dummy cell decoration introduced by preprocess + private K postprocess(K term) { + return new TransformK() { + @Override + public K apply(KApply k) { + if (k.att().contains(Att.DUMMY_CELL())) { + KLabel klabel = KLabel(k.klabel().name() + "-fragment"); + return KApply(klabel, k.klist(), k.att()); } - - // decorate such cell fragment terms with their parent cell label - return new TransformK() { - @Override - public K apply(KApply k0) { - if (hasCells(k0)) { - ArrayList klist0 = new ArrayList(Collections.nCopies(k0.klist().size(), null)); - for (int idx = 0; idx < k0.klist().size(); idx++) { - K item0 = k0.klist().items().get(idx); - klist0.set(idx, item0); - if (item0 instanceof KApply k) { - if (k.klabel().name().equals("#cells")) { - if (cellFragmentVarsCell.contains(k)) { - Sort cellFragmentSort = nthArgSort(k0.klabel(), idx); - if (cellFragmentSort == null) { - throw new IllegalArgumentException("Not found " + idx + "th argument sort of " + k0.klabel()); - } - if (cellFragmentSort.name().endsWith("Fragment")) { - Sort cellSort = Sort(cellFragmentSort.name().substring(0,cellFragmentSort.name().indexOf("Fragment"))); - KLabel cellLabel = cfg.cfg().getCellLabel(cellSort); - klist0.set(idx, KApply(cellLabel, KList(item0), Att().add(Att.DUMMY_CELL()))); - } - } - } - } - } - return KApply(k0.klabel(), KList(klist0), k0.att()); - } - return super.apply(k0); - } - @Override - public K apply(KRewrite k) { - K left = super.apply(k.left()); - return KRewrite(left, k.right(), k.att()); - } - }.apply(term); - } - - // remove the dummy cell decoration introduced by preprocess - private K postprocess(K term) { - return new TransformK() { - @Override - public K apply(KApply k) { - if (k.att().contains(Att.DUMMY_CELL())) { - KLabel klabel = KLabel(k.klabel().name() + "-fragment"); - return KApply(klabel, k.klist(), k.att()); - } - return super.apply(k); - } - }.apply(term); + return super.apply(k); + } + }.apply(term); + } + + private boolean hasCells(KApply k) { + for (int i = 0; i < k.klist().size(); i++) { + K item = k.klist().items().get(i); + if (item instanceof KApply && ((KApply) item).klabel().name().equals("#cells")) { + return true; + } } - - private boolean hasCells(KApply k) { - for (int i = 0; i < k.klist().size(); i++) { - K item = k.klist().items().get(i); - if (item instanceof KApply && ((KApply) item).klabel().name().equals("#cells")) { - return true; - } - } - return false; + return false; + } + + // find nth argument sort for a given klabel + // if multiple signiture exist, then return arbitrary one of them that is not K + private Sort nthArgSort(KLabel klabel, int n) { + java.util.Set, Sort>> sigs = + mutable(JavaConversions.mapAsJavaMap(module.signatureFor()).get(klabel)); + if (sigs == null) { + throw new IllegalArgumentException("Not found signature for label: " + klabel); } - - // find nth argument sort for a given klabel - // if multiple signiture exist, then return arbitrary one of them that is not K - private Sort nthArgSort(KLabel klabel, int n) { - java.util.Set,Sort>> sigs = - mutable(JavaConversions.mapAsJavaMap(module.signatureFor()).get(klabel)); - if (sigs == null) { - throw new IllegalArgumentException("Not found signature for label: " + klabel); - } - Sort sort = null; - for (Tuple2,Sort> sig : sigs) { - List sorts = JavaConversions.seqAsJavaList(sig._1()); - if (n >= sorts.size()) continue; - sort = sorts.get(n); - if (!sort.equals(Sorts.K())) { - return sort; - } - } + Sort sort = null; + for (Tuple2, Sort> sig : sigs) { + List sorts = JavaConversions.seqAsJavaList(sig._1()); + if (n >= sorts.size()) continue; + sort = sorts.get(n); + if (!sort.equals(Sorts.K())) { return sort; + } } + return sort; + } } diff --git a/kernel/src/main/java/org/kframework/compile/SortInfo.java b/kernel/src/main/java/org/kframework/compile/SortInfo.java index 472cb2f6b7d..6632b53a5a4 100644 --- a/kernel/src/main/java/org/kframework/compile/SortInfo.java +++ b/kernel/src/main/java/org/kframework/compile/SortInfo.java @@ -1,10 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterators; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; +import java.util.Map; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.definition.Module; @@ -12,47 +15,51 @@ import org.kframework.kore.KLabel; import org.kframework.kore.Sort; -import java.util.Map; - -import static org.kframework.kore.KORE.*; - -/** - * Information about sorts which is used in cell completion - */ +/** Information about sorts which is used in cell completion */ public class SortInfo { - private final Map closeOperators = Maps.newHashMap(); + private final Map closeOperators = Maps.newHashMap(); - protected void addOp(Sort sort, String label) { - closeOperators.put(sort, KLabel(label)); - } + protected void addOp(Sort sort, String label) { + closeOperators.put(sort, KLabel(label)); + } - public SortInfo() { - } + public SortInfo() {} - /** - * If s is the sort of the contents of a leaf cell, this returns the label to be used as - * the union/append operator when turning dots into an explicit variable - */ - public KLabel getCloseOperator(Sort s) { - return closeOperators.get(s); - } + /** + * If s is the sort of the contents of a leaf cell, this returns the label to be used as the + * union/append operator when turning dots into an explicit variable + */ + public KLabel getCloseOperator(Sort s) { + return closeOperators.get(s); + } - /** - * Gather sort information from a module. - * Populates the close operators only for sorts which only have a single associative production. - */ - public static SortInfo fromModule(Module module) { - Multimap joinOps = HashMultimap.create(); - Collections.stream(module.productionsFor()).forEach(x -> { - if (Collections.stream(x._2()).anyMatch(p -> p.att().contains(Att.ASSOC()) - && Collections.stream(p.items()).filter(i -> i instanceof NonTerminal).count() == 2)) { + /** + * Gather sort information from a module. Populates the close operators only for sorts which only + * have a single associative production. + */ + public static SortInfo fromModule(Module module) { + Multimap joinOps = HashMultimap.create(); + Collections.stream(module.productionsFor()) + .forEach( + x -> { + if (Collections.stream(x._2()) + .anyMatch( + p -> + p.att().contains(Att.ASSOC()) + && Collections.stream(p.items()) + .filter(i -> i instanceof NonTerminal) + .count() + == 2)) { joinOps.put(x._2().head().sort(), x._1()); - } - }); - SortInfo info = new SortInfo(); - joinOps.asMap().forEach((sort, labels) -> { - info.closeOperators.put(sort, Iterators.getNext(labels.iterator(), null)); - }); - return info; - } + } + }); + SortInfo info = new SortInfo(); + joinOps + .asMap() + .forEach( + (sort, labels) -> { + info.closeOperators.put(sort, Iterators.getNext(labels.iterator(), null)); + }); + return info; + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckAnonymous.java b/kernel/src/main/java/org/kframework/compile/checks/CheckAnonymous.java index 0cf1e94e395..c6dbb67d32f 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckAnonymous.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckAnonymous.java @@ -1,8 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.HashMultiset; import com.google.common.collect.Multiset; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.compile.ResolveAnonVar; import org.kframework.definition.Context; @@ -19,92 +24,105 @@ import org.kframework.utils.errorsystem.KException.ExceptionType; import org.kframework.utils.errorsystem.KExceptionManager; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - public class CheckAnonymous { - private final Set errors; - private final KExceptionManager kem; - private final Module module; + private final Set errors; + private final KExceptionManager kem; + private final Module module; - public CheckAnonymous(Set errors, Module module, KExceptionManager kem) { - this.errors = errors; - this.kem = kem; - this.module = module; - } + public CheckAnonymous(Set errors, Module module, KExceptionManager kem) { + this.errors = errors; + this.kem = kem; + this.module = module; + } - private final Multiset vars = HashMultiset.create(); - private final Map loc = new HashMap<>(); + private final Multiset vars = HashMultiset.create(); + private final Map loc = new HashMap<>(); - private void resetVars() { - vars.clear(); - loc.clear(); - } + private void resetVars() { + vars.clear(); + loc.clear(); + } - private void gatherVars(K k) { - new VisitK() { - @Override - public void apply(KVariable var) { - vars.add(var.name()); - loc.put(var.name(), var); - } + private void gatherVars(K k) { + new VisitK() { + @Override + public void apply(KVariable var) { + vars.add(var.name()); + loc.put(var.name(), var); + } - @Override - public void apply(KApply k) { - if (k.klabel() instanceof KVariable) { - apply((KVariable) k.klabel()); - } - super.apply(k); - } - - @Override - public void apply(InjectedKLabel k) { - if (k.klabel() instanceof KVariable) { - apply((KVariable) k.klabel()); - } - } - }.apply(k); - } + @Override + public void apply(KApply k) { + if (k.klabel() instanceof KVariable) { + apply((KVariable) k.klabel()); + } + super.apply(k); + } - public void check(Sentence s) { - if (s.att().getOptional(Att.LABEL()).orElse("").equals("STDIN-STREAM.stdinUnblock")) { - return; + @Override + public void apply(InjectedKLabel k) { + if (k.klabel() instanceof KVariable) { + apply((KVariable) k.klabel()); } - resetVars(); - if (s instanceof RuleOrClaim r) { - gatherVars(r.body()); - gatherVars(r.requires()); - gatherVars(r.ensures()); - } else if (s instanceof Context c) { - gatherVars(c.body()); - gatherVars(c.requires()); - } else if (s instanceof ContextAlias c) { - gatherVars(c.body()); - gatherVars(c.requires()); + } + }.apply(k); + } + + public void check(Sentence s) { + if (s.att().getOptional(Att.LABEL()).orElse("").equals("STDIN-STREAM.stdinUnblock")) { + return; + } + resetVars(); + if (s instanceof RuleOrClaim r) { + gatherVars(r.body()); + gatherVars(r.requires()); + gatherVars(r.ensures()); + } else if (s instanceof Context c) { + gatherVars(c.body()); + gatherVars(c.requires()); + } else if (s instanceof ContextAlias c) { + gatherVars(c.body()); + gatherVars(c.requires()); + } + for (Multiset.Entry entry : vars.entrySet()) { + if (entry.getCount() == 1) { + if (!(entry.getElement().startsWith("_") + || entry.getElement().startsWith("?_") + || entry.getElement().startsWith("!_") + || entry.getElement().startsWith("@_"))) { + if (s instanceof ContextAlias && entry.getElement().equals("HERE")) { + continue; + } + if ((s instanceof Context || s instanceof ContextAlias) + && entry.getElement().equals("HOLE")) { + continue; + } + if (loc.get(entry.getElement()).location().isPresent()) // ignore generated variables + kem.registerCompilerWarning( + ExceptionType.UNUSED_VAR, + errors, + "Variable '" + + entry.getElement() + + "' defined but not used. Prefix variable name with underscore if this is" + + " intentional.", + loc.get(entry.getElement())); } - for (Multiset.Entry entry : vars.entrySet()) { - if (entry.getCount() == 1) { - if (!(entry.getElement().startsWith("_") || entry.getElement().startsWith("?_") || entry.getElement().startsWith("!_") || entry.getElement().startsWith("@_"))) { - if (s instanceof ContextAlias && entry.getElement().equals("HERE")) { - continue; - } - if ((s instanceof Context || s instanceof ContextAlias) && entry.getElement().equals("HOLE")) { - continue; - } - if (loc.get(entry.getElement()).location().isPresent()) // ignore generated variables - kem.registerCompilerWarning(ExceptionType.UNUSED_VAR, errors, "Variable '" + entry.getElement() + "' defined but not used. Prefix variable name with underscore if this is intentional.", - loc.get(entry.getElement())); - } - } else if (entry.getCount() > 1) { - if ((entry.getElement().startsWith("_") || entry.getElement().startsWith("?_") || entry.getElement().startsWith("!_") || entry.getElement().startsWith("@_")) && !ResolveAnonVar.isAnonVar(KVariable(entry.getElement()))) { - errors.add(KEMException.compilerError("Variable '" + entry.getElement() + "' declared as unused, but it is used. Remove underscore from variable name if this is intentional.", - loc.get(entry.getElement()))); - } - } + } else if (entry.getCount() > 1) { + if ((entry.getElement().startsWith("_") + || entry.getElement().startsWith("?_") + || entry.getElement().startsWith("!_") + || entry.getElement().startsWith("@_")) + && !ResolveAnonVar.isAnonVar(KVariable(entry.getElement()))) { + errors.add( + KEMException.compilerError( + "Variable '" + + entry.getElement() + + "' declared as unused, but it is used. Remove underscore from variable name" + + " if this is intentional.", + loc.get(entry.getElement()))); } + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckAssoc.java b/kernel/src/main/java/org/kframework/compile/checks/CheckAssoc.java index eea4f51f14e..d746b7b9621 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckAssoc.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckAssoc.java @@ -1,54 +1,77 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.definition.Module; import org.kframework.definition.Production; import org.kframework.definition.Sentence; import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.errorsystem.KExceptionManager; - -import java.util.Set; /** - * Ensure that left, right, and non-assoc are only applied to productions with sorting which permits associativity. - * That is, if we have `syntax A ::= B "op" C`, then check the following: - * - if left, then A <= C - * - if right, then A <= B - * - if non-assoc, then A <= B and A <= C + * Ensure that left, right, and non-assoc are only applied to productions with sorting which permits + * associativity. That is, if we have `syntax A ::= B "op" C`, then check the following: - if left, + * then A <= C - if right, then A <= B - if non-assoc, then A <= B and A <= C */ public record CheckAssoc(Set errors, Module module) { - public void check(Sentence s) { - if (s instanceof Production p) { - if (p.arity() != 2) { - return; - } - Sort pSort = p.sort(); - Sort leftSort = p.nonterminals().head().sort(); - Sort rightSort = p.nonterminals().last().sort(); - boolean leqLeft = module.subsorts().lessThanEq(pSort, leftSort); - boolean leqRight = module.subsorts().lessThanEq(pSort, rightSort); - if (p.att().contains(Att.LEFT()) && !leqRight) { - errors.add(KEMException.compilerError(Att.LEFT() + - " attribute not permitted on non-associative production.\n" + - "Hint: The sub-sorting relation " + pSort + " <= " + rightSort + - " does not hold, so the " + Att.LEFT() + " attribute has no effect.", p)); - } - if (p.att().contains(Att.RIGHT()) && !leqLeft) { - errors.add(KEMException.compilerError(Att.RIGHT() + - " attribute not permitted on non-associative production.\n" + - "Hint: The sub-sorting relation " + pSort + " <= " + leftSort + - " does not hold, so the " + Att.RIGHT() + " attribute has no effect.", p)); - } - if (p.att().contains(Att.NON_ASSOC()) && !(leqLeft && leqRight)) { - errors.add(KEMException.compilerError(Att.NON_ASSOC() + - " attribute not permitted on non-associative production.\n" + - "Hint: One of the sub-sorting relations " + pSort + " <= " + leftSort + " or " + - pSort + " <= " + rightSort + " does not hold, so the " + Att.NON_ASSOC() + - " attribute has no effect.", p)); - } - } + public void check(Sentence s) { + if (s instanceof Production p) { + if (p.arity() != 2) { + return; + } + Sort pSort = p.sort(); + Sort leftSort = p.nonterminals().head().sort(); + Sort rightSort = p.nonterminals().last().sort(); + boolean leqLeft = module.subsorts().lessThanEq(pSort, leftSort); + boolean leqRight = module.subsorts().lessThanEq(pSort, rightSort); + if (p.att().contains(Att.LEFT()) && !leqRight) { + errors.add( + KEMException.compilerError( + Att.LEFT() + + " attribute not permitted on non-associative production.\n" + + "Hint: The sub-sorting relation " + + pSort + + " <= " + + rightSort + + " does not hold, so the " + + Att.LEFT() + + " attribute has no effect.", + p)); + } + if (p.att().contains(Att.RIGHT()) && !leqLeft) { + errors.add( + KEMException.compilerError( + Att.RIGHT() + + " attribute not permitted on non-associative production.\n" + + "Hint: The sub-sorting relation " + + pSort + + " <= " + + leftSort + + " does not hold, so the " + + Att.RIGHT() + + " attribute has no effect.", + p)); + } + if (p.att().contains(Att.NON_ASSOC()) && !(leqLeft && leqRight)) { + errors.add( + KEMException.compilerError( + Att.NON_ASSOC() + + " attribute not permitted on non-associative production.\n" + + "Hint: One of the sub-sorting relations " + + pSort + + " <= " + + leftSort + + " or " + + pSort + + " <= " + + rightSort + + " does not hold, so the " + + Att.NON_ASSOC() + + " attribute has no effect.", + p)); + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckAtt.java b/kernel/src/main/java/org/kframework/compile/checks/CheckAtt.java index 66ebcd5df50..92cb8ec434f 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckAtt.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckAtt.java @@ -1,6 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.Collections.*; + +import java.util.List; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.attributes.Att.Key; import org.kframework.attributes.HasLocation; @@ -16,223 +22,306 @@ import org.kframework.utils.errorsystem.KException.ExceptionType; import org.kframework.utils.errorsystem.KExceptionManager; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; +/** Created by dwightguth on 1/25/16. */ +public class CheckAtt { + private final scala.collection.Set macros; + private final Set errors; + private final KExceptionManager kem; + private final Module m; + private final boolean isSymbolicKast; -import static org.kframework.Collections.*; + public CheckAtt( + Set errors, KExceptionManager kem, Module m, boolean isSymbolicKast) { + this.errors = errors; + this.kem = kem; + this.m = m; + this.isSymbolicKast = isSymbolicKast; + this.macros = m.macroKLabels(); + } -/** - * Created by dwightguth on 1/25/16. - */ -public class CheckAtt { - private final scala.collection.Set macros; - private final Set errors; - private final KExceptionManager kem; - private final Module m; - private final boolean isSymbolicKast; - - public CheckAtt(Set errors, KExceptionManager kem, Module m, boolean isSymbolicKast) { - this.errors = errors; - this.kem = kem; - this.m = m; - this.isSymbolicKast = isSymbolicKast; - this.macros = m.macroKLabels(); - } - - public void checkUnrecognizedModuleAtts() { - if (!m.att().unrecognizedKeys().isEmpty()) { - errors.add(KEMException.compilerError("Unrecognized attributes on module " + m.name() + ": " + - stream(m.att().unrecognizedKeys()).map(Key::toString).sorted().collect(Collectors.toList()) + - "\nHint: User-defined groups can be added with the group(_) attribute.")); - } + public void checkUnrecognizedModuleAtts() { + if (!m.att().unrecognizedKeys().isEmpty()) { + errors.add( + KEMException.compilerError( + "Unrecognized attributes on module " + + m.name() + + ": " + + stream(m.att().unrecognizedKeys()) + .map(Key::toString) + .sorted() + .collect(Collectors.toList()) + + "\nHint: User-defined groups can be added with the group(_) attribute.")); } + } - public void check(Sentence sentence) { - checkUnrecognizedAtts(sentence); - checkRestrictedAtts(sentence); - if (sentence instanceof Rule) { - check(sentence.att(), sentence); - check((Rule) sentence); - } else if (sentence instanceof Production) { - check((Production) sentence); - } - checkLabel(sentence); + public void check(Sentence sentence) { + checkUnrecognizedAtts(sentence); + checkRestrictedAtts(sentence); + if (sentence instanceof Rule) { + check(sentence.att(), sentence); + check((Rule) sentence); + } else if (sentence instanceof Production) { + check((Production) sentence); } + checkLabel(sentence); + } - private static final Pattern whitespace = Pattern.compile("\\s"); + private static final Pattern whitespace = Pattern.compile("\\s"); - private void checkLabel(Sentence sentence) { - if (sentence.att().contains(Att.LABEL())) { - String label = sentence.att().get(Att.LABEL()); - if (label.contains("`") || whitespace.matcher(label).find()) { - errors.add(KEMException.compilerError("Rule label '" + label + "' cannot contain whitespace or backticks.", sentence)); - } + private void checkLabel(Sentence sentence) { + if (sentence.att().contains(Att.LABEL())) { + String label = sentence.att().get(Att.LABEL()); + if (label.contains("`") || whitespace.matcher(label).find()) { + errors.add( + KEMException.compilerError( + "Rule label '" + label + "' cannot contain whitespace or backticks.", sentence)); } } + } - private void checkUnrecognizedAtts(Sentence sentence) { - if (!sentence.att().unrecognizedKeys().isEmpty()) { - errors.add(KEMException.compilerError("Unrecognized attributes: " + - stream(sentence.att().unrecognizedKeys()).map(Key::toString).sorted().collect(Collectors.toList()) + - "\nHint: User-defined groups can be added with the group(_) attribute.", sentence)); - } + private void checkUnrecognizedAtts(Sentence sentence) { + if (!sentence.att().unrecognizedKeys().isEmpty()) { + errors.add( + KEMException.compilerError( + "Unrecognized attributes: " + + stream(sentence.att().unrecognizedKeys()) + .map(Key::toString) + .sorted() + .collect(Collectors.toList()) + + "\nHint: User-defined groups can be added with the group(_) attribute.", + sentence)); } + } - private void checkRestrictedAtts(Sentence sentence) { - Class cls = sentence.getClass(); - Att att = sentence.att(); - Set keys = stream(att.att().keySet()).map(k -> k._1()).collect(Collectors.toSet()); - keys.removeIf(k -> k.allowedSentences().exists(c -> c.isAssignableFrom(cls))); - if (!keys.isEmpty()) { - List sortedKeys = keys.stream().map(k -> k.toString()).sorted().collect(Collectors.toList()); - errors.add(KEMException.compilerError(cls.getSimpleName() + " sentences can not have the following attributes: " + sortedKeys, sentence)); - } + private void checkRestrictedAtts(Sentence sentence) { + Class cls = sentence.getClass(); + Att att = sentence.att(); + Set keys = stream(att.att().keySet()).map(k -> k._1()).collect(Collectors.toSet()); + keys.removeIf(k -> k.allowedSentences().exists(c -> c.isAssignableFrom(cls))); + if (!keys.isEmpty()) { + List sortedKeys = + keys.stream().map(k -> k.toString()).sorted().collect(Collectors.toList()); + errors.add( + KEMException.compilerError( + cls.getSimpleName() + + " sentences can not have the following attributes: " + + sortedKeys, + sentence)); } + } - private void check(Production prod) { - if (!prod.sort().equals(Sorts.KItem())) { - Att sortAtt = m.sortAttributesFor().getOrElse(prod.sort().head(), () -> Att.empty()); - if (sortAtt.contains(Att.HOOK()) && !sortAtt.get(Att.HOOK()).equals("ARRAY.Array") && !(sortAtt.get(Att.HOOK()).equals("KVAR.KVar") && isSymbolicKast)) { - if (!prod.att().contains(Att.FUNCTION()) && !prod.att().contains(Att.BRACKET()) && - !prod.att().contains(Att.TOKEN()) && !prod.att().contains(Att.MACRO()) && !(prod.klabel().isDefined() && macros.contains(prod.klabel().get()))) { - if (!(prod.sort().equals(Sorts.K()) && ((prod.klabel().isDefined() && (prod.klabel().get().name().equals("#EmptyK") || prod.klabel().get().name().equals("#KSequence"))) || prod.isSubsort()))) { - if (!(sortAtt.contains(Att.CELL_COLLECTION()) && prod.isSubsort())) { - errors.add(KEMException.compilerError("Cannot add new constructors to hooked sort " + prod.sort(), prod)); - } - } - } - } - } - if (prod.att().contains(Att.BINDER()) && !isSymbolicKast) { - if (!prod.att().get(Att.BINDER()).equals("")) { - errors.add(KEMException.compilerError("Attribute value for 'binder' attribute is not supported.", prod)); + private void check(Production prod) { + if (!prod.sort().equals(Sorts.KItem())) { + Att sortAtt = m.sortAttributesFor().getOrElse(prod.sort().head(), () -> Att.empty()); + if (sortAtt.contains(Att.HOOK()) + && !sortAtt.get(Att.HOOK()).equals("ARRAY.Array") + && !(sortAtt.get(Att.HOOK()).equals("KVAR.KVar") && isSymbolicKast)) { + if (!prod.att().contains(Att.FUNCTION()) + && !prod.att().contains(Att.BRACKET()) + && !prod.att().contains(Att.TOKEN()) + && !prod.att().contains(Att.MACRO()) + && !(prod.klabel().isDefined() && macros.contains(prod.klabel().get()))) { + if (!(prod.sort().equals(Sorts.K()) + && ((prod.klabel().isDefined() + && (prod.klabel().get().name().equals("#EmptyK") + || prod.klabel().get().name().equals("#KSequence"))) + || prod.isSubsort()))) { + if (!(sortAtt.contains(Att.CELL_COLLECTION()) && prod.isSubsort())) { + errors.add( + KEMException.compilerError( + "Cannot add new constructors to hooked sort " + prod.sort(), prod)); } - if (prod.nonterminals().size() < 2) { - errors.add(KEMException.compilerError("Binder productions must have at least two nonterminals.", prod)); - } else if (!m.sortAttributesFor().get(prod.nonterminals().apply(0).sort().head()).getOrElse(() -> Att.empty()).getOptional(Att.HOOK()).orElse("").equals("KVAR.KVar")) { - errors.add(KEMException.compilerError("First child of binder must have a sort with the 'KVAR.KVar' hook attribute.", prod)); - } - } - boolean hasColors = false; - int ncolors = 0; - if (prod.att().contains(Att.COLORS())) { - hasColors = true; - ncolors = prod.att().get(Att.COLORS()).split(",").length; + } } - int nterminals = prod.items().size() - prod.nonterminals().size(); - int nescapes = 0; - if (prod.att().contains(Att.FORMAT())) { - String format = prod.att().get(Att.FORMAT()); - for (int i = 0; i < format.length(); i++) { - char c = format.charAt(i); - if (c == '%') { - if (i == format.length() - 1) { - errors.add(KEMException.compilerError("Invalid format attribute: unfinished escape sequence.", prod)); - break; - } - char c2 = format.charAt(i + 1); - i++; - switch(c2) { - case 'n': - case 'i': - case 'd': - case 'r': - break; - case 'c': - nescapes++; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - StringBuilder sb = new StringBuilder(); - for (; i < format.length() && format.charAt(i) >= '0' && format.charAt(i) <= '9'; i++) { - sb.append(format.charAt(i)); - } - i--; - int idx = Integer.parseInt(sb.toString()); - if (idx == 0 || idx > prod.items().size()) { - errors.add(KEMException.compilerError("Invalid format escape sequence '%" + sb + "'. Expected a number between 1 and " + prod.items().size(), prod)); - } else { - ProductionItem pi = prod.items().apply(idx-1); - if (pi instanceof RegexTerminal) { - errors.add(KEMException.compilerError("Invalid format escape sequence referring to regular expression terminal '" + pi + "'.", prod)); - } - } - break; - } - } - } - } else if (!prod.att().contains(Att.TOKEN()) && !prod.sort().equals(Sorts.Layout()) && !prod.sort().equals(Sorts.LineMarker())) { - for (ProductionItem pi : iterable(prod.items())) { + } + } + if (prod.att().contains(Att.BINDER()) && !isSymbolicKast) { + if (!prod.att().get(Att.BINDER()).equals("")) { + errors.add( + KEMException.compilerError( + "Attribute value for 'binder' attribute is not supported.", prod)); + } + if (prod.nonterminals().size() < 2) { + errors.add( + KEMException.compilerError( + "Binder productions must have at least two nonterminals.", prod)); + } else if (!m.sortAttributesFor() + .get(prod.nonterminals().apply(0).sort().head()) + .getOrElse(() -> Att.empty()) + .getOptional(Att.HOOK()) + .orElse("") + .equals("KVAR.KVar")) { + errors.add( + KEMException.compilerError( + "First child of binder must have a sort with the 'KVAR.KVar' hook attribute.", + prod)); + } + } + boolean hasColors = false; + int ncolors = 0; + if (prod.att().contains(Att.COLORS())) { + hasColors = true; + ncolors = prod.att().get(Att.COLORS()).split(",").length; + } + int nterminals = prod.items().size() - prod.nonterminals().size(); + int nescapes = 0; + if (prod.att().contains(Att.FORMAT())) { + String format = prod.att().get(Att.FORMAT()); + for (int i = 0; i < format.length(); i++) { + char c = format.charAt(i); + if (c == '%') { + if (i == format.length() - 1) { + errors.add( + KEMException.compilerError( + "Invalid format attribute: unfinished escape sequence.", prod)); + break; + } + char c2 = format.charAt(i + 1); + i++; + switch (c2) { + case 'n': + case 'i': + case 'd': + case 'r': + break; + case 'c': + nescapes++; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + StringBuilder sb = new StringBuilder(); + for (; + i < format.length() && format.charAt(i) >= '0' && format.charAt(i) <= '9'; + i++) { + sb.append(format.charAt(i)); + } + i--; + int idx = Integer.parseInt(sb.toString()); + if (idx == 0 || idx > prod.items().size()) { + errors.add( + KEMException.compilerError( + "Invalid format escape sequence '%" + + sb + + "'. Expected a number between 1 and " + + prod.items().size(), + prod)); + } else { + ProductionItem pi = prod.items().apply(idx - 1); if (pi instanceof RegexTerminal) { - if (prod.items().size() == 1) { - errors.add(KEMException.compilerError( - "Expected format attribute on production with regular expression terminal. Did you forget the 'token' attribute?", prod)); - } else { - errors.add(KEMException.compilerError( - "Expected format attribute on production with regular expression terminal.", prod)); - } + errors.add( + KEMException.compilerError( + "Invalid format escape sequence referring to regular expression terminal" + + " '" + + pi + + "'.", + prod)); } - } - } - if (hasColors && nescapes + nterminals != ncolors) { - errors.add(KEMException.compilerError("Invalid colors attribute: expected " + (nescapes + nterminals) + " colors, found " + ncolors + " colors instead.", prod)); + } + break; + } } - if (prod.att().contains(Att.FUNCTIONAL())) { - kem.registerCompilerWarning(ExceptionType.FUTURE_ERROR, errors, - "The attribute 'functional' has been deprecated on symbols. Use the combination of attributes 'function' and 'total' instead.", prod); - } - if (prod.att().contains(Att.TOTAL()) && !prod.att().contains(Att.FUNCTION())) { - errors.add(KEMException.compilerError( - "The attribute 'total' cannot be applied to a production which does not have the 'function' attribute.", prod)); + } + } else if (!prod.att().contains(Att.TOKEN()) + && !prod.sort().equals(Sorts.Layout()) + && !prod.sort().equals(Sorts.LineMarker())) { + for (ProductionItem pi : iterable(prod.items())) { + if (pi instanceof RegexTerminal) { + if (prod.items().size() == 1) { + errors.add( + KEMException.compilerError( + "Expected format attribute on production with regular expression terminal. Did" + + " you forget the 'token' attribute?", + prod)); + } else { + errors.add( + KEMException.compilerError( + "Expected format attribute on production with regular expression terminal.", + prod)); + } } + } } + if (hasColors && nescapes + nterminals != ncolors) { + errors.add( + KEMException.compilerError( + "Invalid colors attribute: expected " + + (nescapes + nterminals) + + " colors, found " + + ncolors + + " colors instead.", + prod)); + } + if (prod.att().contains(Att.FUNCTIONAL())) { + kem.registerCompilerWarning( + ExceptionType.FUTURE_ERROR, + errors, + "The attribute 'functional' has been deprecated on symbols. Use the combination of" + + " attributes 'function' and 'total' instead.", + prod); + } + if (prod.att().contains(Att.TOTAL()) && !prod.att().contains(Att.FUNCTION())) { + errors.add( + KEMException.compilerError( + "The attribute 'total' cannot be applied to a production which does not have the" + + " 'function' attribute.", + prod)); + } + } - private void check(Rule rule) { - if (rule.isMacro()) { - kem.registerCompilerWarning(ExceptionType.FUTURE_ERROR, errors, - "The attribute [" + rule.att().getMacro().get() + "] has been deprecated on rules. Use this label on syntax declarations instead.", rule); - } - - checkNonExecutable(rule); + private void check(Rule rule) { + if (rule.isMacro()) { + kem.registerCompilerWarning( + ExceptionType.FUTURE_ERROR, + errors, + "The attribute [" + + rule.att().getMacro().get() + + "] has been deprecated on rules. Use this label on syntax declarations instead.", + rule); } - private void checkNonExecutable(Rule rule) { - boolean isNonExecutable = rule.att().contains(Att.NON_EXECUTABLE()); - boolean isFunction = m.attributesFor() - .getOrElse(m.matchKLabel(rule), Att::empty) - .contains(Att.FUNCTION()); + checkNonExecutable(rule); + } - if(isNonExecutable && !isFunction) { - errors.add( - KEMException.compilerError( - "non-executable attribute is only supported on function rules.", - rule)); - } + private void checkNonExecutable(Rule rule) { + boolean isNonExecutable = rule.att().contains(Att.NON_EXECUTABLE()); + boolean isFunction = + m.attributesFor().getOrElse(m.matchKLabel(rule), Att::empty).contains(Att.FUNCTION()); + + if (isNonExecutable && !isFunction) { + errors.add( + KEMException.compilerError( + "non-executable attribute is only supported on function rules.", rule)); } + } - private void check(Att att, HasLocation loc) { - if (att.contains(Att.OWISE()) && att.contains(Att.SIMPLIFICATION())) { - errors.add(KEMException.compilerError("owise attribute is not supported on simplification rules.", loc)); - } - if (att.contains(Att.PRIORITY()) && att.contains(Att.SIMPLIFICATION())) { - errors.add(KEMException.compilerError("priority attribute is not supported on simplification rules.", loc)); - } - if(att.contains(Att.ANYWHERE()) && att.contains(Att.SIMPLIFICATION())) { - errors.add(KEMException.compilerError("anywhere attribute is not supported on simplification rules.", loc)); - } - if(att.contains(Att.ANYWHERE()) && att.contains(Att.SYMBOLIC())) { - errors.add(KEMException.compilerError("anywhere attribute is not supported on symbolic rules.", loc)); - } + private void check(Att att, HasLocation loc) { + if (att.contains(Att.OWISE()) && att.contains(Att.SIMPLIFICATION())) { + errors.add( + KEMException.compilerError( + "owise attribute is not supported on simplification rules.", loc)); + } + if (att.contains(Att.PRIORITY()) && att.contains(Att.SIMPLIFICATION())) { + errors.add( + KEMException.compilerError( + "priority attribute is not supported on simplification rules.", loc)); + } + if (att.contains(Att.ANYWHERE()) && att.contains(Att.SIMPLIFICATION())) { + errors.add( + KEMException.compilerError( + "anywhere attribute is not supported on simplification rules.", loc)); + } + if (att.contains(Att.ANYWHERE()) && att.contains(Att.SYMBOLIC())) { + errors.add( + KEMException.compilerError( + "anywhere attribute is not supported on symbolic rules.", loc)); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckBracket.java b/kernel/src/main/java/org/kframework/compile/checks/CheckBracket.java index 9b826a49aa2..c2c0864ee15 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckBracket.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckBracket.java @@ -1,6 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.List; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.kil.Module; import org.kframework.kil.ModuleItem; @@ -11,26 +13,31 @@ import org.kframework.kil.Syntax; import org.kframework.utils.errorsystem.KEMException; -import java.util.List; -import java.util.stream.Collectors; - public class CheckBracket { - public static void check(Module m) { - m.getItems().forEach(CheckBracket::check); // i -> check(i) - } + public static void check(Module m) { + m.getItems().forEach(CheckBracket::check); // i -> check(i) + } - private static void check(ModuleItem i) { - if (i instanceof Syntax s) { - for (PriorityBlock b : s.getPriorityBlocks()) { - for (Production p : b.getProductions()) { - if (p.containsAttribute(Att.BRACKET())) { - List nts = p.getItems().stream().filter(x -> x instanceof NonTerminal).collect(Collectors.toList()); - if (nts.size() != 1 || !((NonTerminal) nts.get(0)).getSort().equals(s.getDeclaredSort().getSort())) - throw KEMException.outerParserError("bracket productions should have exactly one non-terminal of the same sort as the production.", p.getSource(), p.getLocation()); - } - } - } + private static void check(ModuleItem i) { + if (i instanceof Syntax s) { + for (PriorityBlock b : s.getPriorityBlocks()) { + for (Production p : b.getProductions()) { + if (p.containsAttribute(Att.BRACKET())) { + List nts = + p.getItems().stream() + .filter(x -> x instanceof NonTerminal) + .collect(Collectors.toList()); + if (nts.size() != 1 + || !((NonTerminal) nts.get(0)).getSort().equals(s.getDeclaredSort().getSort())) + throw KEMException.outerParserError( + "bracket productions should have exactly one non-terminal of the same sort as the" + + " production.", + p.getSource(), + p.getLocation()); + } } + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckConfigurationCells.java b/kernel/src/main/java/org/kframework/compile/checks/CheckConfigurationCells.java index e3700ad27a1..c07eb2197fe 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckConfigurationCells.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckConfigurationCells.java @@ -1,6 +1,10 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.Collections.*; + +import java.util.HashSet; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.compile.ConfigurationInfoFromModule; import org.kframework.definition.Module; @@ -11,56 +15,61 @@ import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import java.util.HashSet; -import java.util.Set; - -import static org.kframework.Collections.*; - -/** - * Checks that no two cells with the same name are declared in the configuration. - */ +/** Checks that no two cells with the same name are declared in the configuration. */ public class CheckConfigurationCells { - private final Set errors; + private final Set errors; - private final Module module; + private final Module module; - private final boolean isSymbolicKast; + private final boolean isSymbolicKast; - public CheckConfigurationCells(Set errors, Module module, boolean isSymbolicKast) { - this.errors = errors; - this.module = module; - this.isSymbolicKast = isSymbolicKast; - } + public CheckConfigurationCells(Set errors, Module module, boolean isSymbolicKast) { + this.errors = errors; + this.module = module; + this.isSymbolicKast = isSymbolicKast; + } - public void check(Sentence s) { - if (s instanceof Production) { - check((Production) s); - } + public void check(Sentence s) { + if (s instanceof Production) { + check((Production) s); } + } - private final Set cells = new HashSet<>(); + private final Set cells = new HashSet<>(); - private void check(Production p) { - if (p.att().contains(Att.CELL())) { - for (ProductionItem i : mutable(p.items())) { - if (i instanceof NonTerminal) { - Sort sort = ((NonTerminal) i).sort(); - if (sort.name().endsWith("Cell")) { - if (cells.contains(sort)) { - Production cell = new ConfigurationInfoFromModule(module).cellProductionsFor().get(sort).get().head(); - errors.add(KEMException.compilerError("Cell " + cell.klabel().get() + " found twice in configuration.", p)); - } - cells.add(sort); - } - } - } - if (p.att().getOptional(Att.MULTIPLICITY()).orElse("").equals("*") && p.att().getOptional(Att.TYPE()).orElse("Bag").equals("Bag")) { - if (!isSymbolicKast) { - errors.add(KEMException.compilerError("Cell bags are only supported on the Java backend. If you want " - + "this feature, comment on https://github.com/runtimeverification/k/issues/1419 . As a workaround, you can add the attribute " - + "type=\"Set\" and add a unique identifier to each element in the set.", p)); - } + private void check(Production p) { + if (p.att().contains(Att.CELL())) { + for (ProductionItem i : mutable(p.items())) { + if (i instanceof NonTerminal) { + Sort sort = ((NonTerminal) i).sort(); + if (sort.name().endsWith("Cell")) { + if (cells.contains(sort)) { + Production cell = + new ConfigurationInfoFromModule(module) + .cellProductionsFor() + .get(sort) + .get() + .head(); + errors.add( + KEMException.compilerError( + "Cell " + cell.klabel().get() + " found twice in configuration.", p)); } + cells.add(sort); + } + } + } + if (p.att().getOptional(Att.MULTIPLICITY()).orElse("").equals("*") + && p.att().getOptional(Att.TYPE()).orElse("Bag").equals("Bag")) { + if (!isSymbolicKast) { + errors.add( + KEMException.compilerError( + "Cell bags are only supported on the Java backend. If you want this feature," + + " comment on https://github.com/runtimeverification/k/issues/1419 . As a" + + " workaround, you can add the attribute type=\"Set\" and add a unique" + + " identifier to each element in the set.", + p)); } + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckFunctions.java b/kernel/src/main/java/org/kframework/compile/checks/CheckFunctions.java index 8c727c51037..ce019ff0fac 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckFunctions.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckFunctions.java @@ -1,6 +1,7 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.compile.RewriteAwareVisitor; import org.kframework.definition.Claim; @@ -14,101 +15,158 @@ import org.kframework.kore.KVariable; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - -/** - * Check that functions are not used on LHS in places that should be performing matching. - */ +/** Check that functions are not used on LHS in places that should be performing matching. */ public record CheckFunctions(Set errors, Module m) { - public void check(Sentence sentence) { - if (sentence instanceof Rule rl) { - checkFuncAtt(rl); - if (!rl.att().contains(Att.SIMPLIFICATION())) - // functions are allowed on the LHS of simplification rules - check(rl.body()); - } else if (sentence instanceof Claim c) { - // functions are allowed on LHS of claims - if (c.att().contains(Att.MACRO()) || c.att().contains(Att.MACRO_REC()) - || c.att().contains(Att.ALIAS()) || c.att().contains(Att.ALIAS_REC())) - errors.add(KEMException.compilerError( - "Attributes " + Att.MACRO() + "|" + Att.MACRO_REC() + "|" - + Att.ALIAS() + "|" + Att.ALIAS_REC() + " are not allowed on claims.", c)); - } else if (sentence instanceof Context ctx) { - check(ctx.body()); - if (ctx.att().contains(Att.MACRO()) || ctx.att().contains(Att.MACRO_REC()) - || ctx.att().contains(Att.ALIAS()) || ctx.att().contains(Att.ALIAS_REC())) - errors.add(KEMException.compilerError( - "Attributes " + Att.MACRO() + "|" + Att.MACRO_REC() + "|" - + Att.ALIAS() + "|" + Att.ALIAS_REC() + " are not allowed on contexts.", ctx)); - } else if (sentence instanceof ContextAlias ctx) { - check(ctx.body()); - if (ctx.att().contains(Att.MACRO()) || ctx.att().contains(Att.MACRO_REC()) - || ctx.att().contains(Att.ALIAS()) || ctx.att().contains(Att.ALIAS_REC())) - errors.add(KEMException.compilerError( - "Attributes " + Att.MACRO() + "|" + Att.MACRO_REC() + "|" - + Att.ALIAS() + "|" + Att.ALIAS_REC() + " are not allowed on contexts.", ctx)); - } + public void check(Sentence sentence) { + if (sentence instanceof Rule rl) { + checkFuncAtt(rl); + if (!rl.att().contains(Att.SIMPLIFICATION())) + // functions are allowed on the LHS of simplification rules + check(rl.body()); + } else if (sentence instanceof Claim c) { + // functions are allowed on LHS of claims + if (c.att().contains(Att.MACRO()) + || c.att().contains(Att.MACRO_REC()) + || c.att().contains(Att.ALIAS()) + || c.att().contains(Att.ALIAS_REC())) + errors.add( + KEMException.compilerError( + "Attributes " + + Att.MACRO() + + "|" + + Att.MACRO_REC() + + "|" + + Att.ALIAS() + + "|" + + Att.ALIAS_REC() + + " are not allowed on claims.", + c)); + } else if (sentence instanceof Context ctx) { + check(ctx.body()); + if (ctx.att().contains(Att.MACRO()) + || ctx.att().contains(Att.MACRO_REC()) + || ctx.att().contains(Att.ALIAS()) + || ctx.att().contains(Att.ALIAS_REC())) + errors.add( + KEMException.compilerError( + "Attributes " + + Att.MACRO() + + "|" + + Att.MACRO_REC() + + "|" + + Att.ALIAS() + + "|" + + Att.ALIAS_REC() + + " are not allowed on contexts.", + ctx)); + } else if (sentence instanceof ContextAlias ctx) { + check(ctx.body()); + if (ctx.att().contains(Att.MACRO()) + || ctx.att().contains(Att.MACRO_REC()) + || ctx.att().contains(Att.ALIAS()) + || ctx.att().contains(Att.ALIAS_REC())) + errors.add( + KEMException.compilerError( + "Attributes " + + Att.MACRO() + + "|" + + Att.MACRO_REC() + + "|" + + Att.ALIAS() + + "|" + + Att.ALIAS_REC() + + " are not allowed on contexts.", + ctx)); } + } - public void check(K body) { - new RewriteAwareVisitor(true, errors) { - boolean atTop = true; - @Override - public void apply(KApply k) { - if (k.klabel().name().equals("#withConfig")) { - super.apply(k); - return; - } - if (k.klabel() instanceof KVariable || CheckKLabels.isInternalKLabel(k.klabel().name(), m) || !m.attributesFor().contains(k.klabel()) ) { - atTop = false; - super.apply(k); - return; - } - Att attributes = m.attributesFor().apply(k.klabel()); - String hook = attributes.getOptional(Att.HOOK()).orElse(""); - if (attributes.contains(Att.FUNCTION()) - && isLHS() - && !atTop - && !(hook.equals("LIST.element") || hook.equals("LIST.concat") || hook.equals("LIST.unit") - || hook.equals("SET.element") || hook.equals("SET.concat") || hook.equals("SET.unit") - || hook.equals("MAP.element") || hook.equals("MAP.concat") || hook.equals("MAP.unit") - || hook.equals("BAG.element") || hook.equals("BAG.concat") || hook.equals("BAG.unit"))) { - errors.add(KEMException.compilerError("Illegal function symbol " + k.klabel().name() + " on LHS of rule." + - " Consider adding `simplification` attribute to the rule if this is intended.", k)); - } - atTop = false; - if (hook.equals("SET.element")) return; - if (hook.equals("MAP.element")) { - apply(k.items().get(1)); - return; - } - super.apply(k); - } - }.apply(body); - } + public void check(K body) { + new RewriteAwareVisitor(true, errors) { + boolean atTop = true; - public void checkFuncAtt(Rule r) { - new RewriteAwareVisitor(true, errors) { - @Override - public void apply(KApply k) { - if (k.klabel().name().equals("#withConfig")) { - super.apply(k); - return; - } - if ((isRHS() && !isLHS()) || k.klabel() instanceof KVariable || !m.attributesFor().contains(k.klabel())) { - return; - } - Att attributes = m.attributesFor().apply(k.klabel()); - if (attributes.contains(Att.FUNCTION()) && (r.att().contains(Att.MACRO()) - || r.att().contains(Att.MACRO_REC()) - || r.att().contains(Att.ALIAS()) - || r.att().contains(Att.ALIAS_REC()))) { - errors.add(KEMException.compilerError( - "Attributes " + Att.MACRO() + "|" + Att.MACRO_REC() + "|" - + Att.ALIAS() + "|" + Att.ALIAS_REC() + " are not allowed on function rules.", r)); - } - } - }.apply(r.body()); - } + @Override + public void apply(KApply k) { + if (k.klabel().name().equals("#withConfig")) { + super.apply(k); + return; + } + if (k.klabel() instanceof KVariable + || CheckKLabels.isInternalKLabel(k.klabel().name(), m) + || !m.attributesFor().contains(k.klabel())) { + atTop = false; + super.apply(k); + return; + } + Att attributes = m.attributesFor().apply(k.klabel()); + String hook = attributes.getOptional(Att.HOOK()).orElse(""); + if (attributes.contains(Att.FUNCTION()) + && isLHS() + && !atTop + && !(hook.equals("LIST.element") + || hook.equals("LIST.concat") + || hook.equals("LIST.unit") + || hook.equals("SET.element") + || hook.equals("SET.concat") + || hook.equals("SET.unit") + || hook.equals("MAP.element") + || hook.equals("MAP.concat") + || hook.equals("MAP.unit") + || hook.equals("BAG.element") + || hook.equals("BAG.concat") + || hook.equals("BAG.unit"))) { + errors.add( + KEMException.compilerError( + "Illegal function symbol " + + k.klabel().name() + + " on LHS of rule. Consider adding `simplification` attribute to the rule if" + + " this is intended.", + k)); + } + atTop = false; + if (hook.equals("SET.element")) return; + if (hook.equals("MAP.element")) { + apply(k.items().get(1)); + return; + } + super.apply(k); + } + }.apply(body); + } + + public void checkFuncAtt(Rule r) { + new RewriteAwareVisitor(true, errors) { + @Override + public void apply(KApply k) { + if (k.klabel().name().equals("#withConfig")) { + super.apply(k); + return; + } + if ((isRHS() && !isLHS()) + || k.klabel() instanceof KVariable + || !m.attributesFor().contains(k.klabel())) { + return; + } + Att attributes = m.attributesFor().apply(k.klabel()); + if (attributes.contains(Att.FUNCTION()) + && (r.att().contains(Att.MACRO()) + || r.att().contains(Att.MACRO_REC()) + || r.att().contains(Att.ALIAS()) + || r.att().contains(Att.ALIAS_REC()))) { + errors.add( + KEMException.compilerError( + "Attributes " + + Att.MACRO() + + "|" + + Att.MACRO_REC() + + "|" + + Att.ALIAS() + + "|" + + Att.ALIAS_REC() + + " are not allowed on function rules.", + r)); + } + } + }.apply(r.body()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckHOLE.java b/kernel/src/main/java/org/kframework/compile/checks/CheckHOLE.java index ca443f43708..8739d609542 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckHOLE.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckHOLE.java @@ -1,6 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.compile.ResolveStrict; @@ -8,84 +13,85 @@ import org.kframework.definition.Module; import org.kframework.definition.Production; import org.kframework.definition.Sentence; -import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KVariable; import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - public record CheckHOLE(Set errors, Module m) { - public void check(Sentence sentence) { - if (sentence instanceof Production) { - check((Production) sentence); - } else if (sentence instanceof Context) { - check((Context) sentence); - } + public void check(Sentence sentence) { + if (sentence instanceof Production) { + check((Production) sentence); + } else if (sentence instanceof Context) { + check((Context) sentence); } + } - private void check(Production prod) { - if (prod.att().contains(Att.STRICT())) { - check(prod, prod.att().get(Att.STRICT())); - } - if (prod.att().contains(Att.SEQSTRICT())) { - check(prod, prod.att().get(Att.SEQSTRICT())); - } + private void check(Production prod) { + if (prod.att().contains(Att.STRICT())) { + check(prod, prod.att().get(Att.STRICT())); } + if (prod.att().contains(Att.SEQSTRICT())) { + check(prod, prod.att().get(Att.SEQSTRICT())); + } + } - private void check(Production prod, String att) { - long arity = prod.nonterminals().size(); - List strictnessPositions = new ArrayList<>(); - if (att.isEmpty()) { + private void check(Production prod, String att) { + long arity = prod.nonterminals().size(); + List strictnessPositions = new ArrayList<>(); + if (att.isEmpty()) { + for (int i = 1; i <= arity; i++) { + strictnessPositions.add(i); + } + } else { + try { + String[] components = att.split(";"); + if (components.length == 1) { + if (Character.isDigit(components[0].trim().charAt(0))) { + ResolveStrict.setPositions(components[0].trim(), strictnessPositions, arity, prod); + } else { for (int i = 1; i <= arity; i++) { - strictnessPositions.add(i); + strictnessPositions.add(i); } + } + } else if (components.length % 2 == 0) { + for (int i = 0; i < components.length; i += 2) { + ResolveStrict.setPositions(components[i + 1].trim(), strictnessPositions, arity, prod); + } } else { - try { - String[] components = att.split(";"); - if (components.length == 1) { - if (Character.isDigit(components[0].trim().charAt(0))) { - ResolveStrict.setPositions(components[0].trim(), strictnessPositions, arity, prod); - } else { - for (int i = 1; i <= arity; i++) { - strictnessPositions.add(i); - } - } - } else if (components.length % 2 == 0) { - for (int i = 0; i < components.length; i += 2) { - ResolveStrict.setPositions(components[i+1].trim(), strictnessPositions, arity, prod); - } - } else { - errors.add(KEMException.compilerError("Invalid strict attribute containing invalid semicolons. Must contain 0, 1, 2, or an even number of components.", prod)); - } - } catch (KEMException e) { - errors.add(e); - } - } - for (int pos : strictnessPositions) { - if (prod.nonterminals().apply(pos-1).sort().equals(Sorts.K())) { - errors.add(KEMException.compilerError("Cannot heat a nonterminal of sort K. Did you mean KItem?", prod)); - } + errors.add( + KEMException.compilerError( + "Invalid strict attribute containing invalid semicolons. Must contain 0, 1, 2, or" + + " an even number of components.", + prod)); } + } catch (KEMException e) { + errors.add(e); + } + } + for (int pos : strictnessPositions) { + if (prod.nonterminals().apply(pos - 1).sort().equals(Sorts.K())) { + errors.add( + KEMException.compilerError( + "Cannot heat a nonterminal of sort K. Did you mean KItem?", prod)); + } } + } - private static final KApply K_HOLE = KApply(KLabel("#SemanticCastToK"), KVariable("HOLE")); + private static final KApply K_HOLE = KApply(KLabel("#SemanticCastToK"), KVariable("HOLE")); - private void check(Context ctx) { - new VisitK() { - @Override - public void apply(KApply k) { - if (k.equals(K_HOLE)) { - errors.add(KEMException.compilerError("Cannot heat a HOLE of sort K. Did you mean to sort it to KItem?", k)); - } - super.apply(k); - } - }.apply(ctx.body()); - } + private void check(Context ctx) { + new VisitK() { + @Override + public void apply(KApply k) { + if (k.equals(K_HOLE)) { + errors.add( + KEMException.compilerError( + "Cannot heat a HOLE of sort K. Did you mean to sort it to KItem?", k)); + } + super.apply(k); + } + }.apply(ctx.body()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckK.java b/kernel/src/main/java/org/kframework/compile/checks/CheckK.java index 35d619a0bdf..d987845a23d 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckK.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckK.java @@ -1,6 +1,7 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; import org.kframework.definition.Context; import org.kframework.definition.ContextAlias; import org.kframework.definition.RuleOrClaim; @@ -12,42 +13,44 @@ import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - public record CheckK(Set errors) { - private void check(K k) { - new VisitK() { - @Override - public void apply(KAs as) { - boolean error = false; - if (!(as.alias() instanceof KVariable)) { - error = true; - if (as.alias() instanceof KApply app) { - if (app.klabel().name().startsWith("#SemanticCastTo") && app.items().size() == 1 && app.items().get(0) instanceof KVariable) { - error = false; - } - } - } - if (error) { - errors.add(KEMException.compilerError("Found #as pattern where the right side is not a variable.", as)); - } - super.apply(as); + private void check(K k) { + new VisitK() { + @Override + public void apply(KAs as) { + boolean error = false; + if (!(as.alias() instanceof KVariable)) { + error = true; + if (as.alias() instanceof KApply app) { + if (app.klabel().name().startsWith("#SemanticCastTo") + && app.items().size() == 1 + && app.items().get(0) instanceof KVariable) { + error = false; } - }.apply(k); - } - - public void check(Sentence s) { - if (s instanceof RuleOrClaim r) { - check(r.body()); - check(r.requires()); - check(r.ensures()); - } else if (s instanceof Context c) { - check(c.body()); - check(c.requires()); - } else if (s instanceof ContextAlias c) { - check(c.body()); - check(c.requires()); + } + } + if (error) { + errors.add( + KEMException.compilerError( + "Found #as pattern where the right side is not a variable.", as)); } + super.apply(as); + } + }.apply(k); + } + + public void check(Sentence s) { + if (s instanceof RuleOrClaim r) { + check(r.body()); + check(r.requires()); + check(r.ensures()); + } else if (s instanceof Context c) { + check(c.body()); + check(c.requires()); + } else if (s instanceof ContextAlias c) { + check(c.body()); + check(c.requires()); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckKLabels.java b/kernel/src/main/java/org/kframework/compile/checks/CheckKLabels.java index a7947a43dbc..1fb6905597b 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckKLabels.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckKLabels.java @@ -1,7 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.Collections.*; + import com.google.common.collect.ImmutableSet; +import java.io.File; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; import org.apache.commons.collections4.CollectionUtils; import org.kframework.Collections; import org.kframework.attributes.Att; @@ -22,184 +28,261 @@ import org.kframework.utils.errorsystem.KException.ExceptionType; import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; - -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.stream.Collectors; import scala.Tuple2; -import static org.kframework.Collections.*; - /** - * Checks to ensure that KLabels in the definition obey rules relating to their use. First, klabels used in rules must - * be defined by a production in one of the modules imported by the module the rule is in. Second, any given klabel - * can only be defined in one module. This ensures that klabels don't mix across modules without strictly enforcing - * the requirement that all klabels be unique, or that all klabels be qualified by their module name. + * Checks to ensure that KLabels in the definition obey rules relating to their use. First, klabels + * used in rules must be defined by a production in one of the modules imported by the module the + * rule is in. Second, any given klabel can only be defined in one module. This ensures that klabels + * don't mix across modules without strictly enforcing the requirement that all klabels be unique, + * or that all klabels be qualified by their module name. */ public class CheckKLabels { - private final Set errors; - private final KExceptionManager kem; - private final FileUtil files; - private final List extraConcreteRules; - public CheckKLabels(Set errors, KExceptionManager kem, FileUtil files, List extraConcreteRules) { - this.errors = errors; - this.kem = kem; - this.files = files; - this.extraConcreteRules = extraConcreteRules; - } + private final Set errors; + private final KExceptionManager kem; + private final FileUtil files; + private final List extraConcreteRules; - private final Map klabels = new HashMap<>(); - private final Map klabelProds = new HashMap<>(); - private final Set usedLabels = new HashSet<>(); + public CheckKLabels( + Set errors, + KExceptionManager kem, + FileUtil files, + List extraConcreteRules) { + this.errors = errors; + this.kem = kem; + this.files = files; + this.extraConcreteRules = extraConcreteRules; + } - public void check(Sentence sentence, Module m) { - VisitK checkKLabels = new VisitK() { - @Override - public void apply(InjectedKLabel k) { - apply(k.klabel(), k); - super.apply(k); - } + private final Map klabels = new HashMap<>(); + private final Map klabelProds = new HashMap<>(); + private final Set usedLabels = new HashSet<>(); - @Override - public void apply(KApply k) { - apply(k.klabel(), k); - super.apply(k); - } + public void check(Sentence sentence, Module m) { + VisitK checkKLabels = + new VisitK() { + @Override + public void apply(InjectedKLabel k) { + apply(k.klabel(), k); + super.apply(k); + } - private void apply(KLabel klabel, K k) { - if (klabel instanceof KVariable) - return; - Optional s = k.att().getOptional(Source.class); - if (s.isPresent()) { - usedLabels.add(klabel.name()); - if (m.definedKLabels().apply(klabel)) { - for (Production prod : iterable(m.productionsFor().apply(klabel.head()))) { - if (prod.source().isPresent() && prod.location().isPresent()) { - usedLabels.addAll(stream(m.productionsForLoc().apply(Tuple2.apply(prod.source().get(), prod.location().get()))) - .filter(p -> p.klabel().isDefined()).map(p -> p.klabel().get().name()).collect(Collectors.toSet())); - } - } - } - } - if (!m.definedKLabels().apply(klabel) && !isInternalKLabel(klabel.name(), m)) { - errors.add(KEMException.compilerError("Found klabel " + klabel.name() + " not defined in any production.", k)); + @Override + public void apply(KApply k) { + apply(k.klabel(), k); + super.apply(k); + } + + private void apply(KLabel klabel, K k) { + if (klabel instanceof KVariable) return; + Optional s = k.att().getOptional(Source.class); + if (s.isPresent()) { + usedLabels.add(klabel.name()); + if (m.definedKLabels().apply(klabel)) { + for (Production prod : iterable(m.productionsFor().apply(klabel.head()))) { + if (prod.source().isPresent() && prod.location().isPresent()) { + usedLabels.addAll( + stream( + m.productionsForLoc() + .apply( + Tuple2.apply(prod.source().get(), prod.location().get()))) + .filter(p -> p.klabel().isDefined()) + .map(p -> p.klabel().get().name()) + .collect(Collectors.toSet())); + } } + } } - }; - if (sentence instanceof Rule rl) { - checkKLabels.apply(rl.body()); - checkKLabels.apply(rl.requires()); - checkKLabels.apply(rl.ensures()); - } else if (sentence instanceof Context ctx) { - checkKLabels.apply(ctx.body()); - checkKLabels.apply(ctx.requires()); - } else if (sentence instanceof ContextAlias ctx) { - checkKLabels.apply(ctx.body()); - checkKLabels.apply(ctx.requires()); - } else if (sentence instanceof Production prod) { - if (prod.klabel().isDefined()) { - KLabel klabel = prod.klabel().get(); - if (klabelProds.containsKey(klabel.name()) && !internalDuplicates.contains(klabel.name())) { - errors.add(KEMException.compilerError("Symbol " + klabel.name() + " is not unique. Previously defined as: " + klabelProds.get(klabel.name()), prod)); - } - klabels.put(klabel.name(), m); - klabelProds.put(klabel.name(), prod); + if (!m.definedKLabels().apply(klabel) && !isInternalKLabel(klabel.name(), m)) { + errors.add( + KEMException.compilerError( + "Found klabel " + klabel.name() + " not defined in any production.", k)); } + } + }; + if (sentence instanceof Rule rl) { + checkKLabels.apply(rl.body()); + checkKLabels.apply(rl.requires()); + checkKLabels.apply(rl.ensures()); + } else if (sentence instanceof Context ctx) { + checkKLabels.apply(ctx.body()); + checkKLabels.apply(ctx.requires()); + } else if (sentence instanceof ContextAlias ctx) { + checkKLabels.apply(ctx.body()); + checkKLabels.apply(ctx.requires()); + } else if (sentence instanceof Production prod) { + if (prod.klabel().isDefined()) { + KLabel klabel = prod.klabel().get(); + if (klabelProds.containsKey(klabel.name()) && !internalDuplicates.contains(klabel.name())) { + errors.add( + KEMException.compilerError( + "Symbol " + + klabel.name() + + " is not unique. Previously defined as: " + + klabelProds.get(klabel.name()), + prod)); } + klabels.put(klabel.name(), m); + klabelProds.put(klabel.name(), prod); + } } + } - private boolean isExtraConcreteRule(Rule r) { - return r.label().isPresent() && extraConcreteRules.contains(r.label().get()); - } + private boolean isExtraConcreteRule(Rule r) { + return r.label().isPresent() && extraConcreteRules.contains(r.label().get()); + } - private boolean hasSymbolicAttWithNoArg(Rule r) { - return r.att().contains(Att.SYMBOLIC()) && r.att().get(Att.SYMBOLIC()).equals(""); - } + private boolean hasSymbolicAttWithNoArg(Rule r) { + return r.att().contains(Att.SYMBOLIC()) && r.att().get(Att.SYMBOLIC()).equals(""); + } - private boolean hasConcreteAttWithNoArg(Rule r) { - return isExtraConcreteRule(r) || (r.att().contains(Att.CONCRETE()) && r.att().get(Att.CONCRETE()).equals("")); - } + private boolean hasConcreteAttWithNoArg(Rule r) { + return isExtraConcreteRule(r) + || (r.att().contains(Att.CONCRETE()) && r.att().get(Att.CONCRETE()).equals("")); + } - private boolean hasConcreteAtt(Rule r) { - return isExtraConcreteRule(r) || r.att().contains(Att.CONCRETE()); - } + private boolean hasConcreteAtt(Rule r) { + return isExtraConcreteRule(r) || r.att().contains(Att.CONCRETE()); + } - public void check(Module mainMod) { - Set definedButNotUsed = new HashSet<>(klabelProds.keySet()); - definedButNotUsed.removeAll(usedLabels); - File includeDir = files.resolveKInclude("."); - String canonicalPath; - try { - canonicalPath = includeDir.getCanonicalPath(); - if (!canonicalPath.endsWith(File.separator)) { - canonicalPath = canonicalPath + File.separator; - } - } catch (IOException e) { - canonicalPath = null; + public void check(Module mainMod) { + Set definedButNotUsed = new HashSet<>(klabelProds.keySet()); + definedButNotUsed.removeAll(usedLabels); + File includeDir = files.resolveKInclude("."); + String canonicalPath; + try { + canonicalPath = includeDir.getCanonicalPath(); + if (!canonicalPath.endsWith(File.separator)) { + canonicalPath = canonicalPath + File.separator; + } + } catch (IOException e) { + canonicalPath = null; + } + for (String symbol : definedButNotUsed) { + Production prod = klabelProds.get(symbol); + Optional s = prod.source(); + if (prod.att().contains(Att.MAINCELL()) + || prod.att().contains(Att.UNUSED()) + || symbol.equals("") + || !s.isPresent() + || (prod.att().contains(Att.CELL()) + && stream(prod.nonterminals()) + .filter( + nt -> + klabels + .get(symbol) + .sortAttributesFor() + .get(nt.sort().head()) + .getOrElse(() -> Att.empty()) + .contains(Att.CELL_COLLECTION())) + .findAny() + .isPresent())) { + continue; + } + if (canonicalPath == null || !s.get().source().contains(canonicalPath)) { + kem.registerCompilerWarning( + ExceptionType.UNUSED_SYMBOL, + errors, + "Symbol '" + + symbol + + "' defined but not used. Add the 'unused' attribute if this is intentional.", + klabelProds.get(symbol)); + } + } + for (KLabel function : iterable(mainMod.functions())) { + boolean allConcrete = true; + boolean allSymbolic = true; + for (Rule rule : + iterable(mainMod.rulesFor().get(function).getOrElse(() -> Collections.Set()))) { + if ((hasConcreteAttWithNoArg(rule) && rule.att().contains(Att.SYMBOLIC())) + || (hasSymbolicAttWithNoArg(rule) && hasConcreteAtt(rule))) { + errors.add( + KEMException.compilerError( + "Rule cannot be both concrete and symbolic in the same variable.", rule)); } - for (String symbol : definedButNotUsed) { - Production prod = klabelProds.get(symbol); - Optional s = prod.source(); - if (prod.att().contains(Att.MAINCELL()) || - prod.att().contains(Att.UNUSED()) || - symbol.equals("") || - !s.isPresent() || - (prod.att().contains(Att.CELL()) && stream(prod.nonterminals()).filter(nt -> klabels.get(symbol).sortAttributesFor().get(nt.sort().head()).getOrElse(() -> Att.empty()).contains(Att.CELL_COLLECTION())).findAny().isPresent())) { - continue; - } - if (canonicalPath == null || !s.get().source().contains(canonicalPath)) { - kem.registerCompilerWarning(ExceptionType.UNUSED_SYMBOL, errors, "Symbol '" + symbol + "' defined but not used. Add the 'unused' attribute if this is intentional.", klabelProds.get(symbol)); - } + if (!hasConcreteAttWithNoArg(rule) && !rule.att().contains(Att.SIMPLIFICATION())) { + allConcrete = false; } - for (KLabel function : iterable(mainMod.functions())) { - boolean allConcrete = true; - boolean allSymbolic = true; - for (Rule rule : iterable(mainMod.rulesFor().get(function).getOrElse(() -> Collections.Set()))) { - if ((hasConcreteAttWithNoArg(rule) && rule.att().contains(Att.SYMBOLIC())) || - (hasSymbolicAttWithNoArg(rule) && hasConcreteAtt(rule))) { - errors.add(KEMException.compilerError("Rule cannot be both concrete and symbolic in the same variable.", rule)); - } - if (!hasConcreteAttWithNoArg(rule) && !rule.att().contains(Att.SIMPLIFICATION())) { - allConcrete = false; - } - if (!hasSymbolicAttWithNoArg(rule) && !rule.att().contains(Att.SIMPLIFICATION())) { - allSymbolic = false; - } - } - // If concrete or symbolic is used on the rule for a function, force all of them to have the same attribute - // to keep the soundness of the definition. Exception are simplification rules which need to be sound by themselves. - // https://github.com/runtimeverification/k/issues/1591 - for (Rule rule : iterable(mainMod.rulesFor().get(function).getOrElse(() -> Collections.Set()))) { - if (hasConcreteAtt(rule) && !allConcrete && !rule.att().contains(Att.SIMPLIFICATION())) { - errors.add(KEMException.compilerError("Found concrete attribute without simplification attribute on function with one or more non-concrete rules.", rule)); - } - if (rule.att().contains(Att.SYMBOLIC()) && !allSymbolic && !rule.att().contains(Att.SIMPLIFICATION())) { - errors.add(KEMException.compilerError("Found symbolic attribute without simplification attribute on function with one or more non-symbolic rules.", rule)); - } - } + if (!hasSymbolicAttWithNoArg(rule) && !rule.att().contains(Att.SIMPLIFICATION())) { + allSymbolic = false; } - for (Rule rule : iterable(mainMod.rules())) { - Att att = rule.att(); - if (att.contains(Att.SIMPLIFICATION()) && hasConcreteAtt(rule) && att.contains(Att.SYMBOLIC())) { - Collection concreteVars = Arrays.stream(att.getOptional(Att.CONCRETE()).orElse("").split(",")) - .map(String::trim).collect(Collectors.toList()); - Collection symbolicVars = Arrays.stream(att.get(Att.SYMBOLIC()).split(",")) - .map(String::trim).collect(Collectors.toList()); - if (concreteVars.isEmpty() || symbolicVars.isEmpty()) - errors.add(KEMException.compilerError("Rule cannot be both concrete and symbolic in the same variable.", rule)); - Collection intersection = CollectionUtils.intersection(concreteVars, symbolicVars); - if (!intersection.isEmpty()) - errors.add(KEMException.compilerError("Rule cannot be both concrete and symbolic in the same variable: " + intersection, rule)); - } + } + // If concrete or symbolic is used on the rule for a function, force all of them to have the + // same attribute + // to keep the soundness of the definition. Exception are simplification rules which need to + // be sound by themselves. + // https://github.com/runtimeverification/k/issues/1591 + for (Rule rule : + iterable(mainMod.rulesFor().get(function).getOrElse(() -> Collections.Set()))) { + if (hasConcreteAtt(rule) && !allConcrete && !rule.att().contains(Att.SIMPLIFICATION())) { + errors.add( + KEMException.compilerError( + "Found concrete attribute without simplification attribute on function with one" + + " or more non-concrete rules.", + rule)); + } + if (rule.att().contains(Att.SYMBOLIC()) + && !allSymbolic + && !rule.att().contains(Att.SIMPLIFICATION())) { + errors.add( + KEMException.compilerError( + "Found symbolic attribute without simplification attribute on function with one" + + " or more non-symbolic rules.", + rule)); } + } } + for (Rule rule : iterable(mainMod.rules())) { + Att att = rule.att(); + if (att.contains(Att.SIMPLIFICATION()) + && hasConcreteAtt(rule) + && att.contains(Att.SYMBOLIC())) { + Collection concreteVars = + Arrays.stream(att.getOptional(Att.CONCRETE()).orElse("").split(",")) + .map(String::trim) + .collect(Collectors.toList()); + Collection symbolicVars = + Arrays.stream(att.get(Att.SYMBOLIC()).split(",")) + .map(String::trim) + .collect(Collectors.toList()); + if (concreteVars.isEmpty() || symbolicVars.isEmpty()) + errors.add( + KEMException.compilerError( + "Rule cannot be both concrete and symbolic in the same variable.", rule)); + Collection intersection = CollectionUtils.intersection(concreteVars, symbolicVars); + if (!intersection.isEmpty()) + errors.add( + KEMException.compilerError( + "Rule cannot be both concrete and symbolic in the same variable: " + intersection, + rule)); + } + } + } - private static final ImmutableSet internalDuplicates = ImmutableSet.of("#EmptyKList", "#EmptyK", "#ruleRequires", "#ruleRequiresEnsures", "#Top", "#Bottom"); + private static final ImmutableSet internalDuplicates = + ImmutableSet.of( + "#EmptyKList", "#EmptyK", "#ruleRequires", "#ruleRequiresEnsures", "#Top", "#Bottom"); - private static final ImmutableSet internalNames = ImmutableSet.of("#cells", "#dots", "#noDots", "#Or", "#fun2", "#fun3", "#let", "#withConfig", "", "#SemanticCastToBag", "_:=K_", "_:/=K_"); + private static final ImmutableSet internalNames = + ImmutableSet.of( + "#cells", + "#dots", + "#noDots", + "#Or", + "#fun2", + "#fun3", + "#let", + "#withConfig", + "", + "#SemanticCastToBag", + "_:=K_", + "_:/=K_"); - public static boolean isInternalKLabel(String name, Module m) { - return m.semanticCasts().apply(name) || internalNames.contains(name)|| m.recordProjections().apply(name) || m.sortPredicates().apply(name) || m.sortProjections().apply(name); - } + public static boolean isInternalKLabel(String name, Module m) { + return m.semanticCasts().apply(name) + || internalNames.contains(name) + || m.recordProjections().apply(name) + || m.sortPredicates().apply(name) + || m.sortProjections().apply(name); + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckLabels.java b/kernel/src/main/java/org/kframework/compile/checks/CheckLabels.java index 2c55fcd94eb..62318e75687 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckLabels.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckLabels.java @@ -1,36 +1,31 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; +import java.util.TreeSet; import org.kframework.definition.ContextAlias; -import org.kframework.definition.Module; import org.kframework.definition.Sentence; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; -import java.util.TreeSet; - -/** - * Check that all sentence labels in a module are unique. - */ +/** Check that all sentence labels in a module are unique. */ public class CheckLabels { - private final Set errors; + private final Set errors; - public CheckLabels(Set errors) { - this.errors = errors; - } + public CheckLabels(Set errors) { + this.errors = errors; + } - private final Set labels = new TreeSet<>(); + private final Set labels = new TreeSet<>(); - public void check(Sentence sentence) { - if (sentence instanceof ContextAlias) { - return; - } - if (sentence.label().isPresent()) { - String label = sentence.label().get(); - if (!labels.add(label)) { - errors.add(KEMException.compilerError("Found duplicate sentence label " + label, sentence)); - } - } + public void check(Sentence sentence) { + if (sentence instanceof ContextAlias) { + return; } + if (sentence.label().isPresent()) { + String label = sentence.label().get(); + if (!labels.add(label)) { + errors.add(KEMException.compilerError("Found duplicate sentence label " + label, sentence)); + } + } + } } - diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckListDecl.java b/kernel/src/main/java/org/kframework/compile/checks/CheckListDecl.java index fd58b25c86e..49e1127e73f 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckListDecl.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckListDecl.java @@ -2,6 +2,7 @@ package org.kframework.compile.checks; import com.google.common.collect.ImmutableSet; +import java.util.Set; import org.kframework.builtin.Sorts; import org.kframework.kil.Module; import org.kframework.kil.ModuleItem; @@ -12,52 +13,49 @@ import org.kframework.kil.UserList; import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.errorsystem.KExceptionManager; - -import java.util.Set; /** - * Checks user list declarations: - * - Base sorts cannot be extended with list. - * - Circular lists are not allowed. - * - Inline lists are not allowed. + * Checks user list declarations: - Base sorts cannot be extended with list. - Circular lists are + * not allowed. - Inline lists are not allowed. */ public class CheckListDecl { - public static void check(Module m) { - m.getItems().stream().forEach(CheckListDecl::check); // i -> check(i) - } - - private static final Set BASE_SORTS = ImmutableSet.of(Sorts.K(), Sorts.KResult(), Sorts.KItem(), - Sorts.KList(), Sorts.Bag(), Sorts.KLabel()); - - private static boolean isBaseSort(Sort sort) { - return BASE_SORTS.contains(sort); - } - - - private static void check(ModuleItem i) { - if (i instanceof Syntax s) { - for (PriorityBlock b : s.getPriorityBlocks()) { - for (Production p : b.getProductions()) { - if (p.getItems().size() == 1 && p.getItems().get(0) instanceof UserList) { // Syntax Es ::= List{E,""} - Sort listSort = s.getDeclaredSort().getSort(); // Es - Sort elemSort = ((UserList) p.getItems().get(0)).getSort(); // E - if (isBaseSort(listSort)) { - throw KEMException.compilerError(listSort + " can not be extended to be a list sort.", p); - } - if (listSort.equals(elemSort)) { - throw KEMException.compilerError("Circular lists are not allowed.", p); - } - } else { - for (ProductionItem it : p.getItems()) { - if (it instanceof UserList) { // Syntax Es ::= ... List{E,""} ... - throw KEMException.compilerError("Inline list declarations are not allowed.", it); - } - } - } - } + public static void check(Module m) { + m.getItems().stream().forEach(CheckListDecl::check); // i -> check(i) + } + + private static final Set BASE_SORTS = + ImmutableSet.of( + Sorts.K(), Sorts.KResult(), Sorts.KItem(), Sorts.KList(), Sorts.Bag(), Sorts.KLabel()); + + private static boolean isBaseSort(Sort sort) { + return BASE_SORTS.contains(sort); + } + + private static void check(ModuleItem i) { + if (i instanceof Syntax s) { + for (PriorityBlock b : s.getPriorityBlocks()) { + for (Production p : b.getProductions()) { + if (p.getItems().size() == 1 + && p.getItems().get(0) instanceof UserList) { // Syntax Es ::= List{E,""} + Sort listSort = s.getDeclaredSort().getSort(); // Es + Sort elemSort = ((UserList) p.getItems().get(0)).getSort(); // E + if (isBaseSort(listSort)) { + throw KEMException.compilerError( + listSort + " can not be extended to be a list sort.", p); + } + if (listSort.equals(elemSort)) { + throw KEMException.compilerError("Circular lists are not allowed.", p); + } + } else { + for (ProductionItem it : p.getItems()) { + if (it instanceof UserList) { // Syntax Es ::= ... List{E,""} ... + throw KEMException.compilerError("Inline list declarations are not allowed.", it); + } } + } } + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckRHSVariables.java b/kernel/src/main/java/org/kframework/compile/checks/CheckRHSVariables.java index 19c80ae5177..319f950866c 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckRHSVariables.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckRHSVariables.java @@ -2,6 +2,8 @@ package org.kframework.compile.checks; import com.google.common.collect.Sets; +import java.util.HashSet; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.backend.Backends; import org.kframework.compile.GatherVarsVisitor; @@ -17,108 +19,117 @@ import org.kframework.utils.errorsystem.KEMException; import scala.Option; -import java.util.HashSet; -import java.util.Set; - /** - * Checks a sentence to determine if it declares any variables in the RHS that are not bound in the LHS. + * Checks a sentence to determine if it declares any variables in the RHS that are not bound in the + * LHS. * - * More specifically, it performs the following checks: for each anonymous variable, if it is on the right hand side - * of a rewrite operator, and does not signify a fresh variable or constant, it is an error. For each non-anonymous - * variable, if it is on the right hand side of a rewrite operator, it is an error if it does not appear anywhere on the - * left hand side of the rule, and does not signify a fresh variable or constant. + *

More specifically, it performs the following checks: for each anonymous variable, if it is on + * the right hand side of a rewrite operator, and does not signify a fresh variable or constant, it + * is an error. For each non-anonymous variable, if it is on the right hand side of a rewrite + * operator, it is an error if it does not appear anywhere on the left hand side of the rule, and + * does not signify a fresh variable or constant. * - * Exception: this check takes into account the {@code Att.UNBOUND_VARIABLES()} attribute and allows the - * variables whose names are specified by the attribute to be unbound in the LHS. + *

Exception: this check takes into account the {@code Att.UNBOUND_VARIABLES()} attribute and + * allows the variables whose names are specified by the attribute to be unbound in the LHS. */ public class CheckRHSVariables { - private final Set errors; - private final boolean errorExistential; - private final String backend; + private final Set errors; + private final boolean errorExistential; + private final String backend; - public CheckRHSVariables(Set errors, boolean errorExistential, String backend) { - this.errors = errors; - this.errorExistential = errorExistential; - this.backend = backend; - } - private void check(RuleOrClaim rule) { - resetVars(); - Set unboundVariableNames = getUnboundVarNames(rule); - boolean errorExistential = this.errorExistential && !(rule.att().contains(Att.LABEL()) && rule.att().get(Att.LABEL()).equals("STDIN-STREAM.stdinUnblock")); - new PatternValueAwareVisitor(true, errors).apply(rule.body()); - new PatternValueAwareVisitor(false, errors).apply(rule.requires()); - new PatternValueAwareVisitor(false, errors).apply(rule.ensures()); - gatherVars(true, rule.body(), errorExistential); - gatherVars(false, rule.ensures(), errorExistential); - if (rule instanceof Claim || (rule instanceof Rule && backend.equals(Backends.HASKELL))) { - gatherVars(true, rule.requires(), errorExistential); - check(rule.body(), true, false, unboundVariableNames); - check(rule.requires(), true, false, unboundVariableNames); - } else { - gatherVars(false, rule.requires(), errorExistential); - check(rule.body(), true, false, unboundVariableNames); - check(rule.requires(), false, false, unboundVariableNames); - } - check(rule.ensures(), false, false, unboundVariableNames); - } + public CheckRHSVariables(Set errors, boolean errorExistential, String backend) { + this.errors = errors; + this.errorExistential = errorExistential; + this.backend = backend; + } - private void check(Context context) { - resetVars(); - gatherVars(true, context.body(), false); - gatherVars(false, context.requires(), false); - check(context.body(), true, false, new HashSet<>()); - check(context.requires(), false, false, new HashSet<>()); + private void check(RuleOrClaim rule) { + resetVars(); + Set unboundVariableNames = getUnboundVarNames(rule); + boolean errorExistential = + this.errorExistential + && !(rule.att().contains(Att.LABEL()) + && rule.att().get(Att.LABEL()).equals("STDIN-STREAM.stdinUnblock")); + new PatternValueAwareVisitor(true, errors).apply(rule.body()); + new PatternValueAwareVisitor(false, errors).apply(rule.requires()); + new PatternValueAwareVisitor(false, errors).apply(rule.ensures()); + gatherVars(true, rule.body(), errorExistential); + gatherVars(false, rule.ensures(), errorExistential); + if (rule instanceof Claim || (rule instanceof Rule && backend.equals(Backends.HASKELL))) { + gatherVars(true, rule.requires(), errorExistential); + check(rule.body(), true, false, unboundVariableNames); + check(rule.requires(), true, false, unboundVariableNames); + } else { + gatherVars(false, rule.requires(), errorExistential); + check(rule.body(), true, false, unboundVariableNames); + check(rule.requires(), false, false, unboundVariableNames); } + check(rule.ensures(), false, false, unboundVariableNames); + } - private void check(ContextAlias context) { - resetVars(); - gatherVars(true, context.body(), false); - gatherVars(false, context.requires(), false); - check(context.body(), true, true, new HashSet<>()); - check(context.requires(), false, true, new HashSet<>()); - } + private void check(Context context) { + resetVars(); + gatherVars(true, context.body(), false); + gatherVars(false, context.requires(), false); + check(context.body(), true, false, new HashSet<>()); + check(context.requires(), false, false, new HashSet<>()); + } + + private void check(ContextAlias context) { + resetVars(); + gatherVars(true, context.body(), false); + gatherVars(false, context.requires(), false); + check(context.body(), true, true, new HashSet<>()); + check(context.requires(), false, true, new HashSet<>()); + } - public void check(Sentence s) { - if (s instanceof RuleOrClaim) { - check((RuleOrClaim) s); - } else if (s instanceof Context) { - check((Context) s); - } else if (s instanceof ContextAlias) { - check((ContextAlias) s); - } + public void check(Sentence s) { + if (s instanceof RuleOrClaim) { + check((RuleOrClaim) s); + } else if (s instanceof Context) { + check((Context) s); + } else if (s instanceof ContextAlias) { + check((ContextAlias) s); } + } - private Set getUnboundVarNames(RuleOrClaim rule) { - Option unboundVariablesString = rule.att().getOption(Att.UNBOUND_VARIABLES()); - Set unboundVariableNames = new HashSet<>(); - if (unboundVariablesString.nonEmpty()) { - String[] components = unboundVariablesString.get().split(","); - for (String component : components) { - unboundVariableNames.add(component.trim()); - } - } - return unboundVariableNames; + private Set getUnboundVarNames(RuleOrClaim rule) { + Option unboundVariablesString = rule.att().getOption(Att.UNBOUND_VARIABLES()); + Set unboundVariableNames = new HashSet<>(); + if (unboundVariablesString.nonEmpty()) { + String[] components = unboundVariablesString.get().split(","); + for (String component : components) { + unboundVariableNames.add(component.trim()); + } } + return unboundVariableNames; + } - private final Set vars = Sets.newHashSet(); + private final Set vars = Sets.newHashSet(); - void resetVars() { - vars.clear(); - } + void resetVars() { + vars.clear(); + } - void gatherVars(boolean isBody, K term, boolean isMacro) { - new GatherVarsVisitor(isBody, errors, vars, isMacro).apply(term); - } + void gatherVars(boolean isBody, K term, boolean isMacro) { + new GatherVarsVisitor(isBody, errors, vars, isMacro).apply(term); + } - private void check(K body, boolean isBody, boolean isAlias, Set unboundVarNames) { - Set unbound = new HashSet<>(); - new ComputeUnboundVariables(isBody, false, errors, vars, unbound::add).apply(body); - for (KVariable k : unbound) { - if (unboundVarNames.contains(k.name())) continue; - if (isAlias && k.name().equals("HOLE")) continue; - errors.add(KEMException.compilerError("Found variable " + k.name() - + " on right hand side of rule, not bound on left hand side." - + " Did you mean \"?" + k.name() + "\"?", k)); - } + private void check(K body, boolean isBody, boolean isAlias, Set unboundVarNames) { + Set unbound = new HashSet<>(); + new ComputeUnboundVariables(isBody, false, errors, vars, unbound::add).apply(body); + for (KVariable k : unbound) { + if (unboundVarNames.contains(k.name())) continue; + if (isAlias && k.name().equals("HOLE")) continue; + errors.add( + KEMException.compilerError( + "Found variable " + + k.name() + + " on right hand side of rule, not bound on left hand side." + + " Did you mean \"?" + + k.name() + + "\"?", + k)); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckRewrite.java b/kernel/src/main/java/org/kframework/compile/checks/CheckRewrite.java index a6e7536df6f..b5f3a18401b 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckRewrite.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckRewrite.java @@ -1,11 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; import org.kframework.definition.Claim; import org.kframework.definition.Module; import org.kframework.definition.RuleOrClaim; import org.kframework.definition.Sentence; -import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KAs; import org.kframework.kore.KRewrite; @@ -13,154 +13,169 @@ import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - -/** - * Created by dwightguth on 1/25/16. - */ +/** Created by dwightguth on 1/25/16. */ public record CheckRewrite(Set errors, Module m) { - public void check(Sentence sentence) { - if (sentence instanceof RuleOrClaim) { - check((RuleOrClaim) sentence, sentence instanceof Claim); - } + public void check(Sentence sentence) { + if (sentence instanceof RuleOrClaim) { + check((RuleOrClaim) sentence, sentence instanceof Claim); } + } - private void check(RuleOrClaim sentence, boolean isClaim) { - class Holder { - boolean hasRewrite = false; - boolean inRewrite = false; - boolean inRewriteRHS = false; - boolean inAs = false; - boolean inFunctionContext = false; - boolean inFunctionBody = false; - } - Holder h = new Holder(); - VisitK visitor = new VisitK() { - @Override - public void apply(KRewrite k) { - boolean inRewrite = h.inRewrite; - boolean inRewriteRHS = h.inRewriteRHS; - if (h.inRewrite) { - errors.add(KEMException.compilerError("Rewrites are not allowed to be nested.", k)); - } - if (h.inFunctionContext) { - errors.add(KEMException.compilerError("Rewrites are not allowed in the context of a function rule.", k)); - } - if (h.inAs) { - errors.add(KEMException.compilerError("Rewrites are not allowed inside an #as pattern.", k)); - } - h.hasRewrite = true; - h.inRewrite = true; - super.apply(k.left()); - h.inRewriteRHS = true; - super.apply(k.right()); - h.inRewriteRHS = inRewriteRHS; - h.inRewrite = inRewrite; + private void check(RuleOrClaim sentence, boolean isClaim) { + class Holder { + boolean hasRewrite = false; + boolean inRewrite = false; + boolean inRewriteRHS = false; + boolean inAs = false; + boolean inFunctionContext = false; + boolean inFunctionBody = false; + } + Holder h = new Holder(); + VisitK visitor = + new VisitK() { + @Override + public void apply(KRewrite k) { + boolean inRewrite = h.inRewrite; + boolean inRewriteRHS = h.inRewriteRHS; + if (h.inRewrite) { + errors.add(KEMException.compilerError("Rewrites are not allowed to be nested.", k)); } - - @Override - public void apply(KAs k) { - boolean inAs = h.inAs; - if (h.inRewriteRHS) - errors.add(KEMException.compilerError("#as is not allowed in the RHS of a rule.", k)); - h.inAs = true; - super.apply(k); - h.inAs = inAs; + if (h.inFunctionContext) { + errors.add( + KEMException.compilerError( + "Rewrites are not allowed in the context of a function rule.", k)); + } + if (h.inAs) { + errors.add( + KEMException.compilerError("Rewrites are not allowed inside an #as pattern.", k)); } + h.hasRewrite = true; + h.inRewrite = true; + super.apply(k.left()); + h.inRewriteRHS = true; + super.apply(k.right()); + h.inRewriteRHS = inRewriteRHS; + h.inRewrite = inRewrite; + } - @Override - public void apply(KVariable k) { - if (!h.inRewriteRHS && k.name().startsWith("?")) { - errors.add(KEMException.compilerError( - "Existential variable " + k.name() + " found in LHS. Existential variables are only allowed in the RHS.", k)); - } + @Override + public void apply(KAs k) { + boolean inAs = h.inAs; + if (h.inRewriteRHS) + errors.add(KEMException.compilerError("#as is not allowed in the RHS of a rule.", k)); + h.inAs = true; + super.apply(k); + h.inAs = inAs; + } + + @Override + public void apply(KVariable k) { + if (!h.inRewriteRHS && k.name().startsWith("?")) { + errors.add( + KEMException.compilerError( + "Existential variable " + + k.name() + + " found in LHS. Existential variables are only allowed in the RHS.", + k)); } + } - @Override - public void apply(KApply k) { - if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#fun2") || k.klabel().name().equals("#fun3")) { - if (k.klabel().name().equals("#fun2")) { - boolean wasInRewrite = h.inRewrite; - boolean hadRewrite = h.hasRewrite; - boolean wasInFunctionContext = h.inFunctionContext; - boolean wasInFunctionBody = h.inFunctionBody; - h.inRewrite = false; - h.hasRewrite = false; - h.inFunctionContext = false; - h.inFunctionBody = false; - apply(k.items().get(0)); - if (!h.hasRewrite) { - errors.add(KEMException.compilerError("#fun expressions must have at least one rewrite.", k)); - } - // in well formed programs this should always reset to true and true, but we want to make sure we - // don't create spurious reports if this constraint was violated by the user. - h.inRewrite = wasInRewrite; - h.hasRewrite = hadRewrite; - h.inFunctionContext = wasInFunctionContext; - h.inFunctionBody = wasInFunctionBody; - apply(k.items().get(1)); - } else if (k.klabel().name().equals("#fun3")) { - boolean wasInRewrite = h.inRewrite; - boolean hadRewrite = h.hasRewrite; - boolean wasInFunctionContext = h.inFunctionContext; - boolean wasInFunctionBody = h.inFunctionBody; - h.inRewrite = true; - h.hasRewrite = true; - h.inFunctionContext = false; - h.inFunctionBody = false; - apply(k.items().get(0)); - apply(k.items().get(1)); - // in well formed programs this should always reset to true and true, but we want to make sure we - // don't create spurious reports if this constraint was violated by the user. - h.inRewrite = wasInRewrite; - h.hasRewrite = hadRewrite; - h.inFunctionContext = wasInFunctionContext; - h.inFunctionBody = wasInFunctionBody; - apply(k.items().get(2)); - } else { - boolean wasInRewrite = h.inRewrite; - boolean hadRewrite = h.hasRewrite; - boolean wasInFunctionContext = h.inFunctionContext; - boolean wasInFunctionBody = h.inFunctionBody; - h.inRewrite = true; - h.hasRewrite = true; - h.inFunctionContext = false; - h.inFunctionBody = false; - apply(k.items().get(0)); - apply(k.items().get(2)); - // in well formed programs this should always reset to true and true, but we want to make sure we - // don't create spurious reports if this constraint was violated by the user. - h.inRewrite = wasInRewrite; - h.hasRewrite = hadRewrite; - h.inFunctionContext = wasInFunctionContext; - h.inFunctionBody = wasInFunctionBody; - apply(k.items().get(1)); - } - } else if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#withConfig")) { - boolean inFunctionContext = h.inFunctionContext; - boolean inFunctionBody = h.inFunctionBody; - if (h.inFunctionContext || h.inFunctionBody) { - errors.add(KEMException.compilerError("Function context is not allowed to be nested.", k)); - } - if (h.inRewrite) { - errors.add(KEMException.compilerError("Function context is not allowed inside a rewrite.", k)); - } - h.inFunctionBody = true; - apply(k.items().get(0)); - h.inFunctionBody = inFunctionBody; - h.inFunctionContext = true; - apply(k.items().get(1)); - h.inFunctionContext = inFunctionContext; - } else { - super.apply(k); + @Override + public void apply(KApply k) { + if (!(k.klabel() instanceof KVariable) && k.klabel().name().equals("#fun2") + || k.klabel().name().equals("#fun3")) { + if (k.klabel().name().equals("#fun2")) { + boolean wasInRewrite = h.inRewrite; + boolean hadRewrite = h.hasRewrite; + boolean wasInFunctionContext = h.inFunctionContext; + boolean wasInFunctionBody = h.inFunctionBody; + h.inRewrite = false; + h.hasRewrite = false; + h.inFunctionContext = false; + h.inFunctionBody = false; + apply(k.items().get(0)); + if (!h.hasRewrite) { + errors.add( + KEMException.compilerError( + "#fun expressions must have at least one rewrite.", k)); } + // in well formed programs this should always reset to true and true, but we want to + // make sure we + // don't create spurious reports if this constraint was violated by the user. + h.inRewrite = wasInRewrite; + h.hasRewrite = hadRewrite; + h.inFunctionContext = wasInFunctionContext; + h.inFunctionBody = wasInFunctionBody; + apply(k.items().get(1)); + } else if (k.klabel().name().equals("#fun3")) { + boolean wasInRewrite = h.inRewrite; + boolean hadRewrite = h.hasRewrite; + boolean wasInFunctionContext = h.inFunctionContext; + boolean wasInFunctionBody = h.inFunctionBody; + h.inRewrite = true; + h.hasRewrite = true; + h.inFunctionContext = false; + h.inFunctionBody = false; + apply(k.items().get(0)); + apply(k.items().get(1)); + // in well formed programs this should always reset to true and true, but we want to + // make sure we + // don't create spurious reports if this constraint was violated by the user. + h.inRewrite = wasInRewrite; + h.hasRewrite = hadRewrite; + h.inFunctionContext = wasInFunctionContext; + h.inFunctionBody = wasInFunctionBody; + apply(k.items().get(2)); + } else { + boolean wasInRewrite = h.inRewrite; + boolean hadRewrite = h.hasRewrite; + boolean wasInFunctionContext = h.inFunctionContext; + boolean wasInFunctionBody = h.inFunctionBody; + h.inRewrite = true; + h.hasRewrite = true; + h.inFunctionContext = false; + h.inFunctionBody = false; + apply(k.items().get(0)); + apply(k.items().get(2)); + // in well formed programs this should always reset to true and true, but we want to + // make sure we + // don't create spurious reports if this constraint was violated by the user. + h.inRewrite = wasInRewrite; + h.hasRewrite = hadRewrite; + h.inFunctionContext = wasInFunctionContext; + h.inFunctionBody = wasInFunctionBody; + apply(k.items().get(1)); + } + } else if (!(k.klabel() instanceof KVariable) + && k.klabel().name().equals("#withConfig")) { + boolean inFunctionContext = h.inFunctionContext; + boolean inFunctionBody = h.inFunctionBody; + if (h.inFunctionContext || h.inFunctionBody) { + errors.add( + KEMException.compilerError("Function context is not allowed to be nested.", k)); + } + if (h.inRewrite) { + errors.add( + KEMException.compilerError( + "Function context is not allowed inside a rewrite.", k)); + } + h.inFunctionBody = true; + apply(k.items().get(0)); + h.inFunctionBody = inFunctionBody; + h.inFunctionContext = true; + apply(k.items().get(1)); + h.inFunctionContext = inFunctionContext; + } else { + super.apply(k); } + } }; - visitor.accept(sentence.requires()); - visitor.accept(sentence.body()); - if (!h.hasRewrite && !isClaim) { - errors.add(KEMException.compilerError("Rules must have at least one rewrite.", sentence.body())); - } + visitor.accept(sentence.requires()); + visitor.accept(sentence.body()); + if (!h.hasRewrite && !isClaim) { + errors.add( + KEMException.compilerError("Rules must have at least one rewrite.", sentence.body())); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckSmtLemmas.java b/kernel/src/main/java/org/kframework/compile/checks/CheckSmtLemmas.java index 343a0454df8..a634d09ccbe 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckSmtLemmas.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckSmtLemmas.java @@ -1,37 +1,41 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.definition.Module; import org.kframework.definition.Rule; import org.kframework.definition.Sentence; import org.kframework.kore.KApply; -import org.kframework.kore.KRewrite; import org.kframework.kore.VisitK; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - public record CheckSmtLemmas(Set errors, Module m) { - public void check(Sentence sentence) { - if ((sentence instanceof Rule) && sentence.att().contains(Att.SMT_LEMMA())) { - check((Rule) sentence); - } + public void check(Sentence sentence) { + if ((sentence instanceof Rule) && sentence.att().contains(Att.SMT_LEMMA())) { + check((Rule) sentence); } + } - private void check(Rule rule){ - new VisitK() { - @Override - public void apply(KApply k) { - if (m.productionsFor().isDefinedAt(k.klabel()) && !m.productionsFor().get(k.klabel()).get() - .exists(p -> p.att().contains(Att.SMT_HOOK()) || p.att().contains(Att.SMTLIB()))) { - errors.add(KEMException.compilerError( - "Invalid term in smt-lemma detected. All terms in smt-lemma rules require smt-hook or smtlib labels", k)); - } + private void check(Rule rule) { + new VisitK() { + @Override + public void apply(KApply k) { + if (m.productionsFor().isDefinedAt(k.klabel()) + && !m.productionsFor() + .get(k.klabel()) + .get() + .exists(p -> p.att().contains(Att.SMT_HOOK()) || p.att().contains(Att.SMTLIB()))) { + errors.add( + KEMException.compilerError( + "Invalid term in smt-lemma detected. All terms in smt-lemma rules require" + + " smt-hook or smtlib labels", + k)); + } - k.klist().items().forEach(super::apply); - } - }.accept(rule.body()); - } + k.klist().items().forEach(super::apply); + } + }.accept(rule.body()); + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckSortTopUniqueness.java b/kernel/src/main/java/org/kframework/compile/checks/CheckSortTopUniqueness.java index c813d08109f..687a17904c3 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckSortTopUniqueness.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckSortTopUniqueness.java @@ -1,6 +1,7 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import java.util.Set; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; import org.kframework.definition.Production; @@ -9,38 +10,34 @@ import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - /** - * Check that every sort has an unique top (super) sort. - * For example, the following is not allowed, since A has multiple top sorts, KList and Bag: - * syntax A - * syntax KList ::= A - * syntax Bag ::= A + * Check that every sort has an unique top (super) sort. For example, the following is not allowed, + * since A has multiple top sorts, KList and Bag: syntax A syntax KList ::= A syntax Bag ::= A */ public record CheckSortTopUniqueness(Set errors, Module module) { - public void check(Sentence s) { - if (s instanceof Production) { - check((Production) s); - } else if (s instanceof SyntaxSort) { - check((SyntaxSort) s); - } + public void check(Sentence s) { + if (s instanceof Production) { + check((Production) s); + } else if (s instanceof SyntaxSort) { + check((SyntaxSort) s); } + } - private void check(SyntaxSort p) { - check(p.sort(), p); - } + private void check(SyntaxSort p) { + check(p.sort(), p); + } - private void check(Production p) { - check(p.sort(), p); - } + private void check(Production p) { + check(p.sort(), p); + } - private void check(Sort s, Sentence p) { - if (!s.equals(Sorts.Cell()) && - module.subsorts().lessThan(s, Sorts.KList()) && - module.subsorts().lessThan(s, Sorts.Bag())) { - errors.add(KEMException.compilerError("Multiple top sorts found for " + s + ": KList and Bag.", p)); - } + private void check(Sort s, Sentence p) { + if (!s.equals(Sorts.Cell()) + && module.subsorts().lessThan(s, Sorts.KList()) + && module.subsorts().lessThan(s, Sorts.Bag())) { + errors.add( + KEMException.compilerError("Multiple top sorts found for " + s + ": KList and Bag.", p)); } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckStreams.java b/kernel/src/main/java/org/kframework/compile/checks/CheckStreams.java index 239672df519..57a0834f3bb 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckStreams.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckStreams.java @@ -1,6 +1,9 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.Collections.*; + +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; @@ -11,32 +14,29 @@ import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - -import static org.kframework.Collections.*; - -/** - * Checks that stream cells have contents of List sort. - */ +/** Checks that stream cells have contents of List sort. */ public record CheckStreams(Set errors, Module module) { - public void check(Sentence s) { - if (s instanceof Production) { - check((Production) s); - } + public void check(Sentence s) { + if (s instanceof Production) { + check((Production) s); } + } - private void check(Production p) { - if (p.att().contains(Att.CELL()) && p.att().contains(Att.STREAM())) { - ProductionItem i = mutable(p.items()).get(1); - if (i instanceof NonTerminal) { - Sort sort = ((NonTerminal) i).sort(); - if (!module.subsorts().lessThanEq(sort, Sorts.List())) { - errors.add(KEMException.compilerError("Wrong sort in streaming cell. Expected List, but found " + sort.toString() + ".", p)); - } - } else { - throw KEMException.internalError("Illegal arguments for stream cell."); - } + private void check(Production p) { + if (p.att().contains(Att.CELL()) && p.att().contains(Att.STREAM())) { + ProductionItem i = mutable(p.items()).get(1); + if (i instanceof NonTerminal) { + Sort sort = ((NonTerminal) i).sort(); + if (!module.subsorts().lessThanEq(sort, Sorts.List())) { + errors.add( + KEMException.compilerError( + "Wrong sort in streaming cell. Expected List, but found " + sort.toString() + ".", + p)); } + } else { + throw KEMException.internalError("Illegal arguments for stream cell."); + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckSyntaxGroups.java b/kernel/src/main/java/org/kframework/compile/checks/CheckSyntaxGroups.java index 015cd8e03de..dd6dcc0d5c4 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckSyntaxGroups.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckSyntaxGroups.java @@ -1,37 +1,43 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.Collections.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import org.kframework.definition.Module; import org.kframework.definition.Sentence; import org.kframework.definition.SyntaxAssociativity; import org.kframework.definition.Tag; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KException; import org.kframework.utils.errorsystem.KExceptionManager; -import org.kframework.definition.Module; -import static org.kframework.Collections.*; - -import java.util.List; -import java.util.ArrayList; -import java.util.Set; public record CheckSyntaxGroups(Set errors, Module module, KExceptionManager kem) { - public void check(Sentence s) { - if(s instanceof SyntaxAssociativity) { - Set tags = mutable(((SyntaxAssociativity) s).tags()); - List tagList = new ArrayList<>(tags); + public void check(Sentence s) { + if (s instanceof SyntaxAssociativity) { + Set tags = mutable(((SyntaxAssociativity) s).tags()); + List tagList = new ArrayList<>(tags); - for(int i = 0; i < tagList.size(); ++i) { - for(int j = i + 1; j < tagList.size(); ++j) { - Tag t1 = tagList.get(i); - Tag t2 = tagList.get(j); + for (int i = 0; i < tagList.size(); ++i) { + for (int j = i + 1; j < tagList.size(); ++j) { + Tag t1 = tagList.get(i); + Tag t2 = tagList.get(j); - if(this.module.priorities().inSomeRelation(t1, t2)) { - String message = "Symbols " + t1 + " and " + t2 + " are in the same associativity group, but have different priorities."; - kem.registerCompilerWarning(KException.ExceptionType.INVALID_ASSOCIATIVITY, errors, message, s); - } - } - } + if (this.module.priorities().inSomeRelation(t1, t2)) { + String message = + "Symbols " + + t1 + + " and " + + t2 + + " are in the same associativity group, but have different priorities."; + kem.registerCompilerWarning( + KException.ExceptionType.INVALID_ASSOCIATIVITY, errors, message, s); + } } + } } + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/CheckTokens.java b/kernel/src/main/java/org/kframework/compile/checks/CheckTokens.java index 17d2546b5cd..f3b597d5a14 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/CheckTokens.java +++ b/kernel/src/main/java/org/kframework/compile/checks/CheckTokens.java @@ -2,42 +2,50 @@ package org.kframework.compile.checks; import com.google.common.collect.ImmutableSet; +import java.util.Set; import org.kframework.attributes.Att; -import org.kframework.attributes.Att.Key; import org.kframework.definition.Module; import org.kframework.definition.Production; import org.kframework.definition.Sentence; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; - public record CheckTokens(Set errors, Module m) { - private static final ImmutableSet ignoredSortNames = ImmutableSet.of("KBott", "KLabel"); - private static final ImmutableSet allowedAtts = ImmutableSet.of(Att.FUNCTION(), Att.TOKEN(), Att.BRACKET()); + private static final ImmutableSet ignoredSortNames = ImmutableSet.of("KBott", "KLabel"); + private static final ImmutableSet allowedAtts = + ImmutableSet.of(Att.FUNCTION(), Att.TOKEN(), Att.BRACKET()); - public void check(Sentence sentence) { - if (sentence instanceof Production p) { - check(p); - } + public void check(Sentence sentence) { + if (sentence instanceof Production p) { + check(p); } + } - // This check ensures that sorts containing token declarations only contain syntax declarations that are also tokens (or macros). - public void check(Production p) { - // ignoredSortNames contains special sorts defined in domains.md or kast.md that are special variables that - // contain subsorts and tokens. The codebase relies on the definitions in these files to be unmodified - // so ignore these names. - if (p.sort().name().startsWith("#") - || allowedAtts.stream().anyMatch(l -> p.att().contains(l)) - || ignoredSortNames.contains(p.sort().name())) { - return; - } - - if (!m.tokenSorts().contains(p.sort()) // We only care about sorts that have been declared as tokens. - || p.klabel().isDefined() && m.macroKLabels().contains(p.klabel().get())) { - return; - } + // This check ensures that sorts containing token declarations only contain syntax declarations + // that are also tokens (or macros). + public void check(Production p) { + // ignoredSortNames contains special sorts defined in domains.md or kast.md that are special + // variables that + // contain subsorts and tokens. The codebase relies on the definitions in these files to be + // unmodified + // so ignore these names. + if (p.sort().name().startsWith("#") + || allowedAtts.stream().anyMatch(l -> p.att().contains(l)) + || ignoredSortNames.contains(p.sort().name())) { + return; + } - errors.add(KEMException.compilerError( - "Sort " + p.sort().name() + " was declared as a token. Productions of this sort can only contain [function] or [token] labels.", p)); + if (!m.tokenSorts() + .contains(p.sort()) // We only care about sorts that have been declared as tokens. + || p.klabel().isDefined() && m.macroKLabels().contains(p.klabel().get())) { + return; } + + errors.add( + KEMException.compilerError( + "Sort " + + p.sort().name() + + " was declared as a token. Productions of this sort can only contain [function]" + + " or [token] labels.", + p)); + } } diff --git a/kernel/src/main/java/org/kframework/compile/checks/ComputeUnboundVariables.java b/kernel/src/main/java/org/kframework/compile/checks/ComputeUnboundVariables.java index 2f9f67d24aa..53db71595c2 100644 --- a/kernel/src/main/java/org/kframework/compile/checks/ComputeUnboundVariables.java +++ b/kernel/src/main/java/org/kframework/compile/checks/ComputeUnboundVariables.java @@ -1,81 +1,84 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile.checks; +import static org.kframework.kore.KORE.*; + +import java.util.Set; +import java.util.function.Consumer; import org.kframework.builtin.KLabels; +import org.kframework.compile.ResolveAnonVar; +import org.kframework.compile.RewriteAwareVisitor; import org.kframework.definition.Production; import org.kframework.kore.InjectedKLabel; -import org.kframework.kore.K; import org.kframework.kore.KApply; import org.kframework.kore.KVariable; -import org.kframework.compile.ResolveAnonVar; -import org.kframework.compile.RewriteAwareVisitor; import org.kframework.kore.Sort; import org.kframework.utils.errorsystem.KEMException; -import java.util.Set; -import java.util.function.Consumer; - -import static org.kframework.kore.KORE.*; - -/** - * Created by dwightguth on 3/6/17. - */ +/** Created by dwightguth on 3/6/17. */ public class ComputeUnboundVariables extends RewriteAwareVisitor { - private final Set vars; - private final Consumer reporter; - private Sort context = null; - private boolean isInKLhs = false; - private final boolean lambda; + private final Set vars; + private final Consumer reporter; + private Sort context = null; + private boolean isInKLhs = false; + private final boolean lambda; - public ComputeUnboundVariables(boolean isBody, boolean lambda, Set errors, Set vars, Consumer reporter) { - super(isBody, errors); - this.lambda = lambda; - this.vars = vars; - this.reporter = reporter; - } + public ComputeUnboundVariables( + boolean isBody, + boolean lambda, + Set errors, + Set vars, + Consumer reporter) { + super(isBody, errors); + this.lambda = lambda; + this.vars = vars; + this.reporter = reporter; + } - @Override - public void apply(KVariable k) { - if (context != null) { - k = KVariable(k.name(), k.att().add(Sort.class, context)); - } - if (isRHS() && !isInKLhs) { - if (!k.name().equals(KLabels.THIS_CONFIGURATION) && - ((k.equals(ResolveAnonVar.ANON_VAR) && !isLHS()) - || (!k.equals(ResolveAnonVar.ANON_VAR) && !(k.name().startsWith("?") || (k.name().startsWith("!") && !lambda)) && !vars.contains(k)))) { - reporter.accept(k); - } - } + @Override + public void apply(KVariable k) { + if (context != null) { + k = KVariable(k.name(), k.att().add(Sort.class, context)); + } + if (isRHS() && !isInKLhs) { + if (!k.name().equals(KLabels.THIS_CONFIGURATION) + && ((k.equals(ResolveAnonVar.ANON_VAR) && !isLHS()) + || (!k.equals(ResolveAnonVar.ANON_VAR) + && !(k.name().startsWith("?") || (k.name().startsWith("!") && !lambda)) + && !vars.contains(k)))) { + reporter.accept(k); + } } + } - @Override - public void apply(InjectedKLabel k) { - if (k.klabel() instanceof KVariable) { - apply((KVariable) k.klabel()); - } - super.apply(k); + @Override + public void apply(InjectedKLabel k) { + if (k.klabel() instanceof KVariable) { + apply((KVariable) k.klabel()); } + super.apply(k); + } - @Override - public void apply(KApply k) { - if (k.klabel().equals(KLabels.IN_K) || k.klabel().equals(KLabels.NOT_IN_K)) { - boolean tmp = isInKLhs; - isInKLhs = true; - apply(k.items().get(0)); - isInKLhs = tmp; - apply(k.items().get(1)); - return; - } - if (k.klabel().name().startsWith("#SemanticCastTo")) { - Sort savedContext = context; - context = k.att().get(Production.class).sort(); - apply(k.items().get(0)); - context = savedContext; - return; - } - if (k.klabel() instanceof KVariable) { - apply((KVariable) k.klabel()); - } - super.apply(k); + @Override + public void apply(KApply k) { + if (k.klabel().equals(KLabels.IN_K) || k.klabel().equals(KLabels.NOT_IN_K)) { + boolean tmp = isInKLhs; + isInKLhs = true; + apply(k.items().get(0)); + isInKLhs = tmp; + apply(k.items().get(1)); + return; + } + if (k.klabel().name().startsWith("#SemanticCastTo")) { + Sort savedContext = context; + context = k.att().get(Production.class).sort(); + apply(k.items().get(0)); + context = savedContext; + return; + } + if (k.klabel() instanceof KVariable) { + apply((KVariable) k.klabel()); } + super.apply(k); + } } diff --git a/kernel/src/main/java/org/kframework/kast/KastFrontEnd.java b/kernel/src/main/java/org/kframework/kast/KastFrontEnd.java index 0b8ed8c45fe..668c9e259dd 100644 --- a/kernel/src/main/java/org/kframework/kast/KastFrontEnd.java +++ b/kernel/src/main/java/org/kframework/kast/KastFrontEnd.java @@ -4,6 +4,16 @@ import com.google.common.collect.Lists; import com.google.inject.Inject; import com.google.inject.Provider; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; import org.kframework.attributes.Att; import org.kframework.attributes.Source; import org.kframework.builtin.BooleanUtils; @@ -36,202 +46,246 @@ import scala.Tuple2; import scala.util.Either; -import java.io.File; -import java.io.IOException; -import java.io.Reader; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - public class KastFrontEnd extends FrontEnd { - public static List getModules() { - List modules = new ArrayList<>(); - modules.add(new KastModule()); - modules.add(new JCommanderModule()); - modules.add(new CommonModule()); - return modules; - } + public static List getModules() { + List modules = new ArrayList<>(); + modules.add(new KastModule()); + modules.add(new JCommanderModule()); + modules.add(new CommonModule()); + return modules; + } - private final KastOptions options; - private final Stopwatch sw; - private final KExceptionManager kem; - private final Provider files; - private final Map env; - private final Provider kompiledDir; - private final Provider compiledDef; - private final Provider kprint; - private final DefinitionScope scope; - - @Inject - KastFrontEnd( - KastOptions options, - @Usage String usage, - Stopwatch sw, - KExceptionManager kem, - JarInfo jarInfo, - @Environment Map env, - Provider files, - @KompiledDir Provider kompiledDir, - Provider compiledDef, - Provider kprint, - DefinitionScope scope) { - super(kem, options.global, usage, jarInfo, files); - this.options = options; - this.sw = sw; - this.kem = kem; - this.files = files; - this.env = env; - this.kompiledDir = kompiledDir; - this.compiledDef = compiledDef; - this.kprint = kprint; - this.scope = scope; - } + private final KastOptions options; + private final Stopwatch sw; + private final KExceptionManager kem; + private final Provider files; + private final Map env; + private final Provider kompiledDir; + private final Provider compiledDef; + private final Provider kprint; + private final DefinitionScope scope; + + @Inject + KastFrontEnd( + KastOptions options, + @Usage String usage, + Stopwatch sw, + KExceptionManager kem, + JarInfo jarInfo, + @Environment Map env, + Provider files, + @KompiledDir Provider kompiledDir, + Provider compiledDef, + Provider kprint, + DefinitionScope scope) { + super(kem, options.global, usage, jarInfo, files); + this.options = options; + this.sw = sw; + this.kem = kem; + this.files = files; + this.env = env; + this.kompiledDir = kompiledDir; + this.compiledDef = compiledDef; + this.kprint = kprint; + this.scope = scope; + } - public enum KompileSteps { - help, concretizeCells, anonVars + public enum KompileSteps { + help, + concretizeCells, + anonVars + } + + /** + * @return true if the application terminated normally; false otherwise + */ + @Override + public int run() { + if (options.steps.contains(KompileSteps.help)) { + System.out.println( + "For --input rule, apply these steps, in this order, separated by comma:\n" + + " concretizeCells - configuration concretization\n" + + " anonVars - rename anonymous variables to be unique\n" + + " , - empty list of steps"); + return 0; } + scope.enter(kompiledDir.get()); + try { + CompiledDefinition def = compiledDef.get(); - /** - * - * @return true if the application terminated normally; false otherwise - */ - @Override - public int run() { - if (options.steps.contains(KompileSteps.help)) { - System.out.println( - "For --input rule, apply these steps, in this order, separated by comma:\n" + - " concretizeCells - configuration concretization\n" + - " anonVars - rename anonymous variables to be unique\n" + - " , - empty list of steps"); - return 0; + org.kframework.kore.Sort sort = options.sort; + String startSymbolLocation = "kast CLI --sort"; + if (sort == null) { + if (env.get("KRUN_SORT") != null) { + sort = Outer.parseSort(env.get("KRUN_SORT")); + startSymbolLocation = "kast env KRUN_SORT"; } - scope.enter(kompiledDir.get()); - try { - CompiledDefinition def = compiledDef.get(); - - org.kframework.kore.Sort sort = options.sort; - String startSymbolLocation = "kast CLI --sort"; - if (sort == null) { - if (env.get("KRUN_SORT") != null) { - sort = Outer.parseSort(env.get("KRUN_SORT")); - startSymbolLocation = "kast env KRUN_SORT"; - } - } + } - if (options.input.equals(InputModes.RULE)) { - options.module = def.executionModule().name(); - if (sort == null) { - sort = Sorts.K(); - startSymbolLocation = "kast default K"; - } - Module mod = def.ruleParsingModuleFor(options.module) - .getOrElse(() -> {throw KEMException.innerParserError("Module " + options.module + " not found. Specify a module with -m.");}); - String stringToParse = FileUtil.read(options.stringToParse()); - Source source = options.source(); - - try (ParseInModule parseInModule = RuleGrammarGenerator.getCombinedGrammar(mod, true, null)) { - if (options.debugTokens) - System.out.println(parseInModule.tokenizeString(stringToParse, source)); - else { - Tuple2, K>, Set> res = parseInModule.parseString(stringToParse, sort, startSymbolLocation, source); - kem.addAllKException(res._2().stream().map(KEMException::getKException).collect(Collectors.toSet())); - if (res._1().isLeft()) { - throw res._1().left().get().iterator().next(); - } - // important to get the extension module for unparsing because it contains generated syntax - // like casts, projections and others - Module unparsingMod = parseInModule.getExtensionModule(); - K parsed = new TreeNodesToKORE(Outer::parseSort, true).down(res._1().right().get()); - - if (options.expandMacros) { - parsed = ExpandMacros.forNonSentences(unparsingMod, files.get(), def.kompileOptions, false).expand(parsed); - } - ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); - LabelInfo labelInfo = new LabelInfoFromModule(mod); - SortInfo sortInfo = SortInfo.fromModule(mod); - - Rule r = Rule.apply(parsed, BooleanUtils.TRUE, BooleanUtils.TRUE, Att.empty()); - if (options.steps.contains(KompileSteps.anonVars)) - r = (Rule) new ResolveAnonVar().resolve(r); - r = (Rule) new ResolveSemanticCasts(false).resolve(r); // move casts to side condition predicates - r = (Rule) new ConstantFolding().fold(unparsingMod, r); - r = (Rule) new CloseCells(configInfo, sortInfo, labelInfo).close(r); - if (options.steps.contains(KompileSteps.concretizeCells)) { - r = (Rule) new AddImplicitComputationCell(configInfo, labelInfo).apply(mod, r); - r = (Rule) new ConcretizeCells(configInfo, labelInfo, sortInfo, mod).concretize(mod, r); - } - K result = r.body(); - kprint.get().prettyPrint(def.kompiledDefinition, unparsingMod, s -> kprint.get().outputFile(s), result, sort); - } - } - - sw.printTotal("Total"); - return 0; - } else if (!options.steps.equals(Lists.newArrayList(KompileSteps.anonVars))) { - throw KEMException.innerParserError("Option --steps is available only with --input rule."); - } + if (options.input.equals(InputModes.RULE)) { + options.module = def.executionModule().name(); + if (sort == null) { + sort = Sorts.K(); + startSymbolLocation = "kast default K"; + } + Module mod = + def.ruleParsingModuleFor(options.module) + .getOrElse( + () -> { + throw KEMException.innerParserError( + "Module " + options.module + " not found. Specify a module with -m."); + }); + String stringToParse = FileUtil.read(options.stringToParse()); + Source source = options.source(); - Module unparsingMod; - if (sort == null) { - sort = def.programStartSymbol; - startSymbolLocation = " program default"; + try (ParseInModule parseInModule = + RuleGrammarGenerator.getCombinedGrammar(mod, true, null)) { + if (options.debugTokens) + System.out.println(parseInModule.tokenizeString(stringToParse, source)); + else { + Tuple2, K>, Set> res = + parseInModule.parseString(stringToParse, sort, startSymbolLocation, source); + kem.addAllKException( + res._2().stream().map(KEMException::getKException).collect(Collectors.toSet())); + if (res._1().isLeft()) { + throw res._1().left().get().iterator().next(); } + // important to get the extension module for unparsing because it contains generated + // syntax + // like casts, projections and others + Module unparsingMod = parseInModule.getExtensionModule(); + K parsed = new TreeNodesToKORE(Outer::parseSort, true).down(res._1().right().get()); - if (options.module == null) { - options.module = def.mainSyntaxModuleName(); - unparsingMod = switch (options.input) { - case KORE -> def.languageParsingModule(); - default -> def.kompiledDefinition.getModule(def.mainSyntaxModuleName()).get(); - }; - } else { - Option maybeUnparsingMod = def.kompiledDefinition.getModule(options.module); - if (maybeUnparsingMod.isEmpty()) { - throw KEMException.innerParserError("Module " + options.module + " not found."); - } - unparsingMod = maybeUnparsingMod.get(); + if (options.expandMacros) { + parsed = + ExpandMacros.forNonSentences(unparsingMod, files.get(), def.kompileOptions, false) + .expand(parsed); } + ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(mod); + LabelInfo labelInfo = new LabelInfoFromModule(mod); + SortInfo sortInfo = SortInfo.fromModule(mod); - Option maybeMod = def.programParsingModuleFor(options.module, kem); - if (maybeMod.isEmpty()) { - throw KEMException.innerParserError("Module " + options.module + " not found. Specify a module with -m."); - } - Module parsingMod = maybeMod.get(); - - KRead kread = new KRead(kem, files.get(), options.input, options.global); - if (options.genParser || options.genGlrParser) { - kread.createBisonParser(parsingMod, sort, options.bisonOutputFile(), options.genGlrParser, options.bisonFile, options.bisonStackMaxDepth, false); - try { - Files.copy(options.bisonOutputFile().toPath(), files.get().resolveKompiled("parser_" + sort.name() + "_" + options.module).toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) {} - } else { - Reader stringToParse = options.stringToParse(); - Source source = options.source(); - if (options.debugTokens) - System.out.println(kread.showTokens(parsingMod, def, FileUtil.read(stringToParse), source)); - else { - K parsed = kread.prettyRead(parsingMod, sort, startSymbolLocation, def, source, FileUtil.read(stringToParse), options.debugParse); - - if (options.expandMacros) { - parsed = ExpandMacros.forNonSentences(unparsingMod, files.get(), def.kompileOptions, false).expand(parsed); - } - - if (sort.equals(Sorts.K())) { - sort = Sorts.KItem(); - } - - kprint.get().prettyPrint(def.kompiledDefinition, unparsingMod, s -> kprint.get().outputFile(s), parsed, sort); - } + Rule r = Rule.apply(parsed, BooleanUtils.TRUE, BooleanUtils.TRUE, Att.empty()); + if (options.steps.contains(KompileSteps.anonVars)) + r = (Rule) new ResolveAnonVar().resolve(r); + r = + (Rule) + new ResolveSemanticCasts(false) + .resolve(r); // move casts to side condition predicates + r = (Rule) new ConstantFolding().fold(unparsingMod, r); + r = (Rule) new CloseCells(configInfo, sortInfo, labelInfo).close(r); + if (options.steps.contains(KompileSteps.concretizeCells)) { + r = (Rule) new AddImplicitComputationCell(configInfo, labelInfo).apply(mod, r); + r = + (Rule) + new ConcretizeCells(configInfo, labelInfo, sortInfo, mod).concretize(mod, r); } + K result = r.body(); + kprint + .get() + .prettyPrint( + def.kompiledDefinition, + unparsingMod, + s -> kprint.get().outputFile(s), + result, + sort); + } + } + + sw.printTotal("Total"); + return 0; + } else if (!options.steps.equals(Lists.newArrayList(KompileSteps.anonVars))) { + throw KEMException.innerParserError("Option --steps is available only with --input rule."); + } - sw.printTotal("Total"); - return 0; - } finally { - scope.exit(); + Module unparsingMod; + if (sort == null) { + sort = def.programStartSymbol; + startSymbolLocation = " program default"; + } + + if (options.module == null) { + options.module = def.mainSyntaxModuleName(); + unparsingMod = + switch (options.input) { + case KORE -> def.languageParsingModule(); + default -> def.kompiledDefinition.getModule(def.mainSyntaxModuleName()).get(); + }; + } else { + Option maybeUnparsingMod = def.kompiledDefinition.getModule(options.module); + if (maybeUnparsingMod.isEmpty()) { + throw KEMException.innerParserError("Module " + options.module + " not found."); + } + unparsingMod = maybeUnparsingMod.get(); + } + + Option maybeMod = def.programParsingModuleFor(options.module, kem); + if (maybeMod.isEmpty()) { + throw KEMException.innerParserError( + "Module " + options.module + " not found. Specify a module with -m."); + } + Module parsingMod = maybeMod.get(); + + KRead kread = new KRead(kem, files.get(), options.input, options.global); + if (options.genParser || options.genGlrParser) { + kread.createBisonParser( + parsingMod, + sort, + options.bisonOutputFile(), + options.genGlrParser, + options.bisonFile, + options.bisonStackMaxDepth, + false); + try { + Files.copy( + options.bisonOutputFile().toPath(), + files.get().resolveKompiled("parser_" + sort.name() + "_" + options.module).toPath(), + StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { } + } else { + Reader stringToParse = options.stringToParse(); + Source source = options.source(); + if (options.debugTokens) + System.out.println( + kread.showTokens(parsingMod, def, FileUtil.read(stringToParse), source)); + else { + K parsed = + kread.prettyRead( + parsingMod, + sort, + startSymbolLocation, + def, + source, + FileUtil.read(stringToParse), + options.debugParse); + + if (options.expandMacros) { + parsed = + ExpandMacros.forNonSentences(unparsingMod, files.get(), def.kompileOptions, false) + .expand(parsed); + } + + if (sort.equals(Sorts.K())) { + sort = Sorts.KItem(); + } + + kprint + .get() + .prettyPrint( + def.kompiledDefinition, + unparsingMod, + s -> kprint.get().outputFile(s), + parsed, + sort); + } + } + + sw.printTotal("Total"); + return 0; + } finally { + scope.exit(); } + } } diff --git a/kernel/src/main/java/org/kframework/kast/KastModule.java b/kernel/src/main/java/org/kframework/kast/KastModule.java index a28605ce26d..4e34309e370 100644 --- a/kernel/src/main/java/org/kframework/kast/KastModule.java +++ b/kernel/src/main/java/org/kframework/kast/KastModule.java @@ -1,6 +1,9 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kast; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.multibindings.Multibinder; import org.kframework.kil.loader.Context; import org.kframework.main.FrontEnd; import org.kframework.main.GlobalOptions; @@ -12,39 +15,37 @@ import org.kframework.utils.inject.RequestScoped; import org.kframework.utils.options.DefinitionLoadingOptions; -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.TypeLiteral; -import com.google.inject.multibindings.Multibinder; - public class KastModule extends AbstractModule { - @Override - public void configure() { - binder().requireAtInjectOnConstructors(); - bind(FrontEnd.class).to(KastFrontEnd.class); - bind(Tool.class).toInstance(Tool.KAST); - - install(new DefinitionLoadingModule()); - - bind(Context.class).annotatedWith(Main.class).to(Context.class); - - Multibinder optionsBinder = Multibinder.newSetBinder(binder(), Object.class, Options.class); - optionsBinder.addBinding().to(KastOptions.class); - } - - @Provides @RequestScoped - GlobalOptions globalOptions(KastOptions options) { - return options.global; - } - - @Provides @RequestScoped - PrintOptions printOptions(KastOptions options) { - return options.print; - } - - @Provides - DefinitionLoadingOptions defLoadingOptions(KastOptions options) { - return options.definitionLoading; - } + @Override + public void configure() { + binder().requireAtInjectOnConstructors(); + bind(FrontEnd.class).to(KastFrontEnd.class); + bind(Tool.class).toInstance(Tool.KAST); + + install(new DefinitionLoadingModule()); + + bind(Context.class).annotatedWith(Main.class).to(Context.class); + + Multibinder optionsBinder = + Multibinder.newSetBinder(binder(), Object.class, Options.class); + optionsBinder.addBinding().to(KastOptions.class); + } + + @Provides + @RequestScoped + GlobalOptions globalOptions(KastOptions options) { + return options.global; + } + + @Provides + @RequestScoped + PrintOptions printOptions(KastOptions options) { + return options.print; + } + + @Provides + DefinitionLoadingOptions defLoadingOptions(KastOptions options) { + return options.definitionLoading; + } } diff --git a/kernel/src/main/java/org/kframework/kast/KastOptions.java b/kernel/src/main/java/org/kframework/kast/KastOptions.java index aa63d6d8078..2ac46ad9274 100644 --- a/kernel/src/main/java/org/kframework/kast/KastOptions.java +++ b/kernel/src/main/java/org/kframework/kast/KastOptions.java @@ -7,11 +7,17 @@ import com.google.common.collect.Lists; import com.google.inject.Inject; import com.google.inject.Provider; +import java.io.BufferedReader; +import java.io.File; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.util.List; import org.kframework.attributes.Source; import org.kframework.kore.Sort; import org.kframework.main.GlobalOptions; -import org.kframework.parser.outer.Outer; import org.kframework.parser.InputModes; +import org.kframework.parser.outer.Outer; import org.kframework.unparser.OutputModes; import org.kframework.unparser.PrintOptions; import org.kframework.utils.errorsystem.KEMException; @@ -20,148 +26,175 @@ import org.kframework.utils.options.BaseEnumConverter; import org.kframework.utils.options.DefinitionLoadingOptions; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.File; -import java.io.Reader; -import java.io.StringReader; -import java.util.Collections; -import java.util.List; - @RequestScoped public final class KastOptions { - @Inject - public KastOptions() {} - - @Parameter(description="") - private List parameters; - - public Reader stringToParse() { - checkFileExprExclusion(); - if (expression != null) { - return new StringReader(expression); - } - checkSingleFile(); - if (parameters.get(0).equals("-")) { - return new BufferedReader(new InputStreamReader(System.in)); - } - return files.get().readFromWorkingDirectory(parameters.get(0)); - } + @Inject + public KastOptions() {} - private void checkFileExprExclusion() { - if (parameters != null && parameters.size() > 0 && expression != null) { - throw KEMException.criticalError("It is an error to provide both a file and an expression to parse."); - } - } + @Parameter(description = "") + private List parameters; - private void checkSingleFile() { - if (parameters != null && parameters.size() > 1) { - throw KEMException.criticalError("You can only parse one program at a time."); - } - if (parameters == null || parameters.size() != 1) { - throw KEMException.criticalError("You have to provide a file in order to kast a program."); - } + public Reader stringToParse() { + checkFileExprExclusion(); + if (expression != null) { + return new StringReader(expression); } - - private Provider files; - - @Inject - public void setFiles(Provider files) { - this.files = files; + checkSingleFile(); + if (parameters.get(0).equals("-")) { + return new BufferedReader(new InputStreamReader(System.in)); } + return files.get().readFromWorkingDirectory(parameters.get(0)); + } - /** - * Get the source of the string to parse. This method is undefined if it is called before calling - * {@link #stringToParse()}. - * @return A textual description of the source of the string to parse. - */ - public Source source() { - if (expression != null) { - return Source.apply(""); - } else { - return Source.apply(files.get().resolveWorkingDirectory(parameters.get(0)).getAbsolutePath()); - } + private void checkFileExprExclusion() { + if (parameters != null && parameters.size() > 0 && expression != null) { + throw KEMException.criticalError( + "It is an error to provide both a file and an expression to parse."); } + } - @ParametersDelegate - public transient GlobalOptions global = new GlobalOptions(); - - @ParametersDelegate - public DefinitionLoadingOptions definitionLoading = new DefinitionLoadingOptions(); - - @ParametersDelegate - public PrintOptions print = new PrintOptions(OutputModes.KAST); - - @Parameter(names={"--gen-parser"}, description="Generate a Bison/Flex parser for the specified module and sort.") - public boolean genParser; - - @Parameter(names={"--gen-glr-parser"}, description="Generate a Bison/Flex GLR parser for the specified module and sort.") - public boolean genGlrParser; - - public File bisonOutputFile() { - checkSingleFile(); - return files.get().resolveWorkingDirectory(parameters.get(0)); + private void checkSingleFile() { + if (parameters != null && parameters.size() > 1) { + throw KEMException.criticalError("You can only parse one program at a time."); } - - @Parameter(names="--bison-file", descriptionKey = "file", hidden = true, - description="C file containing functions to link into bison parser.") - public String bisonFile; - - @Parameter(names="--bison-stack-max-depth", descriptionKey = "size", hidden = true, - description="Maximum size of bison parsing stack.") - public long bisonStackMaxDepth = 10000; - - @Parameter(names={"--expression", "-e"}, descriptionKey = "expression", - description="An expression to parse passed on the command line. It is an error to provide both this " + - "option and a file to parse.") - private String expression; - - @Parameter(names={"--sort", "-s"}, descriptionKey = "sort", converter=SortTypeConverter.class, - description="The start sort for the default parser. The default is the sort of $PGM from the configuration. " + - "A sort may also be specified with the 'KRUN_SORT' environment variable, in which case it is used " + - "if the option is not specified on the command line.") - public Sort sort; - - public static class SortTypeConverter implements IStringConverter { - // converts the command line argument into a Sort - @Override - public Sort convert(String arg) { - return Outer.parseSort(arg); - } + if (parameters == null || parameters.size() != 1) { + throw KEMException.criticalError("You have to provide a file in order to kast a program."); } - - @Parameter(names={"--module", "-m"}, descriptionKey = "name", - description="Parse text in the specified module. Defaults to the syntax module of the definition.") - public String module; - - @Parameter(names="--expand-macros", description="Also expand macros in the parsed string.") - public boolean expandMacros = false; - - @Parameter(names={"--input", "-i"}, descriptionKey = "mode", converter=InputModeConverter.class, - description="How to read kast input in. is either [program|binary|kast|json|kore|rule].") - public InputModes input = InputModes.PROGRAM; - - @Parameter(names={"--steps"}, descriptionKey = "steps", - description="Apply specified kompilation steps to the parsed term. Only for --input rule. " + - "Use --steps help for a detailed description of available steps.") - public List steps = Lists.newArrayList(KastFrontEnd.KompileSteps.anonVars); - - public static class InputModeConverter extends BaseEnumConverter { - - public InputModeConverter(String optionName) { - super(optionName); - } - - @Override - public Class enumClass() { - return InputModes.class; - } + } + + private Provider files; + + @Inject + public void setFiles(Provider files) { + this.files = files; + } + + /** + * Get the source of the string to parse. This method is undefined if it is called before calling + * {@link #stringToParse()}. + * + * @return A textual description of the source of the string to parse. + */ + public Source source() { + if (expression != null) { + return Source.apply(""); + } else { + return Source.apply(files.get().resolveWorkingDirectory(parameters.get(0)).getAbsolutePath()); + } + } + + @ParametersDelegate public transient GlobalOptions global = new GlobalOptions(); + + @ParametersDelegate + public DefinitionLoadingOptions definitionLoading = new DefinitionLoadingOptions(); + + @ParametersDelegate public PrintOptions print = new PrintOptions(OutputModes.KAST); + + @Parameter( + names = {"--gen-parser"}, + description = "Generate a Bison/Flex parser for the specified module and sort.") + public boolean genParser; + + @Parameter( + names = {"--gen-glr-parser"}, + description = "Generate a Bison/Flex GLR parser for the specified module and sort.") + public boolean genGlrParser; + + public File bisonOutputFile() { + checkSingleFile(); + return files.get().resolveWorkingDirectory(parameters.get(0)); + } + + @Parameter( + names = "--bison-file", + descriptionKey = "file", + hidden = true, + description = "C file containing functions to link into bison parser.") + public String bisonFile; + + @Parameter( + names = "--bison-stack-max-depth", + descriptionKey = "size", + hidden = true, + description = "Maximum size of bison parsing stack.") + public long bisonStackMaxDepth = 10000; + + @Parameter( + names = {"--expression", "-e"}, + descriptionKey = "expression", + description = + "An expression to parse passed on the command line. It is an error to provide both this " + + "option and a file to parse.") + private String expression; + + @Parameter( + names = {"--sort", "-s"}, + descriptionKey = "sort", + converter = SortTypeConverter.class, + description = + "The start sort for the default parser. The default is the sort of $PGM from the" + + " configuration. A sort may also be specified with the 'KRUN_SORT' environment" + + " variable, in which case it is used if the option is not specified on the command" + + " line.") + public Sort sort; + + public static class SortTypeConverter implements IStringConverter { + // converts the command line argument into a Sort + @Override + public Sort convert(String arg) { + return Outer.parseSort(arg); + } + } + + @Parameter( + names = {"--module", "-m"}, + descriptionKey = "name", + description = + "Parse text in the specified module. Defaults to the syntax module of the definition.") + public String module; + + @Parameter(names = "--expand-macros", description = "Also expand macros in the parsed string.") + public boolean expandMacros = false; + + @Parameter( + names = {"--input", "-i"}, + descriptionKey = "mode", + converter = InputModeConverter.class, + description = + "How to read kast input in. is either [program|binary|kast|json|kore|rule].") + public InputModes input = InputModes.PROGRAM; + + @Parameter( + names = {"--steps"}, + descriptionKey = "steps", + description = + "Apply specified kompilation steps to the parsed term. Only for --input rule. " + + "Use --steps help for a detailed description of available steps.") + public List steps = + Lists.newArrayList(KastFrontEnd.KompileSteps.anonVars); + + public static class InputModeConverter extends BaseEnumConverter { + + public InputModeConverter(String optionName) { + super(optionName); } - @Parameter(names="--debug-tokens", description="Print a Markdown table of tokens matched by the scanner. Useful for debugging parsing errors.") - public boolean debugTokens = false; - - @Parameter(names="--debug-parse", description="Print extended diagnostic information and partial ASTs for parse errors.") - public boolean debugParse = false; + @Override + public Class enumClass() { + return InputModes.class; + } + } + + @Parameter( + names = "--debug-tokens", + description = + "Print a Markdown table of tokens matched by the scanner. Useful for debugging parsing" + + " errors.") + public boolean debugTokens = false; + + @Parameter( + names = "--debug-parse", + description = "Print extended diagnostic information and partial ASTs for parse errors.") + public boolean debugParse = false; } diff --git a/kernel/src/main/java/org/kframework/kdep/KDepFrontEnd.java b/kernel/src/main/java/org/kframework/kdep/KDepFrontEnd.java index 8a7c15c3220..212422636d1 100644 --- a/kernel/src/main/java/org/kframework/kdep/KDepFrontEnd.java +++ b/kernel/src/main/java/org/kframework/kdep/KDepFrontEnd.java @@ -1,10 +1,17 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kdep; -import com.google.inject.Provider; import com.google.common.collect.Lists; import com.google.inject.Inject; import com.google.inject.Module; +import com.google.inject.Provider; +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.collections4.ListUtils; import org.kframework.attributes.Source; import org.kframework.kompile.Kompile; @@ -20,23 +27,17 @@ import org.kframework.utils.inject.JCommanderModule.Usage; import org.kframework.utils.options.OuterParsingOptions; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - /** * Frontend for kdep tool. + * + *

kdep is designed to generate a Makefile that contains the dependencies that kompile has on + * files when you run it. This can be used in order to ensure that if any of the files required by a + * k definition are changed, the makefile will rerun kompile. + * + *

Example Makefile snippet: + * *

- * kdep is designed to generate a Makefile that contains the dependencies - * that kompile has on files when you run it. This can be used in order to ensure that if any - * of the files required by a k definition are changed, the makefile will rerun kompile. - *

- * Example Makefile snippet: - *

+ * *

  *     .depend:
  *             kdep definition.k --output-directory "kompiled directory" -I includes > .depend
@@ -46,89 +47,106 @@
  */
 public class KDepFrontEnd extends FrontEnd {
 
-    private final KDepOptions kdepOptions;
-    private final OuterParsingOptions options;
-    private final KExceptionManager kem;
-    private final Stopwatch sw;
-    private final Provider files;
-    private final GlobalOptions globalOptions;
+  private final KDepOptions kdepOptions;
+  private final OuterParsingOptions options;
+  private final KExceptionManager kem;
+  private final Stopwatch sw;
+  private final Provider files;
+  private final GlobalOptions globalOptions;
 
-    @Inject
-    public KDepFrontEnd(
-            KDepOptions kdepOptions,
-            OuterParsingOptions options,
-            KExceptionManager kem,
-            GlobalOptions globalOptions,
-            @Usage String usage,
-            Stopwatch sw,
-            JarInfo jarInfo,
-            Provider files) {
-        super(kem, globalOptions, usage, jarInfo, files);
-        this.kdepOptions = kdepOptions;
-        this.options = options;
-        this.globalOptions = globalOptions;
-        this.kem = kem;
-        this.sw = sw;
-        this.files = files;
-    }
+  @Inject
+  public KDepFrontEnd(
+      KDepOptions kdepOptions,
+      OuterParsingOptions options,
+      KExceptionManager kem,
+      GlobalOptions globalOptions,
+      @Usage String usage,
+      Stopwatch sw,
+      JarInfo jarInfo,
+      Provider files) {
+    super(kem, globalOptions, usage, jarInfo, files);
+    this.kdepOptions = kdepOptions;
+    this.options = options;
+    this.globalOptions = globalOptions;
+    this.kem = kem;
+    this.sw = sw;
+    this.files = files;
+  }
 
-    public static List getModules() {
-        List modules = new ArrayList<>();
-        modules.add(new KDepModule());
-        modules.add(new JCommanderModule());
-        modules.add(new CommonModule());
-        return modules;
-    }
+  public static List getModules() {
+    List modules = new ArrayList<>();
+    modules.add(new KDepModule());
+    modules.add(new JCommanderModule());
+    modules.add(new CommonModule());
+    return modules;
+  }
 
-    @Override
-    protected int run() {
-        ParserUtils parser = new ParserUtils(files.get(), kem, globalOptions, options);
-        List modules = new ArrayList<>();
-        Source source = Source.apply(options.mainDefinitionFile(files.get()).getAbsolutePath());
-        File currentDirectory = options.mainDefinitionFile(files.get()).getParentFile();
-        List lookupDirectories = ListUtils.union(options.includes.stream()
-                        .map(files.get()::resolveWorkingDirectory).collect(Collectors.toList()),
-                Lists.newArrayList(Kompile.BUILTIN_DIRECTORY));
+  @Override
+  protected int run() {
+    ParserUtils parser = new ParserUtils(files.get(), kem, globalOptions, options);
+    List modules = new ArrayList<>();
+    Source source = Source.apply(options.mainDefinitionFile(files.get()).getAbsolutePath());
+    File currentDirectory = options.mainDefinitionFile(files.get()).getParentFile();
+    List lookupDirectories =
+        ListUtils.union(
+            options.includes.stream()
+                .map(files.get()::resolveWorkingDirectory)
+                .collect(Collectors.toList()),
+            Lists.newArrayList(Kompile.BUILTIN_DIRECTORY));
 
-        Set requiredFiles = new HashSet<>();
-        // load builtin files if needed first
-        if (!options.noPrelude) {
-            modules.addAll(parser.slurp(Kompile.REQUIRE_PRELUDE_K,
-                    source,
-                    currentDirectory,
-                    lookupDirectories,
-                    requiredFiles));
-        }
+    Set requiredFiles = new HashSet<>();
+    // load builtin files if needed first
+    if (!options.noPrelude) {
+      modules.addAll(
+          parser.slurp(
+              Kompile.REQUIRE_PRELUDE_K,
+              source,
+              currentDirectory,
+              lookupDirectories,
+              requiredFiles));
+    }
 
-        modules.addAll(parser.slurp(FileUtil.load(options.mainDefinitionFile(files.get())),
-                source,
-                currentDirectory,
-                lookupDirectories,
-                requiredFiles));
-        Set allFiles = modules.stream().map(m -> new File(m.getSource().source())).collect(Collectors.toSet());
-        System.out.println(files.get().resolveWorkingDirectory(".").toURI().relativize(files.get().resolveKompiled("timestamp").toURI()).getPath() + " : \\");
+    modules.addAll(
+        parser.slurp(
+            FileUtil.load(options.mainDefinitionFile(files.get())),
+            source,
+            currentDirectory,
+            lookupDirectories,
+            requiredFiles));
+    Set allFiles =
+        modules.stream().map(m -> new File(m.getSource().source())).collect(Collectors.toSet());
+    System.out.println(
+        files
+                .get()
+                .resolveWorkingDirectory(".")
+                .toURI()
+                .relativize(files.get().resolveKompiled("timestamp").toURI())
+                .getPath()
+            + " : \\");
 
-        List sortedFiles = new ArrayList(allFiles);
-        Collections.sort(sortedFiles, (File a, File b) -> {
+    List sortedFiles = new ArrayList(allFiles);
+    Collections.sort(
+        sortedFiles,
+        (File a, File b) -> {
           return a.getAbsolutePath().compareTo(b.getAbsolutePath());
         });
 
-        for (File file : sortedFiles) {
-            System.out.println("    " + file.getAbsolutePath() + " \\");
-        }
-        System.out.println();
+    for (File file : sortedFiles) {
+      System.out.println("    " + file.getAbsolutePath() + " \\");
+    }
+    System.out.println();
 
-        if (this.kdepOptions.alsoRemakeDepend) {
-            System.out.println("DEPEND_FILE=$(lastword $(MAKEFILE_LIST))");
-            System.out.println("$(DEPEND_FILE) : " + " \\");
-            System.out.println("    $(wildcard \\");
+    if (this.kdepOptions.alsoRemakeDepend) {
+      System.out.println("DEPEND_FILE=$(lastword $(MAKEFILE_LIST))");
+      System.out.println("$(DEPEND_FILE) : " + " \\");
+      System.out.println("    $(wildcard \\");
 
-            for (File file : sortedFiles) {
-                System.out.println("        " + file.getAbsolutePath() + " \\");
-            }
+      for (File file : sortedFiles) {
+        System.out.println("        " + file.getAbsolutePath() + " \\");
+      }
 
-            System.out.println("    )");
-        }
-        return 0;
+      System.out.println("    )");
     }
+    return 0;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kdep/KDepModule.java b/kernel/src/main/java/org/kframework/kdep/KDepModule.java
index ed6af4762b9..516e989a87a 100644
--- a/kernel/src/main/java/org/kframework/kdep/KDepModule.java
+++ b/kernel/src/main/java/org/kframework/kdep/KDepModule.java
@@ -3,9 +3,7 @@
 
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
-import com.google.inject.TypeLiteral;
 import com.google.inject.multibindings.Multibinder;
-import org.kframework.kompile.KompileOptions;
 import org.kframework.main.FrontEnd;
 import org.kframework.main.GlobalOptions;
 import org.kframework.main.Tool;
@@ -16,30 +14,36 @@
 import org.kframework.utils.options.OutputDirectoryOptions;
 
 /**
- * Guice module for kdep tool. Binds the information needed to compute the kompiled directory as well as the options
- * and frontend.
+ * Guice module for kdep tool. Binds the information needed to compute the kompiled directory as
+ * well as the options and frontend.
  */
 public class KDepModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        binder().requireAtInjectOnConstructors();
-        bind(FrontEnd.class).to(KDepFrontEnd.class);
-        bind(Tool.class).toInstance(Tool.KDEP);
+  @Override
+  protected void configure() {
+    binder().requireAtInjectOnConstructors();
+    bind(FrontEnd.class).to(KDepFrontEnd.class);
+    bind(Tool.class).toInstance(Tool.KDEP);
 
-        install(new OuterParsingModule());
+    install(new OuterParsingModule());
 
-        Multibinder optionsBinder = Multibinder.newSetBinder(binder(), Object.class, Options.class);
-        optionsBinder.addBinding().to(KDepOptions.class);
-    }
+    Multibinder optionsBinder =
+        Multibinder.newSetBinder(binder(), Object.class, Options.class);
+    optionsBinder.addBinding().to(KDepOptions.class);
+  }
 
-    @Provides @RequestScoped
-    GlobalOptions globalOptions(KDepOptions options) {
-        return options.global;
-    }
+  @Provides
+  @RequestScoped
+  GlobalOptions globalOptions(KDepOptions options) {
+    return options.global;
+  }
 
-    @Provides
-    OuterParsingOptions outerParsingOptions(KDepOptions options) { return options.outerParsing; }
+  @Provides
+  OuterParsingOptions outerParsingOptions(KDepOptions options) {
+    return options.outerParsing;
+  }
 
-    @Provides
-    OutputDirectoryOptions outputDirectoryOptions(KDepOptions options) { return options.outputDirectory; }
+  @Provides
+  OutputDirectoryOptions outputDirectoryOptions(KDepOptions options) {
+    return options.outputDirectory;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kdep/KDepOptions.java b/kernel/src/main/java/org/kframework/kdep/KDepOptions.java
index c65cc98273e..b0129fefc5c 100644
--- a/kernel/src/main/java/org/kframework/kdep/KDepOptions.java
+++ b/kernel/src/main/java/org/kframework/kdep/KDepOptions.java
@@ -10,25 +10,23 @@
 import org.kframework.utils.options.OutputDirectoryOptions;
 
 /**
- * JCommander options for kdep. Essentially, this should contain all the kompile options needed in order to decide what
- * files get slurped by the outer parser.
+ * JCommander options for kdep. Essentially, this should contain all the kompile options needed in
+ * order to decide what files get slurped by the outer parser.
  */
-
 @RequestScoped
 public class KDepOptions {
 
-    @Inject
-    public KDepOptions() {}
+  @Inject
+  public KDepOptions() {}
 
-    @ParametersDelegate
-    public transient GlobalOptions global = new GlobalOptions();
+  @ParametersDelegate public transient GlobalOptions global = new GlobalOptions();
 
-    @ParametersDelegate
-    public OuterParsingOptions outerParsing = new OuterParsingOptions();
+  @ParametersDelegate public OuterParsingOptions outerParsing = new OuterParsingOptions();
 
-    @ParametersDelegate
-    public OutputDirectoryOptions outputDirectory = new OutputDirectoryOptions();
+  @ParametersDelegate public OutputDirectoryOptions outputDirectory = new OutputDirectoryOptions();
 
-    @Parameter(names="--remake-depend", description="Generate an additional rule to remake the dependency file.")
-    public boolean alsoRemakeDepend = false;
+  @Parameter(
+      names = "--remake-depend",
+      description = "Generate an additional rule to remake the dependency file.")
+  public boolean alsoRemakeDepend = false;
 }
diff --git a/kernel/src/main/java/org/kframework/kil/ASTNode.java b/kernel/src/main/java/org/kframework/kil/ASTNode.java
index 5df3e9498ae..228f815809a 100644
--- a/kernel/src/main/java/org/kframework/kil/ASTNode.java
+++ b/kernel/src/main/java/org/kframework/kil/ASTNode.java
@@ -1,165 +1,165 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
+import java.io.Serializable;
+import java.util.Optional;
 import org.kframework.attributes.Att;
 import org.kframework.attributes.HasLocation;
 import org.kframework.attributes.Location;
 import org.kframework.attributes.Source;
 import org.kframework.utils.errorsystem.KEMException;
 
-import java.io.Serializable;
-import java.util.Optional;
-
-/**
- * Base class for K AST. Useful for Visitors and Transformers.
- */
+/** Base class for K AST. Useful for Visitors and Transformers. */
 public abstract class ASTNode implements Serializable, HasLocation {
-    /**
-     *
-     */
-    private static final long serialVersionUID = 1L;
-    /**
-     * Used on any node for metadata also used on {@link Rule} and {@link Production} for the attribute list.
-     */
-    private Att att = Att.empty();
-
-    private Source source;
-    private Location location;
-
-    /**
-     * Default constructor (generated at runtime)
-     */
-    public ASTNode() {
-        this(null, null);
-    }
-
-    /**
-     * Constructor with specified location and filename.
-     *
-     * @param loc
-     * @param file
-     */
-    public ASTNode(Location loc, Source source) {
-        setLocation(loc);
-        setSource(source);
-    }
-
-    /**
-     * Retrieves the location of the current ASTNode.
-     *
-     * @return recorded location or null if no recorded location found.
-     */
-    public Location getLocation() {
-        return location;
-    }
-
-    /**
-     * Sets the location or removes it if appropriate.
-     *
-     * @param loc
-     */
-    public void setLocation(Location location) {
-        this.location = location;
-    }
-
-    /**
-     * Retrieves the source of the current ASTNode.
-     *
-     * @return recorded source or null if no recorded source found.
-     */
-    public Source getSource() {
-        return source;
-    }
-
-    /**
-     * Sets the source or removes it if appropriate.
-     *
-     * @param file
-     */
-    public void setSource(Source source) {
-        this.source = source;
+  /** */
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * Used on any node for metadata also used on {@link Rule} and {@link Production} for the
+   * attribute list.
+   */
+  private Att att = Att.empty();
+
+  private Source source;
+  private Location location;
+
+  /** Default constructor (generated at runtime) */
+  public ASTNode() {
+    this(null, null);
+  }
+
+  /**
+   * Constructor with specified location and filename.
+   *
+   * @param loc
+   * @param file
+   */
+  public ASTNode(Location loc, Source source) {
+    setLocation(loc);
+    setSource(source);
+  }
+
+  /**
+   * Retrieves the location of the current ASTNode.
+   *
+   * @return recorded location or null if no recorded location found.
+   */
+  public Location getLocation() {
+    return location;
+  }
+
+  /**
+   * Sets the location or removes it if appropriate.
+   *
+   * @param loc
+   */
+  public void setLocation(Location location) {
+    this.location = location;
+  }
+
+  /**
+   * Retrieves the source of the current ASTNode.
+   *
+   * @return recorded source or null if no recorded source found.
+   */
+  public Source getSource() {
+    return source;
+  }
+
+  /**
+   * Sets the source or removes it if appropriate.
+   *
+   * @param file
+   */
+  public void setSource(Source source) {
+    this.source = source;
+  }
+
+  public Optional location() {
+    return Optional.ofNullable(location);
+  }
+
+  public Optional source() {
+    return Optional.ofNullable(source);
+  }
+
+  /*
+   * methods for easy attributes manipulation
+   */
+
+  /**
+   * Append an attribute to the list of attributes. In particular, - inserting a key from the
+   * attribute whitelist if the attribute is recognized as a built-in - add the source location to
+   * any exceptions (ie. parameter restrictions) thrown when inserting the key - otherwise,
+   * inserting an unrecognized key to be errored on later
+   *
+   * @param key
+   * @param val
+   */
+  public void addBuiltInOrUnrecognizedAttribute(
+      String key, String val, Source source, Location loc) {
+    Att.Key attKey = Att.getBuiltinKeyOptional(key).orElse(Att.unrecognizedKey(key));
+    if (att.contains(attKey)) {
+      throw KEMException.outerParserError("Duplicate attribute: " + key, source, loc);
     }
-
-    public Optional location() { return Optional.ofNullable(location); }
-    public Optional source() { return Optional.ofNullable(source); }
-
-    /*
-     * methods for easy attributes manipulation
-     */
-
-    /**
-     * Append an attribute to the list of attributes. In particular,
-     * - inserting a key from the attribute whitelist if the attribute is recognized as a built-in
-     * - add the source location to any exceptions (ie. parameter restrictions) thrown when inserting the key
-     * - otherwise, inserting an unrecognized key to be errored on later
-     *
-     * @param key
-     * @param val
-     */
-    public void addBuiltInOrUnrecognizedAttribute(String key, String val, Source source, Location loc) {
-        Att.Key attKey = Att.getBuiltinKeyOptional(key).orElse(Att.unrecognizedKey(key));
-        if (att.contains(attKey)) {
-            throw KEMException.outerParserError("Duplicate attribute: " + key, source, loc);
-        }
-        try {
-            att = att.add(attKey, val);
-        } catch (KEMException e) {
-            throw e.withLocation(loc, source);
-        }
-    }
-
-    /**
-     * Appends an attribute to the list of attributes.
-     *
-     * @param key
-     * @param val
-     */
-    public void addAttribute(Att.Key key, String val) {
-        att = att.add(key, val);
-    }
-
-    /**
-     * @param key
-     * @return whether the attribute key occurs in the list of attributes.
-     */
-    public boolean containsAttribute(Att.Key key) {
-        return att.contains(key);
-    }
-
-
-    /**
-     * Retrieves the attribute by key from the list of attributes
-     *
-     * @param key
-     * @return a value for key in the list of attributes or the default value.
-     */
-    public String getAttribute(Att.Key key) {
-        return att.getOptional(key).orElse(null);
-    }
-
-    /**
-     * @return the attributes object associated to this ASTNode. Constructs one if it is
-     * not already created.
-     */
-    public Att getAttributes() {
-        return att;
-    }
-
-    /**
-     * Sets the attributes to the provided Att
-     *
-     * @param att - the new attributes
-     */
-    public void setAttributes(Att att) {
-        this.att = att;
-    }
-
-    public abstract void toString(StringBuilder sb);
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        toString(sb);
-        return sb.toString();
+    try {
+      att = att.add(attKey, val);
+    } catch (KEMException e) {
+      throw e.withLocation(loc, source);
     }
+  }
+
+  /**
+   * Appends an attribute to the list of attributes.
+   *
+   * @param key
+   * @param val
+   */
+  public void addAttribute(Att.Key key, String val) {
+    att = att.add(key, val);
+  }
+
+  /**
+   * @param key
+   * @return whether the attribute key occurs in the list of attributes.
+   */
+  public boolean containsAttribute(Att.Key key) {
+    return att.contains(key);
+  }
+
+  /**
+   * Retrieves the attribute by key from the list of attributes
+   *
+   * @param key
+   * @return a value for key in the list of attributes or the default value.
+   */
+  public String getAttribute(Att.Key key) {
+    return att.getOptional(key).orElse(null);
+  }
+
+  /**
+   * @return the attributes object associated to this ASTNode. Constructs one if it is not already
+   *     created.
+   */
+  public Att getAttributes() {
+    return att;
+  }
+
+  /**
+   * Sets the attributes to the provided Att
+   *
+   * @param att - the new attributes
+   */
+  public void setAttributes(Att att) {
+    this.att = att;
+  }
+
+  public abstract void toString(StringBuilder sb);
+
+  @Override
+  public String toString() {
+    StringBuilder sb = new StringBuilder();
+    toString(sb);
+    return sb.toString();
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Definition.java b/kernel/src/main/java/org/kframework/kil/Definition.java
index 4157a5f8959..9fc3b977c3d 100644
--- a/kernel/src/main/java/org/kframework/kil/Definition.java
+++ b/kernel/src/main/java/org/kframework/kil/Definition.java
@@ -2,62 +2,59 @@
 package org.kframework.kil;
 
 import com.google.inject.Inject;
-
 import java.io.File;
-import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-
 /**
- * Represents a language definition.
- * Includes contents from all {@code required}-d files.
+ * Represents a language definition. Includes contents from all {@code required}-d files.
+ *
  * @see DefinitionLoader
  */
 public class Definition extends ASTNode {
 
-    private List items;
-    private File mainFile;
-    private String mainModule;
-    /** An index of all modules in {@link #items} by name */
-    private String mainSyntaxModule;
-    public Map locations = new HashMap<>();
+  private List items;
+  private File mainFile;
+  private String mainModule;
 
-    public Definition() {
-        super();
-    }
+  /** An index of all modules in {@link #items} by name */
+  private String mainSyntaxModule;
 
-    @Inject
-    public Definition(Void v) {}
+  public Map locations = new HashMap<>();
 
-    @Override
-    public void toString(StringBuilder sb) {
-        for (DefinitionItem di : items) {
-            di.toString(sb);
-            sb.append("\n\n");
-        }
-    }
+  public Definition() {
+    super();
+  }
 
-    public void setItems(List items) {
-        this.items = items;
-    }
+  @Inject
+  public Definition(Void v) {}
 
-    public List getItems() {
-        return items;
+  @Override
+  public void toString(StringBuilder sb) {
+    for (DefinitionItem di : items) {
+      di.toString(sb);
+      sb.append("\n\n");
     }
+  }
 
-    public void setMainModule(String mainModule) {
-        this.mainModule = mainModule;
-    }
+  public void setItems(List items) {
+    this.items = items;
+  }
 
-    public String getMainModule() {
-        return mainModule;
-    }
+  public List getItems() {
+    return items;
+  }
 
-    public void setMainSyntaxModule(String mainSyntaxModule) {
-        this.mainSyntaxModule = mainSyntaxModule;
-    }
+  public void setMainModule(String mainModule) {
+    this.mainModule = mainModule;
+  }
+
+  public String getMainModule() {
+    return mainModule;
+  }
 
+  public void setMainSyntaxModule(String mainSyntaxModule) {
+    this.mainSyntaxModule = mainSyntaxModule;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/DefinitionItem.java b/kernel/src/main/java/org/kframework/kil/DefinitionItem.java
index 176f86298ae..ecfa04ddc02 100644
--- a/kernel/src/main/java/org/kframework/kil/DefinitionItem.java
+++ b/kernel/src/main/java/org/kframework/kil/DefinitionItem.java
@@ -3,18 +3,18 @@
 
 public abstract class DefinitionItem extends ASTNode {
 
-    /** set iff the item was read from a file in the standard libraries */
-    private boolean predefined;
+  /** set iff the item was read from a file in the standard libraries */
+  private boolean predefined;
 
-    public DefinitionItem() {
-        super();
-    }
+  public DefinitionItem() {
+    super();
+  }
 
-    public void setPredefined(boolean predefined) {
-        this.predefined = predefined;
-    }
+  public void setPredefined(boolean predefined) {
+    this.predefined = predefined;
+  }
 
-    public boolean isPredefined() {
-        return predefined;
-    }
+  public boolean isPredefined() {
+    return predefined;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Import.java b/kernel/src/main/java/org/kframework/kil/Import.java
index 09756eb5c3e..83950d1a609 100644
--- a/kernel/src/main/java/org/kframework/kil/Import.java
+++ b/kernel/src/main/java/org/kframework/kil/Import.java
@@ -7,45 +7,45 @@
 /** An import directive */
 public class Import extends ModuleItem {
 
-    String name;
-    boolean isPublic;
-
-    public Import(String importName, boolean isPublic) {
-        super();
-        name = importName;
-        this.isPublic = isPublic;
+  String name;
+  boolean isPublic;
+
+  public Import(String importName, boolean isPublic) {
+    super();
+    name = importName;
+    this.isPublic = isPublic;
+  }
+
+  public Import(String importName, boolean isPublic, Location loc, Source source) {
+    super(loc, source);
+    this.name = importName;
+    this.isPublic = isPublic;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("  imports ");
+    if (!isPublic) {
+      sb.append("private ");
+    } else {
+      sb.append("public ");
     }
+    sb.append(name);
+  }
 
-    public Import(String importName, boolean isPublic, Location loc, Source source) {
-        super(loc, source);
-        this.name = importName;
-        this.isPublic = isPublic;
-    }
+  public String getName() {
+    return name;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("  imports ");
-        if (!isPublic) {
-          sb.append("private ");
-        } else {
-          sb.append("public ");
-        }
-        sb.append(name);
-    }
+  public void setName(String name) {
+    this.name = name;
+  }
 
-    public String getName() {
-        return name;
-    }
+  public boolean isPublic() {
+    return isPublic;
+  }
 
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public boolean isPublic() {
-      return isPublic;
-    }
-
-    public void setPublic(boolean isPublic) {
-      this.isPublic = isPublic;
-    }
+  public void setPublic(boolean isPublic) {
+    this.isPublic = isPublic;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Lexical.java b/kernel/src/main/java/org/kframework/kil/Lexical.java
index 7c65e35be40..09bc6d485b9 100644
--- a/kernel/src/main/java/org/kframework/kil/Lexical.java
+++ b/kernel/src/main/java/org/kframework/kil/Lexical.java
@@ -6,48 +6,44 @@
 /** A terminal in a {@link Production}. */
 public class Lexical extends ProductionItem {
 
-    private final String lexicalRule;
-    private String follow;
-
-    public Lexical(String terminal, String follow) {
-        super();
-        this.lexicalRule = terminal;
-        this.follow = follow;
-    }
-
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("r");
-        sb.append(StringUtil.enquoteKString(lexicalRule));
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (obj == this)
-            return true;
-        if (!(obj instanceof Lexical trm))
-            return false;
-
-        return trm.lexicalRule.equals(this.lexicalRule);
-    }
-
-    @Override
-    public int hashCode() {
-        return this.lexicalRule.hashCode();
-    }
-
-    public void setFollow(String follow) {
-        this.follow = follow;
-    }
-
-    public String getFollow() {
-        return follow;
-    }
-
-    public String getLexicalRule() {
-        return lexicalRule;
-    }
-
+  private final String lexicalRule;
+  private String follow;
+
+  public Lexical(String terminal, String follow) {
+    super();
+    this.lexicalRule = terminal;
+    this.follow = follow;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("r");
+    sb.append(StringUtil.enquoteKString(lexicalRule));
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (obj == this) return true;
+    if (!(obj instanceof Lexical trm)) return false;
+
+    return trm.lexicalRule.equals(this.lexicalRule);
+  }
+
+  @Override
+  public int hashCode() {
+    return this.lexicalRule.hashCode();
+  }
+
+  public void setFollow(String follow) {
+    this.follow = follow;
+  }
+
+  public String getFollow() {
+    return follow;
+  }
+
+  public String getLexicalRule() {
+    return lexicalRule;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Module.java b/kernel/src/main/java/org/kframework/kil/Module.java
index 7d4ed6f10ae..f618c940950 100644
--- a/kernel/src/main/java/org/kframework/kil/Module.java
+++ b/kernel/src/main/java/org/kframework/kil/Module.java
@@ -1,79 +1,81 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
-import org.kframework.kore.Sort;
-
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
+import org.kframework.kore.Sort;
 
 /** A module. */
 public class Module extends DefinitionItem {
-    private String name;
-    private List items = new ArrayList<>();
+  private String name;
+  private List items = new ArrayList<>();
 
-    // lazily computed set of sorts.
-    private Set sorts;
+  // lazily computed set of sorts.
+  private Set sorts;
 
-    public Module() {
-        super();
-    }
+  public Module() {
+    super();
+  }
 
-    public Module(String name) {
-        super();
-        this.name = name;
-    }
+  public Module(String name) {
+    super();
+    this.name = name;
+  }
 
-    public void appendModuleItem(ModuleItem item) {
-        this.items.add(item);
-        this.sorts = null;
-    }
+  public void appendModuleItem(ModuleItem item) {
+    this.items.add(item);
+    this.sorts = null;
+  }
 
-    public void setName(String name) {
-        this.name = name;
-    }
+  public void setName(String name) {
+    this.name = name;
+  }
 
-    public String getName() {
-        return name;
-    }
+  public String getName() {
+    return name;
+  }
 
-    public void setItems(List items) {
-        this.items = items;
-        this.sorts = null;
-    }
+  public void setItems(List items) {
+    this.items = items;
+    this.sorts = null;
+  }
 
-    public List getItems() {
-        return items;
-    }
+  public List getItems() {
+    return items;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("module ").append(name).append(" ").append(getAttributes().withUserGroupsAsGroupAtt()).append("\n");
-        for (ModuleItem i : items) {
-            i.toString(sb);
-            sb.append("\n");
-        }
-        sb.append("endmodule");
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("module ")
+        .append(name)
+        .append(" ")
+        .append(getAttributes().withUserGroupsAsGroupAtt())
+        .append("\n");
+    for (ModuleItem i : items) {
+      i.toString(sb);
+      sb.append("\n");
     }
+    sb.append("endmodule");
+  }
 
-    /**
-     * Used to determine if a module was modified.
-     *  GH #2910
-     * This allows for scripts to move files around after compilation but still give error messages
-     * if the contents of modules differ.
-     */
-    public String digest() {
-        try {
-            StringBuilder mod = new StringBuilder();
-            toString(mod);
-            MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
-            messageDigest.update(mod.toString().getBytes());
-            return new String(messageDigest.digest());
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(e);
-        }
+  /**
+   * Used to determine if a module was modified. GH #2910 This allows for
+   * scripts to move files around after compilation but still give error messages if the contents of
+   * modules differ.
+   */
+  public String digest() {
+    try {
+      StringBuilder mod = new StringBuilder();
+      toString(mod);
+      MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
+      messageDigest.update(mod.toString().getBytes());
+      return new String(messageDigest.digest());
+    } catch (NoSuchAlgorithmException e) {
+      throw new RuntimeException(e);
     }
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/ModuleItem.java b/kernel/src/main/java/org/kframework/kil/ModuleItem.java
index cb58956c620..6a5ef1373a2 100644
--- a/kernel/src/main/java/org/kframework/kil/ModuleItem.java
+++ b/kernel/src/main/java/org/kframework/kil/ModuleItem.java
@@ -4,23 +4,20 @@
 import org.kframework.attributes.Location;
 import org.kframework.attributes.Source;
 
-import org.w3c.dom.Element;
-
 public abstract class ModuleItem extends ASTNode {
-    public ModuleItem() {
-        super();
-    }
-
-    public ModuleItem(Location loc, Source source) {
-        super(loc, source);
-    }
+  public ModuleItem() {
+    super();
+  }
 
-    public java.util.List getLabels() {
-        return null;
-    }
+  public ModuleItem(Location loc, Source source) {
+    super(loc, source);
+  }
 
-    public java.util.List getKLabels() {
-        return null;
-    }
+  public java.util.List getLabels() {
+    return null;
+  }
 
+  public java.util.List getKLabels() {
+    return null;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/NonTerminal.java b/kernel/src/main/java/org/kframework/kil/NonTerminal.java
index 64c58213481..e78447f5078 100644
--- a/kernel/src/main/java/org/kframework/kil/NonTerminal.java
+++ b/kernel/src/main/java/org/kframework/kil/NonTerminal.java
@@ -1,66 +1,60 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
+import java.util.Optional;
 import org.kframework.kore.Sort;
-
 import scala.Option;
 
-import java.util.Optional;
-
 /** A nonterminal in a {@link Production}. Also abused in some places as a sort identifier */
 public class NonTerminal extends ProductionItem {
 
-    private Sort sort;
-    private final Optional name;
+  private Sort sort;
+  private final Optional name;
 
-    public NonTerminal(Sort sort, Optional name) {
-        super();
-        this.sort = sort;
-        this.name = name;
-    }
+  public NonTerminal(Sort sort, Optional name) {
+    super();
+    this.sort = sort;
+    this.name = name;
+  }
 
-    public Option getName() {
-        if (name.isPresent()) {
-            return Option.apply(name.get());
-        }
-        return Option.empty();
+  public Option getName() {
+    if (name.isPresent()) {
+      return Option.apply(name.get());
     }
+    return Option.empty();
+  }
 
-    public void setSort(Sort sort) {
-        this.sort = sort;
-    }
+  public void setSort(Sort sort) {
+    this.sort = sort;
+  }
 
-    public Sort getSort() {
-        return sort;
-    }
+  public Sort getSort() {
+    return sort;
+  }
 
-    public Sort getRealSort() {
-        return sort;
-    }
+  public Sort getRealSort() {
+    return sort;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        if (name.isPresent()) {
-          sb.append(name.get()).append(": ");
-        }
-        sb.append(sort);
+  @Override
+  public void toString(StringBuilder sb) {
+    if (name.isPresent()) {
+      sb.append(name.get()).append(": ");
     }
+    sb.append(sort);
+  }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (obj == this)
-            return true;
-        if (!(obj instanceof NonTerminal nt))
-            return false;
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (obj == this) return true;
+    if (!(obj instanceof NonTerminal nt)) return false;
 
-        return sort.equals(nt.sort);
-    }
-
-    @Override
-    public int hashCode() {
-        return sort.hashCode();
-    }
+    return sort.equals(nt.sort);
+  }
 
+  @Override
+  public int hashCode() {
+    return sort.hashCode();
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/PriorityBlock.java b/kernel/src/main/java/org/kframework/kil/PriorityBlock.java
index 776ed5c7721..008c31a2227 100644
--- a/kernel/src/main/java/org/kframework/kil/PriorityBlock.java
+++ b/kernel/src/main/java/org/kframework/kil/PriorityBlock.java
@@ -2,94 +2,89 @@
 package org.kframework.kil;
 
 import com.google.common.collect.Lists;
-
 import java.util.ArrayList;
 
 /**
  * A block of productions at the same priority within a syntax declaration.
+ *
  * @see Syntax
  */
 public class PriorityBlock extends ASTNode {
 
-    java.util.List productions = new ArrayList();
-    /** "left", "right", or "non-assoc" if this group of productions had
-     * an explicitly declared associativity, "" otherwise */
-    String assoc;
-
-    public java.util.List getProductions() {
-        return productions;
+  java.util.List productions = new ArrayList();
+
+  /**
+   * "left", "right", or "non-assoc" if this group of productions had an explicitly declared
+   * associativity, "" otherwise
+   */
+  String assoc;
+
+  public java.util.List getProductions() {
+    return productions;
+  }
+
+  public void setProductions(java.util.List productions) {
+    this.productions = productions;
+  }
+
+  public String getAssoc() {
+    return assoc;
+  }
+
+  public void setAssoc(String assoc) {
+    this.assoc = assoc;
+  }
+
+  public PriorityBlock() {
+    super();
+    this.assoc = "";
+  }
+
+  public PriorityBlock(String assoc, java.util.List productions) {
+    super();
+    this.assoc = assoc;
+    this.productions = productions;
+  }
+
+  public PriorityBlock(String assoc, Production... productions) {
+    this(assoc, Lists.newArrayList(productions));
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    if (!assoc.equals("")) {
+      sb.append(assoc).append(": \n    ");
     }
-
-    public void setProductions(java.util.List productions) {
-        this.productions = productions;
+    String conn = "";
+    for (Production production : productions) {
+      sb.append(conn);
+      production.toString(sb);
+      conn = "\n  | ";
     }
+  }
 
-    public String getAssoc() {
-        return assoc;
-    }
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (this == obj) return true;
+    if (!(obj instanceof PriorityBlock pb)) return false;
 
-    public void setAssoc(String assoc) {
-        this.assoc = assoc;
-    }
+    if (!pb.getAssoc().equals(this.assoc)) return false;
 
-    public PriorityBlock() {
-        super();
-        this.assoc = "";
-    }
-
-    public PriorityBlock(String assoc, java.util.List productions) {
-        super();
-        this.assoc = assoc;
-        this.productions = productions;
-    }
+    if (pb.productions.size() != productions.size()) return false;
 
-    public PriorityBlock(String assoc, Production... productions) {
-        this(assoc, Lists.newArrayList(productions));
+    for (int i = 0; i < pb.productions.size(); i++) {
+      if (!pb.productions.get(i).equals(productions.get(i))) return false;
     }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        if (!assoc.equals("")) {
-            sb.append(assoc).append(": \n    ");
-        }
-        String conn = "";
-        for (Production production : productions) {
-            sb.append(conn);
-            production.toString(sb);
-            conn = "\n  | ";
-        }
-    }
+    return true;
+  }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (this == obj)
-            return true;
-        if (!(obj instanceof PriorityBlock pb))
-            return false;
-
-        if (!pb.getAssoc().equals(this.assoc))
-            return false;
-
-        if (pb.productions.size() != productions.size())
-            return false;
-
-        for (int i = 0; i < pb.productions.size(); i++) {
-            if (!pb.productions.get(i).equals(productions.get(i)))
-                return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = assoc.hashCode();
-
-        for (Production prd : productions)
-            hash += prd.hashCode();
-        return hash;
-    }
+  @Override
+  public int hashCode() {
+    int hash = assoc.hashCode();
 
+    for (Production prd : productions) hash += prd.hashCode();
+    return hash;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/PriorityBlockExtended.java b/kernel/src/main/java/org/kframework/kil/PriorityBlockExtended.java
index ffccf40a51b..34b216d8a18 100644
--- a/kernel/src/main/java/org/kframework/kil/PriorityBlockExtended.java
+++ b/kernel/src/main/java/org/kframework/kil/PriorityBlockExtended.java
@@ -1,64 +1,59 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
-import org.kframework.definition.Tag;
-
 import java.util.ArrayList;
+import org.kframework.definition.Tag;
 
-/** A group within a {@code syntax priorities} declaration.
- * @see PriorityExtended */
+/**
+ * A group within a {@code syntax priorities} declaration.
+ *
+ * @see PriorityExtended
+ */
 public class PriorityBlockExtended extends ASTNode {
 
-    java.util.List productions = new ArrayList<>();
+  java.util.List productions = new ArrayList<>();
 
-    public java.util.List getProductions() {
-        return productions;
-    }
+  public java.util.List getProductions() {
+    return productions;
+  }
 
-    public void setProductions(java.util.List productions) {
-        this.productions = productions;
-    }
+  public void setProductions(java.util.List productions) {
+    this.productions = productions;
+  }
 
-    public PriorityBlockExtended(java.util.List productions) {
-        super();
-        this.productions.addAll(productions);
-    }
+  public PriorityBlockExtended(java.util.List productions) {
+    super();
+    this.productions.addAll(productions);
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        for (Tag production : productions) {
-            sb.append(production);
-            sb.append(" ");
-        }
+  @Override
+  public void toString(StringBuilder sb) {
+    for (Tag production : productions) {
+      sb.append(production);
+      sb.append(" ");
     }
+  }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (this == obj)
-            return true;
-        if (!(obj instanceof PriorityBlockExtended pb))
-            return false;
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (this == obj) return true;
+    if (!(obj instanceof PriorityBlockExtended pb)) return false;
 
-        if (pb.productions.size() != productions.size())
-            return false;
+    if (pb.productions.size() != productions.size()) return false;
 
-        for (int i = 0; i < pb.productions.size(); i++) {
-            if (!pb.productions.get(i).equals(productions.get(i)))
-                return false;
-        }
-
-        return true;
+    for (int i = 0; i < pb.productions.size(); i++) {
+      if (!pb.productions.get(i).equals(productions.get(i))) return false;
     }
 
-    @Override
-    public int hashCode() {
-        int hash = 0;
+    return true;
+  }
 
-        for (Tag prd : productions)
-            hash += prd.hashCode();
-        return hash;
-    }
+  @Override
+  public int hashCode() {
+    int hash = 0;
 
+    for (Tag prd : productions) hash += prd.hashCode();
+    return hash;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/PriorityExtended.java b/kernel/src/main/java/org/kframework/kil/PriorityExtended.java
index c65e5e79fba..86f6da122c7 100644
--- a/kernel/src/main/java/org/kframework/kil/PriorityExtended.java
+++ b/kernel/src/main/java/org/kframework/kil/PriorityExtended.java
@@ -1,62 +1,58 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
-/** A priority declaration, {@code syntax priorities} labels {@code >} ... {@code >} labels.
+/**
+ * A priority declaration, {@code syntax priorities} labels {@code >} ... {@code >}
+ * labels.
+ *
  * @see PriorityBlockExtended
  */
 public class PriorityExtended extends ModuleItem {
-    /** Highest priority block comes first */
-    java.util.List priorityBlocks;
-
-    public PriorityExtended(java.util.List priorities) {
-        super();
-        this.priorityBlocks = priorities;
-    }
-
-    public java.util.List getPriorityBlocks() {
-        return priorityBlocks;
+  /** Highest priority block comes first */
+  java.util.List priorityBlocks;
+
+  public PriorityExtended(java.util.List priorities) {
+    super();
+    this.priorityBlocks = priorities;
+  }
+
+  public java.util.List getPriorityBlocks() {
+    return priorityBlocks;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("  syntax priorities ");
+    String conn = "";
+    for (PriorityBlockExtended pb : priorityBlocks) {
+      sb.append(conn);
+      pb.toString(sb);
+      conn = " > ";
     }
+    sb.append(" ");
+    sb.append(getAttributes());
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("  syntax priorities ");
-        String conn = "";
-        for (PriorityBlockExtended pb : priorityBlocks) {
-            sb.append(conn);
-            pb.toString(sb);
-            conn = " > ";
-        }
-        sb.append(" ");
-        sb.append(getAttributes());
-    }
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (this == obj) return true;
+    if (!(obj instanceof PriorityExtended syn)) return false;
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (this == obj)
-            return true;
-        if (!(obj instanceof PriorityExtended syn))
-            return false;
+    if (syn.priorityBlocks.size() != priorityBlocks.size()) return false;
 
-        if (syn.priorityBlocks.size() != priorityBlocks.size())
-            return false;
-
-        for (int i = 0; i < syn.priorityBlocks.size(); i++) {
-            if (!syn.priorityBlocks.get(i).equals(priorityBlocks.get(i)))
-                return false;
-        }
-
-        return true;
+    for (int i = 0; i < syn.priorityBlocks.size(); i++) {
+      if (!syn.priorityBlocks.get(i).equals(priorityBlocks.get(i))) return false;
     }
 
-    @Override
-    public int hashCode() {
-        int hash = 0;
+    return true;
+  }
 
-        for (PriorityBlockExtended pb : priorityBlocks)
-            hash += pb.hashCode();
-        return hash;
-    }
+  @Override
+  public int hashCode() {
+    int hash = 0;
 
+    for (PriorityBlockExtended pb : priorityBlocks) hash += pb.hashCode();
+    return hash;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/PriorityExtendedAssoc.java b/kernel/src/main/java/org/kframework/kil/PriorityExtendedAssoc.java
index 6dce9bdcfe6..aa683d88bc9 100644
--- a/kernel/src/main/java/org/kframework/kil/PriorityExtendedAssoc.java
+++ b/kernel/src/main/java/org/kframework/kil/PriorityExtendedAssoc.java
@@ -4,72 +4,67 @@
 import org.kframework.definition.Tag;
 
 /**
- * An associativity declaration, one of {@code syntax left}, {@code syntax right}, or {@ code syntax non-assoc}.
+ * An associativity declaration, one of {@code syntax left}, {@code syntax right}, or {@ code syntax
+ * non-assoc}.
  */
 public class PriorityExtendedAssoc extends ModuleItem {
-    /** "left", "right", "non-assoc" */
-    String assoc = null;
-    /** The labels getting an associativity. */
-    java.util.List tags;
+  /** "left", "right", "non-assoc" */
+  String assoc = null;
 
-    public String getAssoc() {
-        return assoc;
-    }
+  /** The labels getting an associativity. */
+  java.util.List tags;
 
-    public void setAssoc(String assoc) {
-        this.assoc = assoc;
-    }
+  public String getAssoc() {
+    return assoc;
+  }
 
-    public java.util.List getTags() {
-        return tags;
-    }
+  public void setAssoc(String assoc) {
+    this.assoc = assoc;
+  }
 
-    public void setTags(java.util.List tags) {
-        this.tags = tags;
-    }
+  public java.util.List getTags() {
+    return tags;
+  }
 
-    public PriorityExtendedAssoc(String assoc, java.util.List tags) {
-        super();
-        this.tags = tags;
-        this.assoc = assoc;
-    }
+  public void setTags(java.util.List tags) {
+    this.tags = tags;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("  syntax ").append(assoc).append(" ");
-        for (Tag pb : tags) {
-            sb.append(pb).append(" ");
-        }
-        sb.append(getAttributes());
-    }
+  public PriorityExtendedAssoc(String assoc, java.util.List tags) {
+    super();
+    this.tags = tags;
+    this.assoc = assoc;
+  }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (this == obj)
-            return true;
-        if (!(obj instanceof PriorityExtendedAssoc syn))
-            return false;
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("  syntax ").append(assoc).append(" ");
+    for (Tag pb : tags) {
+      sb.append(pb).append(" ");
+    }
+    sb.append(getAttributes());
+  }
 
-        if (syn.tags.size() != tags.size())
-            return false;
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (this == obj) return true;
+    if (!(obj instanceof PriorityExtendedAssoc syn)) return false;
 
-        for (int i = 0; i < syn.tags.size(); i++) {
-            if (!syn.tags.get(i).equals(tags.get(i)))
-                return false;
-        }
+    if (syn.tags.size() != tags.size()) return false;
 
-        return true;
+    for (int i = 0; i < syn.tags.size(); i++) {
+      if (!syn.tags.get(i).equals(tags.get(i))) return false;
     }
 
-    @Override
-    public int hashCode() {
-        int hash = assoc.hashCode();
+    return true;
+  }
 
-        for (Tag pb : tags)
-            hash += pb.hashCode();
-        return hash;
-    }
+  @Override
+  public int hashCode() {
+    int hash = assoc.hashCode();
 
+    for (Tag pb : tags) hash += pb.hashCode();
+    return hash;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Production.java b/kernel/src/main/java/org/kframework/kil/Production.java
index e0d89b95a83..3021bc9d5fd 100644
--- a/kernel/src/main/java/org/kframework/kil/Production.java
+++ b/kernel/src/main/java/org/kframework/kil/Production.java
@@ -1,252 +1,249 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
-import org.kframework.kore.Sort;
-import org.kframework.attributes.Att;
-
 import com.google.common.collect.Multimap;
-import org.kframework.utils.StringUtil;
-
 import java.util.ArrayList;
 import java.util.List;
+import org.kframework.attributes.Att;
+import org.kframework.kore.Sort;
+import org.kframework.utils.StringUtil;
 
 /**
  * A production. Any explicit attributes on the production are stored in {@link ASTNode#attributes}.
  */
 public class Production extends ASTNode {
 
-    /*
-     * Andrei S: It appears that the cons attribute is mandatory for all new production added during compilation, otherwise a null pointer exception can be thrown in one of the later compilation
-     * steps.
-     */
-    protected List items;
-    protected Sort sort;
-    protected List params;
-    protected String ownerModuleName;
-    private Multimap binderMap;
-
-    public boolean isListDecl() {
-        return items.size() == 1 && items.get(0) instanceof UserList;
-    }
-
-    /**
-     * Returns the KLabel for the list terminator.
-     * Constructed as '.List{""}
-     * Should be called only if isListDecl is true.
-     * @return String representation of the separator KLabel.
-     */
-    public String getTerminatorKLabel(boolean kore) {
-        assert isListDecl();
-        return ".List{" + StringUtil.enquoteCString(getKLabel(kore)) + "}" + (kore ? "_" + getSort().name() : "");
-    }
-
-    /**
-     * True if this production consists of a single nonterminal,
-     * even if it has an explicitly assigned label and so is
-     * not semantically a subsort declaration.
-     * @return
-     */
-    public boolean isSyntacticSubsort() {
-        return items.size() == 1 && items.get(0) instanceof NonTerminal;
-    }
-
-    public boolean isLexical() {
-        return items.size() == 1 && items.get(0) instanceof Lexical;
-    }
-
-    /**
-     * Retrieves the {@link Lexical} object of the production if this is a lexical token.
-     * Should not be called on other types of productions.
-     * @return the Lexical object
-     */
-    public Lexical getLexical() {
-        assert isLexical();
-        return (Lexical) items.get(0);
-    }
-
-    /**
-     * Retrieves the {@link Terminal} object of the production if this is a constant.
-     * Should not be called on other types of productions.
-     * @return the Terminal object
-     */
-    public Terminal getConstant() {
-        assert isTerminal(); // should be at least a single terminal
-        return (Terminal) items.get(0);
-    }
-
-    /**
-     * Returns true if this production consists of exactly one terminal.
-     */
-    public boolean isTerminal() {
-        return items.size() == 1 && items.get(0) instanceof Terminal;
-    }
-
-    public Production(NonTerminal sort, java.util.List items) {
-        super();
-        this.items = items;
-        this.sort = sort.getSort();
-    }
-
-    public Production(NonTerminal sort, java.util.List items, String ownerModule) {
-        super();
-        this.items = items;
-        this.sort = sort.getSort();
-        this.ownerModuleName = ownerModule;
-    }
-
-    /**
-     * Gets the KLabel corresponding to this production. A production has a
-     * KLabel if and only if the production flattens in KORE to a term which is of sort
-     * KItem (ie, is a function or a constructor).
-     * @return
-     */
-    public String getKLabel(boolean kore) {
-        String klabel = getAttribute(Att.KLABEL());
-        if (klabel == null && (isSyntacticSubsort() || containsAttribute(Att.TOKEN()) || containsAttribute(Att.BRACKET()))) {
-            return null;
-        } else if (klabel == null || (kore && getAttribute(Att.SYMBOL()) == null)) {
-            klabel = getPrefixLabel(kore);
-        }
-        return klabel.replace(" ", "");
-    }
-
-    public String getBracketLabel(boolean kore) {
-        String klabel = getAttribute(Att.KLABEL());
-        if (klabel == null || (kore && getAttribute(Att.SYMBOL()) == null)) {
-            klabel = getPrefixLabel(kore);
-        }
-        return klabel.replace(" ", "");
-    }
-
-    private String getPrefixLabel(boolean kore) {
-        String label = "";
-        List sorts = new ArrayList<>();
-        for (ProductionItem pi : items) {
-            if (pi instanceof NonTerminal) {
-                label += "_";
-                sorts.add(((NonTerminal) pi).getSort().name());
-            } else if (pi instanceof Terminal) {
-                label += ((Terminal) pi).getTerminal();
-            } else if (pi instanceof UserList) {
-                label += "_" + ((UserList) pi).separator + "_";
-                sorts.add(((UserList) pi).sort.name());
-                sorts.add(sort.name());
-            }
-        }
-        return label + "_" + ownerModuleName + (kore ? "_" + sorts.stream().reduce(sort.name(), (s1, s2) -> s1 + "_" + s2) : "");
-    }
-
-    public java.util.List getItems() {
-        return items;
-    }
-
-    public void setItems(java.util.List items) {
-        this.items = items;
-    }
-
-    /**
-     * Gets the arity of a production. A production's arity is the number of
-     * nonterminals in the syntactic declaration which the production
-     * corresponds to.
-     * @return
-     */
-    public int getArity() {
-        int arity = 0;
-        for (ProductionItem i : items) {
-            if (i instanceof UserList)
-                arity += 2;
-            if (i instanceof NonTerminal)
-                arity++;
-        }
-        return arity;
-    }
-
-    public Sort getSort() {
-        return sort;
-    }
-
-    public void setSort(Sort sort) {
-        this.sort = sort;
-    }
-
-    public List getParams() {
-        return params;
-    }
-
-    public void setParams(List params) {
-        this.params = params;
-    }
-
-    public ASTNode getChildNode(int idx) {
-        int arity = -1;
-        if (items.get(0) instanceof UserList) {
-            if (idx == 0) {
-                return items.get(0);
-            } else {
-                return this;
-            }
-        }
-        for (ProductionItem i : items) {
-            if (!(i instanceof Terminal))
-                arity++;
-            if (arity == idx) {
-                return i;
-            }
-        }
-        return null;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        Production other = (Production) obj;
-        if (items == null) {
-            if (other.items != null)
-                return false;
-        } else if (!items.equals(other.items))
-            return false;
-        if (getAttribute(Att.KLABEL()) == null) {
-            if (other.getAttribute(Att.KLABEL()) != null)
-                return false;
-        } else if (!getAttribute(Att.KLABEL()).equals(other.getAttribute(Att.KLABEL())))
-            return false;
-        if (sort == null) {
-            if (other.sort != null)
-                return false;
-        } else if (!sort.equals(other.sort))
-            return false;
-        if (binderMap == null) {
-            return other.binderMap == null;
-        } else return binderMap.equals(other.binderMap);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((items == null) ? 0 : items.hashCode());
-        result = prime * result
-                + ((getAttribute(Att.KLABEL()) == null) ? 0 : getAttribute(Att.KLABEL()).hashCode());
-        result = prime * result + ((sort == null) ? 0 : sort.hashCode());
-        result = prime * result + ((binderMap == null) ? 0 : binderMap.hashCode());
-        return result;
-    }
-
-    @Override
-    public void toString(StringBuilder sb) {
-        for (ProductionItem i : items) {
-            i.toString(sb);
-            sb.append(" ");
-        }
-        sb.append(getAttributes().withUserGroupsAsGroupAtt());
-    }
-
-    public void setOwnerModuleName(String ownerModuleName) {
-        this.ownerModuleName = ownerModuleName;
-    }
+  /*
+   * Andrei S: It appears that the cons attribute is mandatory for all new production added during compilation, otherwise a null pointer exception can be thrown in one of the later compilation
+   * steps.
+   */
+  protected List items;
+  protected Sort sort;
+  protected List params;
+  protected String ownerModuleName;
+  private Multimap binderMap;
+
+  public boolean isListDecl() {
+    return items.size() == 1 && items.get(0) instanceof UserList;
+  }
+
+  /**
+   * Returns the KLabel for the list terminator. Constructed as '.List{""} Should be
+   * called only if isListDecl is true.
+   *
+   * @return String representation of the separator KLabel.
+   */
+  public String getTerminatorKLabel(boolean kore) {
+    assert isListDecl();
+    return ".List{"
+        + StringUtil.enquoteCString(getKLabel(kore))
+        + "}"
+        + (kore ? "_" + getSort().name() : "");
+  }
+
+  /**
+   * True if this production consists of a single nonterminal, even if it has an explicitly assigned
+   * label and so is not semantically a subsort declaration.
+   *
+   * @return
+   */
+  public boolean isSyntacticSubsort() {
+    return items.size() == 1 && items.get(0) instanceof NonTerminal;
+  }
+
+  public boolean isLexical() {
+    return items.size() == 1 && items.get(0) instanceof Lexical;
+  }
+
+  /**
+   * Retrieves the {@link Lexical} object of the production if this is a lexical token. Should not
+   * be called on other types of productions.
+   *
+   * @return the Lexical object
+   */
+  public Lexical getLexical() {
+    assert isLexical();
+    return (Lexical) items.get(0);
+  }
+
+  /**
+   * Retrieves the {@link Terminal} object of the production if this is a constant. Should not be
+   * called on other types of productions.
+   *
+   * @return the Terminal object
+   */
+  public Terminal getConstant() {
+    assert isTerminal(); // should be at least a single terminal
+    return (Terminal) items.get(0);
+  }
+
+  /** Returns true if this production consists of exactly one terminal. */
+  public boolean isTerminal() {
+    return items.size() == 1 && items.get(0) instanceof Terminal;
+  }
+
+  public Production(NonTerminal sort, java.util.List items) {
+    super();
+    this.items = items;
+    this.sort = sort.getSort();
+  }
+
+  public Production(NonTerminal sort, java.util.List items, String ownerModule) {
+    super();
+    this.items = items;
+    this.sort = sort.getSort();
+    this.ownerModuleName = ownerModule;
+  }
+
+  /**
+   * Gets the KLabel corresponding to this production. A production has a KLabel if and only if the
+   * production flattens in KORE to a term which is of sort KItem (ie, is a function or a
+   * constructor).
+   *
+   * @return
+   */
+  public String getKLabel(boolean kore) {
+    String klabel = getAttribute(Att.KLABEL());
+    if (klabel == null
+        && (isSyntacticSubsort()
+            || containsAttribute(Att.TOKEN())
+            || containsAttribute(Att.BRACKET()))) {
+      return null;
+    } else if (klabel == null || (kore && getAttribute(Att.SYMBOL()) == null)) {
+      klabel = getPrefixLabel(kore);
+    }
+    return klabel.replace(" ", "");
+  }
+
+  public String getBracketLabel(boolean kore) {
+    String klabel = getAttribute(Att.KLABEL());
+    if (klabel == null || (kore && getAttribute(Att.SYMBOL()) == null)) {
+      klabel = getPrefixLabel(kore);
+    }
+    return klabel.replace(" ", "");
+  }
+
+  private String getPrefixLabel(boolean kore) {
+    String label = "";
+    List sorts = new ArrayList<>();
+    for (ProductionItem pi : items) {
+      if (pi instanceof NonTerminal) {
+        label += "_";
+        sorts.add(((NonTerminal) pi).getSort().name());
+      } else if (pi instanceof Terminal) {
+        label += ((Terminal) pi).getTerminal();
+      } else if (pi instanceof UserList) {
+        label += "_" + ((UserList) pi).separator + "_";
+        sorts.add(((UserList) pi).sort.name());
+        sorts.add(sort.name());
+      }
+    }
+    return label
+        + "_"
+        + ownerModuleName
+        + (kore ? "_" + sorts.stream().reduce(sort.name(), (s1, s2) -> s1 + "_" + s2) : "");
+  }
+
+  public java.util.List getItems() {
+    return items;
+  }
+
+  public void setItems(java.util.List items) {
+    this.items = items;
+  }
+
+  /**
+   * Gets the arity of a production. A production's arity is the number of nonterminals in the
+   * syntactic declaration which the production corresponds to.
+   *
+   * @return
+   */
+  public int getArity() {
+    int arity = 0;
+    for (ProductionItem i : items) {
+      if (i instanceof UserList) arity += 2;
+      if (i instanceof NonTerminal) arity++;
+    }
+    return arity;
+  }
+
+  public Sort getSort() {
+    return sort;
+  }
+
+  public void setSort(Sort sort) {
+    this.sort = sort;
+  }
+
+  public List getParams() {
+    return params;
+  }
+
+  public void setParams(List params) {
+    this.params = params;
+  }
+
+  public ASTNode getChildNode(int idx) {
+    int arity = -1;
+    if (items.get(0) instanceof UserList) {
+      if (idx == 0) {
+        return items.get(0);
+      } else {
+        return this;
+      }
+    }
+    for (ProductionItem i : items) {
+      if (!(i instanceof Terminal)) arity++;
+      if (arity == idx) {
+        return i;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) return true;
+    if (obj == null) return false;
+    if (getClass() != obj.getClass()) return false;
+    Production other = (Production) obj;
+    if (items == null) {
+      if (other.items != null) return false;
+    } else if (!items.equals(other.items)) return false;
+    if (getAttribute(Att.KLABEL()) == null) {
+      if (other.getAttribute(Att.KLABEL()) != null) return false;
+    } else if (!getAttribute(Att.KLABEL()).equals(other.getAttribute(Att.KLABEL()))) return false;
+    if (sort == null) {
+      if (other.sort != null) return false;
+    } else if (!sort.equals(other.sort)) return false;
+    if (binderMap == null) {
+      return other.binderMap == null;
+    } else return binderMap.equals(other.binderMap);
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((items == null) ? 0 : items.hashCode());
+    result =
+        prime * result
+            + ((getAttribute(Att.KLABEL()) == null) ? 0 : getAttribute(Att.KLABEL()).hashCode());
+    result = prime * result + ((sort == null) ? 0 : sort.hashCode());
+    result = prime * result + ((binderMap == null) ? 0 : binderMap.hashCode());
+    return result;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    for (ProductionItem i : items) {
+      i.toString(sb);
+      sb.append(" ");
+    }
+    sb.append(getAttributes().withUserGroupsAsGroupAtt());
+  }
+
+  public void setOwnerModuleName(String ownerModuleName) {
+    this.ownerModuleName = ownerModuleName;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/ProductionItem.java b/kernel/src/main/java/org/kframework/kil/ProductionItem.java
index f6bd8d16687..3297d1bfa2c 100644
--- a/kernel/src/main/java/org/kframework/kil/ProductionItem.java
+++ b/kernel/src/main/java/org/kframework/kil/ProductionItem.java
@@ -2,7 +2,7 @@
 package org.kframework.kil;
 
 public abstract class ProductionItem extends ASTNode {
-    public ProductionItem() {
-        super();
-    }
+  public ProductionItem() {
+    super();
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Require.java b/kernel/src/main/java/org/kframework/kil/Require.java
index b243911231e..75a4eb56306 100644
--- a/kernel/src/main/java/org/kframework/kil/Require.java
+++ b/kernel/src/main/java/org/kframework/kil/Require.java
@@ -5,25 +5,25 @@
 
 /** A require directive */
 public class Require extends DefinitionItem {
-    /** The string argument to {@code require}, as written in the input file. */
-    private String value;
+  /** The string argument to {@code require}, as written in the input file. */
+  private String value;
 
-    public Require(String value) {
-        super();
-        this.value = value;
-    }
+  public Require(String value) {
+    super();
+    this.value = value;
+  }
 
-    public void setValue(String value) {
-        this.value = value;
-    }
+  public void setValue(String value) {
+    this.value = value;
+  }
 
-    public String getValue() {
-        return value;
-    }
+  public String getValue() {
+    return value;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("require ");
-        sb.append(StringUtil.enquoteCString(value));
-    }
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("require ");
+    sb.append(StringUtil.enquoteCString(value));
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/SortSynonym.java b/kernel/src/main/java/org/kframework/kil/SortSynonym.java
index dc172a4c367..0e985b2ea55 100644
--- a/kernel/src/main/java/org/kframework/kil/SortSynonym.java
+++ b/kernel/src/main/java/org/kframework/kil/SortSynonym.java
@@ -5,41 +5,41 @@
 
 public class SortSynonym extends ModuleItem {
 
-    public final Sort newSort;
-    public final Sort oldSort;
-
-    public SortSynonym(NonTerminal newSort, NonTerminal oldSort) {
-        super();
-        this.newSort = newSort.getSort();
-        this.oldSort = oldSort.getSort();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        SortSynonym other = (SortSynonym) obj;
-        if (!newSort.equals(other.newSort))
-            return false;
-        return oldSort.equals(other.oldSort);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + newSort.hashCode();
-        result = prime * result + oldSort.hashCode();
-        return result;
-    }
-
-    @Override
-    public void toString(StringBuilder sb) {
-      sb.append("  syntax ").append(newSort).append(" = ").append(oldSort).append(" ").append(getAttributes());
-    }
-
+  public final Sort newSort;
+  public final Sort oldSort;
+
+  public SortSynonym(NonTerminal newSort, NonTerminal oldSort) {
+    super();
+    this.newSort = newSort.getSort();
+    this.oldSort = oldSort.getSort();
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) return true;
+    if (obj == null) return false;
+    if (getClass() != obj.getClass()) return false;
+    SortSynonym other = (SortSynonym) obj;
+    if (!newSort.equals(other.newSort)) return false;
+    return oldSort.equals(other.oldSort);
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + newSort.hashCode();
+    result = prime * result + oldSort.hashCode();
+    return result;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("  syntax ")
+        .append(newSort)
+        .append(" = ")
+        .append(oldSort)
+        .append(" ")
+        .append(getAttributes());
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/StringSentence.java b/kernel/src/main/java/org/kframework/kil/StringSentence.java
index 17c0d31050a..bfbf1de44b2 100644
--- a/kernel/src/main/java/org/kframework/kil/StringSentence.java
+++ b/kernel/src/main/java/org/kframework/kil/StringSentence.java
@@ -5,65 +5,65 @@
  * Used as a container for unparsed sentences like rule, context and configuration.
  *
  * @author Radu
- *
  */
 public class StringSentence extends ModuleItem {
-    private String content;
-    private final int contentStartLine;
-    private final int contentStartColumn;
-    private String label;
-    private String type;
+  private String content;
+  private final int contentStartLine;
+  private final int contentStartColumn;
+  private String label;
+  private String type;
 
-    public StringSentence(String content, int contentStartLine, int contentStartColumn, String type, String label) {
-        this.content = content;
-        this.contentStartLine = contentStartLine;
-        this.contentStartColumn = contentStartColumn;
-        this.type = type;
-        this.label = label;
-    }
+  public StringSentence(
+      String content, int contentStartLine, int contentStartColumn, String type, String label) {
+    this.content = content;
+    this.contentStartLine = contentStartLine;
+    this.contentStartColumn = contentStartColumn;
+    this.type = type;
+    this.label = label;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        switch (type) {
-        case "config" -> sb.append("  configuration ");
-        case "alias" -> sb.append("  context alias ");
-        default -> sb.append("  ").append(type).append(" ");
-        }
-        if (!label.equals("")) {
-          sb.append("[").append(label).append("]: ");
-        }
-        sb.append(content).append(" ").append(getAttributes());
+  @Override
+  public void toString(StringBuilder sb) {
+    switch (type) {
+      case "config" -> sb.append("  configuration ");
+      case "alias" -> sb.append("  context alias ");
+      default -> sb.append("  ").append(type).append(" ");
     }
-
-    public String getContent() {
-        return content;
+    if (!label.equals("")) {
+      sb.append("[").append(label).append("]: ");
     }
+    sb.append(content).append(" ").append(getAttributes());
+  }
 
-    public void setContent(String content) {
-        this.content = content;
-    }
+  public String getContent() {
+    return content;
+  }
 
-    public void setType(String type) {
-        this.type = type;
-    }
+  public void setContent(String content) {
+    this.content = content;
+  }
 
-    public String getType() {
-        return type;
-    }
+  public void setType(String type) {
+    this.type = type;
+  }
 
-    public String getLabel() {
-        return label;
-    }
+  public String getType() {
+    return type;
+  }
 
-    public void setLabel(String label) {
-        this.label = label;
-    }
+  public String getLabel() {
+    return label;
+  }
 
-    public int getContentStartLine() {
-        return contentStartLine;
-    }
+  public void setLabel(String label) {
+    this.label = label;
+  }
 
-    public int getContentStartColumn() {
-        return contentStartColumn;
-    }
+  public int getContentStartLine() {
+    return contentStartLine;
+  }
+
+  public int getContentStartColumn() {
+    return contentStartColumn;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Syntax.java b/kernel/src/main/java/org/kframework/kil/Syntax.java
index a88dda8191c..40a793ab0c2 100644
--- a/kernel/src/main/java/org/kframework/kil/Syntax.java
+++ b/kernel/src/main/java/org/kframework/kil/Syntax.java
@@ -1,111 +1,100 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil;
 
-import org.kframework.kore.Sort;
-
 import java.util.ArrayList;
 import java.util.List;
+import org.kframework.kore.Sort;
 
 /**
- * A syntax declaration.
- * Contains {@link Production}s, grouped into a list {@link PriorityBlock}
+ * A syntax declaration. Contains {@link Production}s, grouped into a list {@link PriorityBlock}
  * according to precedence marked by {@code >} in the declaration.
  */
 public class Syntax extends ModuleItem {
-    /** The sort being declared. */
-    NonTerminal sort;
-    java.util.List params;
-    java.util.List priorityBlocks;
-
-    public Syntax(NonTerminal sort, List params, List priorities) {
-        super();
-        this.sort = sort;
-        this.params = params;
-        this.priorityBlocks = priorities;
-    }
-
-    public Syntax(NonTerminal sort, List params) {
-        this(sort, params, new ArrayList());
-    }
-
-    /**
-     * The sort being declared.
-     */
-    public NonTerminal getDeclaredSort() {
-        return sort;
-    }
-
-    public List getParams() {
-        return params;
+  /** The sort being declared. */
+  NonTerminal sort;
+
+  java.util.List params;
+  java.util.List priorityBlocks;
+
+  public Syntax(NonTerminal sort, List params, List priorities) {
+    super();
+    this.sort = sort;
+    this.params = params;
+    this.priorityBlocks = priorities;
+  }
+
+  public Syntax(NonTerminal sort, List params) {
+    this(sort, params, new ArrayList());
+  }
+
+  /** The sort being declared. */
+  public NonTerminal getDeclaredSort() {
+    return sort;
+  }
+
+  public List getParams() {
+    return params;
+  }
+
+  public void setSort(NonTerminal sort) {
+    this.sort = sort;
+  }
+
+  public java.util.List getPriorityBlocks() {
+    return priorityBlocks;
+  }
+
+  public void setPriorityBlocks(java.util.List priorityBlocks) {
+    this.priorityBlocks = priorityBlocks;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("  syntax ");
+    if (!params.isEmpty()) {
+      sb.append("{");
+      String conn = "";
+      for (Sort param : params) {
+        sb.append(conn);
+        sb.append(param);
+        conn = ", ";
+      }
+      sb.append("} ");
     }
-
-    public void setSort(NonTerminal sort) {
-        this.sort = sort;
+    sb.append(sort).append(" ").append(getAttributes());
+    if (!priorityBlocks.isEmpty()) {
+      sb.append(" ::=\n    ");
+      String conn = "";
+      for (PriorityBlock pb : priorityBlocks) {
+        sb.append(conn);
+        pb.toString(sb);
+        conn = "\n  > ";
+      }
     }
+  }
 
-    public java.util.List getPriorityBlocks() {
-        return priorityBlocks;
-    }
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (this == obj) return true;
+    if (!(obj instanceof Syntax syn)) return false;
 
-    public void setPriorityBlocks(java.util.List priorityBlocks) {
-        this.priorityBlocks = priorityBlocks;
-    }
-
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append("  syntax ");
-        if(!params.isEmpty()) {
-            sb.append("{");
-            String conn = "";
-            for (Sort param : params) {
-                sb.append(conn);
-                sb.append(param);
-                conn = ", ";
-            }
-            sb.append("} ");
-        }
-        sb.append(sort).append(" ").append(getAttributes());
-        if (!priorityBlocks.isEmpty()) {
-            sb.append(" ::=\n    ");
-            String conn = "";
-            for (PriorityBlock pb : priorityBlocks) {
-                sb.append(conn);
-                pb.toString(sb);
-                conn = "\n  > ";
-            }
-        }
-    }
+    if (!syn.getDeclaredSort().equals(this.sort)) return false;
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (this == obj)
-            return true;
-        if (!(obj instanceof Syntax syn))
-            return false;
+    if (syn.priorityBlocks.size() != priorityBlocks.size()) return false;
 
-        if (!syn.getDeclaredSort().equals(this.sort))
-            return false;
-
-        if (syn.priorityBlocks.size() != priorityBlocks.size())
-            return false;
-
-        for (int i = 0; i < syn.priorityBlocks.size(); i++) {
-            if (!syn.priorityBlocks.get(i).equals(priorityBlocks.get(i)))
-                return false;
-        }
-
-        return true;
+    for (int i = 0; i < syn.priorityBlocks.size(); i++) {
+      if (!syn.priorityBlocks.get(i).equals(priorityBlocks.get(i))) return false;
     }
 
-    @Override
-    public int hashCode() {
-        int hash = sort.hashCode();
+    return true;
+  }
 
-        for (PriorityBlock pb : priorityBlocks)
-            hash += pb.hashCode();
-        return hash;
-    }
+  @Override
+  public int hashCode() {
+    int hash = sort.hashCode();
 
+    for (PriorityBlock pb : priorityBlocks) hash += pb.hashCode();
+    return hash;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/SyntaxLexical.java b/kernel/src/main/java/org/kframework/kil/SyntaxLexical.java
index 7a10192bd21..2f269dd0935 100644
--- a/kernel/src/main/java/org/kframework/kil/SyntaxLexical.java
+++ b/kernel/src/main/java/org/kframework/kil/SyntaxLexical.java
@@ -5,41 +5,41 @@
 
 public class SyntaxLexical extends ModuleItem {
 
-    public final String name;
-    public final String regex;
-
-    public SyntaxLexical(String name, String regex) {
-        super();
-        this.name = name;
-        this.regex = regex;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
-            return false;
-        SyntaxLexical other = (SyntaxLexical) obj;
-        if (!name.equals(other.name))
-            return false;
-        return regex.equals(other.regex);
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + name.hashCode();
-        result = prime * result + regex.hashCode();
-        return result;
-    }
-
-    @Override
-    public void toString(StringBuilder sb) {
-      sb.append("  syntax lexical ").append(name).append(" = r").append(StringUtil.enquoteKString(regex)).append(" ").append(getAttributes());
-    }
-
+  public final String name;
+  public final String regex;
+
+  public SyntaxLexical(String name, String regex) {
+    super();
+    this.name = name;
+    this.regex = regex;
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (this == obj) return true;
+    if (obj == null) return false;
+    if (getClass() != obj.getClass()) return false;
+    SyntaxLexical other = (SyntaxLexical) obj;
+    if (!name.equals(other.name)) return false;
+    return regex.equals(other.regex);
+  }
+
+  @Override
+  public int hashCode() {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + name.hashCode();
+    result = prime * result + regex.hashCode();
+    return result;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append("  syntax lexical ")
+        .append(name)
+        .append(" = r")
+        .append(StringUtil.enquoteKString(regex))
+        .append(" ")
+        .append(getAttributes());
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/Terminal.java b/kernel/src/main/java/org/kframework/kil/Terminal.java
index 3091c35d98e..e8ac10a1de4 100644
--- a/kernel/src/main/java/org/kframework/kil/Terminal.java
+++ b/kernel/src/main/java/org/kframework/kil/Terminal.java
@@ -6,40 +6,37 @@
 /** A terminal in a {@link Production}. */
 public class Terminal extends ProductionItem {
 
-    private String terminal;
-
-    public Terminal(String terminal) {
-        super();
-        this.terminal = terminal;
-    }
-
-    public void setTerminal(String terminal) {
-        this.terminal = terminal;
-    }
-
-    public String getTerminal() {
-        return terminal;
-    }
-
-    @Override
-    public void toString(StringBuilder sb) {
-        sb.append(StringUtil.enquoteCString(terminal));
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (obj == this)
-            return true;
-        if (!(obj instanceof Terminal trm))
-            return false;
-
-        return trm.terminal.equals(this.terminal);
-    }
-
-    @Override
-    public int hashCode() {
-        return this.terminal.hashCode();
-    }
+  private String terminal;
+
+  public Terminal(String terminal) {
+    super();
+    this.terminal = terminal;
+  }
+
+  public void setTerminal(String terminal) {
+    this.terminal = terminal;
+  }
+
+  public String getTerminal() {
+    return terminal;
+  }
+
+  @Override
+  public void toString(StringBuilder sb) {
+    sb.append(StringUtil.enquoteCString(terminal));
+  }
+
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (obj == this) return true;
+    if (!(obj instanceof Terminal trm)) return false;
+
+    return trm.terminal.equals(this.terminal);
+  }
+
+  @Override
+  public int hashCode() {
+    return this.terminal.hashCode();
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/UserList.java b/kernel/src/main/java/org/kframework/kil/UserList.java
index 48f4e9abaf6..88820ff4f69 100644
--- a/kernel/src/main/java/org/kframework/kil/UserList.java
+++ b/kernel/src/main/java/org/kframework/kil/UserList.java
@@ -5,77 +5,82 @@
 import org.kframework.utils.StringUtil;
 
 /**
- * A production item for a cons-list with separator, like List{UserSort,";"}. Must be the only item in a {@link Production}.
+ * A production item for a cons-list with separator, like List{UserSort,";"}. Must be the only item
+ * in a {@link Production}.
  */
 public class UserList extends ProductionItem {
-    protected Sort sort;
-    protected String separator;
-    protected String listType;
+  protected Sort sort;
+  protected String separator;
+  protected String listType;
 
-    public static final String ZERO_OR_MORE = "*";
-    public static final String ONE_OR_MORE = "+";
+  public static final String ZERO_OR_MORE = "*";
+  public static final String ONE_OR_MORE = "+";
 
-    public UserList(Sort sort, String separator) {
-        this.sort = sort;
-        this.separator = separator.trim();
-        this.listType = ZERO_OR_MORE;
-    }
+  public UserList(Sort sort, String separator) {
+    this.sort = sort;
+    this.separator = separator.trim();
+    this.listType = ZERO_OR_MORE;
+  }
 
-    public UserList(Sort sort, String separator, String listType) {
-        this.sort = sort;
-        this.separator = separator.trim();
-        this.listType = listType;
-    }
+  public UserList(Sort sort, String separator, String listType) {
+    this.sort = sort;
+    this.separator = separator.trim();
+    this.listType = listType;
+  }
 
-    @Override
-    public void toString(StringBuilder sb) {
-        if (listType.equals(ZERO_OR_MORE)) {
-            sb.append("List{").append(sort).append(",").append(StringUtil.enquoteCString(separator)).append("}");
-        } else {
-            sb.append("NeList{").append(sort).append(",").append(StringUtil.enquoteCString(separator)).append("}");
-        }
+  @Override
+  public void toString(StringBuilder sb) {
+    if (listType.equals(ZERO_OR_MORE)) {
+      sb.append("List{")
+          .append(sort)
+          .append(",")
+          .append(StringUtil.enquoteCString(separator))
+          .append("}");
+    } else {
+      sb.append("NeList{")
+          .append(sort)
+          .append(",")
+          .append(StringUtil.enquoteCString(separator))
+          .append("}");
     }
+  }
 
-    public Sort getSort() {
-        return sort;
-    }
+  public Sort getSort() {
+    return sort;
+  }
 
-    public void setSort(Sort sort) {
-        this.sort = sort;
-    }
+  public void setSort(Sort sort) {
+    this.sort = sort;
+  }
 
-    public String getSeparator() {
-        return separator;
-    }
+  public String getSeparator() {
+    return separator;
+  }
 
-    public void setSeparator(String separator) {
-        this.separator = separator.trim();
-    }
+  public void setSeparator(String separator) {
+    this.separator = separator.trim();
+  }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null)
-            return false;
-        if (obj == this)
-            return true;
-        if (!(obj instanceof UserList srt))
-            return false;
+  @Override
+  public boolean equals(Object obj) {
+    if (obj == null) return false;
+    if (obj == this) return true;
+    if (!(obj instanceof UserList srt)) return false;
 
-        if (!sort.equals(srt.getSort()))
-            return false;
-        return separator.equals(srt.getSeparator());
-    }
+    if (!sort.equals(srt.getSort())) return false;
+    return separator.equals(srt.getSeparator());
+  }
 
-    @Override
-    public int hashCode() {
-        return this.separator.hashCode() + this.sort.hashCode();
-    }
+  @Override
+  public int hashCode() {
+    return this.separator.hashCode() + this.sort.hashCode();
+  }
 
-    public String getListType() {
-        return listType;
-    }
+  public String getListType() {
+    return listType;
+  }
 
-    public void setListType(String listType) {
-        this.listType = listType;
-    }
+  public void setListType(String listType) {
+    this.listType = listType;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kil/loader/Context.java b/kernel/src/main/java/org/kframework/kil/loader/Context.java
index a136a3922e6..e8994639f9b 100644
--- a/kernel/src/main/java/org/kframework/kil/loader/Context.java
+++ b/kernel/src/main/java/org/kframework/kil/loader/Context.java
@@ -1,50 +1,48 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kil.loader;
 
+import static org.kframework.Collections.*;
+
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.SetMultimap;
 import com.google.inject.Inject;
+import java.io.Serializable;
 import org.kframework.attributes.Att;
-import org.kframework.attributes.Att.Key;
 import org.kframework.kil.Production;
 import org.kframework.kompile.KompileOptions;
 import org.kframework.main.GlobalOptions;
 import org.kframework.utils.inject.RequestScoped;
 import scala.Tuple2;
 
-import java.io.Serializable;
-
-import static org.kframework.Collections.*;
-
 @RequestScoped
 public class Context implements Serializable {
 
-    @Inject
-    public Context() {}
-
-    /**
-     * Represents a map from all Klabels or attributes in string representation
-     * to sets of corresponding productions.
-     */
-    public SetMultimap tags = HashMultimap.create();
-
-    // TODO(dwightguth): remove these fields and replace with injected dependencies
-    @Deprecated @Inject public transient GlobalOptions globalOptions;
-    public KompileOptions kompileOptions;
-
-    public void addProduction(Production p) {
-        if (p.containsAttribute(Att.GROUP())) {
-            throw new AssertionError(
-                    "Must call ExpandGroupAttribute.apply(Definition) before creating a Context.");
-        }
-
-        if (p.getKLabel(false) != null) {
-            tags.put(p.getKLabel(false), p);
-        } else if (p.getAttributes().contains(Att.BRACKET())) {
-            tags.put(p.getBracketLabel(false), p);
-        }
-        for (Tuple2 a : iterable(p.getAttributes().att().keys())) {
-            tags.put(a._1.key(), p);
-        }
+  @Inject
+  public Context() {}
+
+  /**
+   * Represents a map from all Klabels or attributes in string representation to sets of
+   * corresponding productions.
+   */
+  public SetMultimap tags = HashMultimap.create();
+
+  // TODO(dwightguth): remove these fields and replace with injected dependencies
+  @Deprecated @Inject public transient GlobalOptions globalOptions;
+  public KompileOptions kompileOptions;
+
+  public void addProduction(Production p) {
+    if (p.containsAttribute(Att.GROUP())) {
+      throw new AssertionError(
+          "Must call ExpandGroupAttribute.apply(Definition) before creating a Context.");
+    }
+
+    if (p.getKLabel(false) != null) {
+      tags.put(p.getKLabel(false), p);
+    } else if (p.getAttributes().contains(Att.BRACKET())) {
+      tags.put(p.getBracketLabel(false), p);
+    }
+    for (Tuple2 a : iterable(p.getAttributes().att().keys())) {
+      tags.put(a._1.key(), p);
     }
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/BackendModule.java b/kernel/src/main/java/org/kframework/kompile/BackendModule.java
index 5425cabee5c..5b04657ba3b 100644
--- a/kernel/src/main/java/org/kframework/kompile/BackendModule.java
+++ b/kernel/src/main/java/org/kframework/kompile/BackendModule.java
@@ -4,29 +4,29 @@
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.multibindings.MapBinder;
+import java.util.Map;
 import org.kframework.backend.kore.KoreBackend;
 import org.kframework.compile.Backend;
 import org.kframework.utils.errorsystem.KEMException;
 import org.kframework.utils.errorsystem.KExceptionManager;
 
-import java.util.Map;
-
 public class BackendModule extends AbstractModule {
-    @Override
-    protected void configure() {
-        binder().requireAtInjectOnConstructors();
-        MapBinder backendBinder = MapBinder.newMapBinder(
-                binder(), String.class, org.kframework.compile.Backend.class);
-        backendBinder.addBinding("kore").to(KoreBackend.class);
-    }
+  @Override
+  protected void configure() {
+    binder().requireAtInjectOnConstructors();
+    MapBinder backendBinder =
+        MapBinder.newMapBinder(binder(), String.class, org.kframework.compile.Backend.class);
+    backendBinder.addBinding("kore").to(KoreBackend.class);
+  }
 
-    @Provides
-    org.kframework.compile.Backend getKoreBackend(KompileOptions options, Map map, KExceptionManager kem) {
-        org.kframework.compile.Backend backend = map.get(options.backend);
-        if (backend == null) {
-            throw KEMException.criticalError("Invalid backend: " + options.backend
-                    + ". It should be one of " + map.keySet());
-        }
-        return backend;
+  @Provides
+  org.kframework.compile.Backend getKoreBackend(
+      KompileOptions options, Map map, KExceptionManager kem) {
+    org.kframework.compile.Backend backend = map.get(options.backend);
+    if (backend == null) {
+      throw KEMException.criticalError(
+          "Invalid backend: " + options.backend + ". It should be one of " + map.keySet());
     }
+    return backend;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/CompiledDefinition.java b/kernel/src/main/java/org/kframework/kompile/CompiledDefinition.java
index a7f045feaab..1d6242aacc9 100644
--- a/kernel/src/main/java/org/kframework/kompile/CompiledDefinition.java
+++ b/kernel/src/main/java/org/kframework/kompile/CompiledDefinition.java
@@ -1,6 +1,17 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kompile;
 
+import static org.kframework.Collections.*;
+import static org.kframework.definition.Constructors.*;
+import static org.kframework.kore.KORE.*;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 import org.kframework.Collections;
 import org.kframework.attributes.Att;
 import org.kframework.attributes.Source;
@@ -23,204 +34,260 @@
 import org.kframework.parser.inner.ParseInModule;
 import org.kframework.parser.inner.RuleGrammarGenerator;
 import org.kframework.parser.outer.Outer;
+import org.kframework.utils.StringUtil;
 import org.kframework.utils.errorsystem.KEMException;
 import org.kframework.utils.errorsystem.KExceptionManager;
 import org.kframework.utils.file.FileUtil;
-import org.kframework.utils.StringUtil;
 import org.kframework.utils.options.InnerParsingOptions;
 import org.kframework.utils.options.OuterParsingOptions;
 import scala.Option;
 import scala.Tuple2;
 import scala.util.Either;
 
-import java.io.Serializable;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-import static org.kframework.Collections.*;
-import static org.kframework.definition.Constructors.*;
-import static org.kframework.kore.KORE.*;
-
 /**
- * A class representing a compiled definition. It has everything needed for executing and parsing programs.
+ * A class representing a compiled definition. It has everything needed for executing and parsing
+ * programs.
  */
-
 public class CompiledDefinition implements Serializable {
-    public final KompileOptions kompileOptions;
-    private final OuterParsingOptions outerParsingOptions;
-    private transient final GlobalOptions globalOptions;
-    private final InnerParsingOptions innerParsingOptions;
-    private final Definition parsedDefinition;
-    public final Definition kompiledDefinition;
-    public final Sort programStartSymbol;
-    public final HashMap configurationVariableDefaultSorts = new HashMap<>();
-    public final KLabel topCellInitializer;
-    private final Module languageParsingModule;
-    private final Map cachedcompiledPatterns = new ConcurrentHashMap<>();
-    private final Map cachedParsedPatterns = new ConcurrentHashMap<>();
-
-
-    public CompiledDefinition(KompileOptions kompileOptions, OuterParsingOptions outerParsingOptions, InnerParsingOptions innerParsingOptions, GlobalOptions globalOptions, Definition parsedDefinition, Definition kompiledDefinition, FileUtil files, KExceptionManager kem, KLabel topCellInitializer) {
-        this.kompileOptions = kompileOptions;
-        this.outerParsingOptions = outerParsingOptions;
-        this.innerParsingOptions = innerParsingOptions;
-        this.globalOptions = globalOptions;
-        this.parsedDefinition = parsedDefinition;
-        this.kompiledDefinition = kompiledDefinition;
-        initializeConfigurationVariableDefaultSorts(files);
-        this.programStartSymbol = configurationVariableDefaultSorts.getOrDefault("$PGM", Sorts.K());
-        this.topCellInitializer = topCellInitializer;
-        this.languageParsingModule = kompiledDefinition.getModule("LANGUAGE-PARSING").get();
-    }
+  public final KompileOptions kompileOptions;
+  private final OuterParsingOptions outerParsingOptions;
+  private final transient GlobalOptions globalOptions;
+  private final InnerParsingOptions innerParsingOptions;
+  private final Definition parsedDefinition;
+  public final Definition kompiledDefinition;
+  public final Sort programStartSymbol;
+  public final HashMap configurationVariableDefaultSorts = new HashMap<>();
+  public final KLabel topCellInitializer;
+  private final Module languageParsingModule;
+  private final Map cachedcompiledPatterns = new ConcurrentHashMap<>();
+  private final Map cachedParsedPatterns = new ConcurrentHashMap<>();
 
-    private Rule getExitCodeRule(Definition parsedDefinition) {
-        Module mainMod = parsedDefinition.mainModule();
-        Set exitProds = stream(mainMod.productions()).filter(p -> p.att().contains(Att.EXIT())).collect(Collectors.toSet());
-        if (exitProds.size() == 0) {
-            return null;
-        } else if (exitProds.size() > 1) {
-            throw KEMException.compilerError("Found more than one or zero productions with 'exit' attribute. Exactly one production, a cell, must have this attribute, designating the exit code of krun. Found:\n" + exitProds);
-        }
-        Production exitProd = exitProds.iterator().next();
-        return Rule(IncompleteCellUtils.make(exitProd.klabel().get(), false, KApply(KLabel("#SemanticCastToInt"), KVariable("_")), false), BooleanUtils.TRUE, BooleanUtils.TRUE);
+  public CompiledDefinition(
+      KompileOptions kompileOptions,
+      OuterParsingOptions outerParsingOptions,
+      InnerParsingOptions innerParsingOptions,
+      GlobalOptions globalOptions,
+      Definition parsedDefinition,
+      Definition kompiledDefinition,
+      FileUtil files,
+      KExceptionManager kem,
+      KLabel topCellInitializer) {
+    this.kompileOptions = kompileOptions;
+    this.outerParsingOptions = outerParsingOptions;
+    this.innerParsingOptions = innerParsingOptions;
+    this.globalOptions = globalOptions;
+    this.parsedDefinition = parsedDefinition;
+    this.kompiledDefinition = kompiledDefinition;
+    initializeConfigurationVariableDefaultSorts(files);
+    this.programStartSymbol = configurationVariableDefaultSorts.getOrDefault("$PGM", Sorts.K());
+    this.topCellInitializer = topCellInitializer;
+    this.languageParsingModule = kompiledDefinition.getModule("LANGUAGE-PARSING").get();
+  }
+
+  private Rule getExitCodeRule(Definition parsedDefinition) {
+    Module mainMod = parsedDefinition.mainModule();
+    Set exitProds =
+        stream(mainMod.productions())
+            .filter(p -> p.att().contains(Att.EXIT()))
+            .collect(Collectors.toSet());
+    if (exitProds.size() == 0) {
+      return null;
+    } else if (exitProds.size() > 1) {
+      throw KEMException.compilerError(
+          "Found more than one or zero productions with 'exit' attribute. Exactly one production, a"
+              + " cell, must have this attribute, designating the exit code of krun. Found:\n"
+              + exitProds);
     }
+    Production exitProd = exitProds.iterator().next();
+    return Rule(
+        IncompleteCellUtils.make(
+            exitProd.klabel().get(),
+            false,
+            KApply(KLabel("#SemanticCastToInt"), KVariable("_")),
+            false),
+        BooleanUtils.TRUE,
+        BooleanUtils.TRUE);
+  }
 
-    private void initializeConfigurationVariableDefaultSorts(FileUtil files) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("#!/usr/bin/env bash\n\n");
-        StringBuilder arr = new StringBuilder("declaredConfigVars=(\n");
-        // searching for #SemanticCastTo(Map:lookup(_, #token(, KConfigVar)))
-        Collections.stream(kompiledDefinition.mainModule().rules())
-                .forEach(r -> {
-                    new VisitK() {
-                        @Override
-                        public void apply(KApply k) {
-                            if (k.klabel().name().startsWith("project:")
-                                    && k.items().size() == 1 && k.items().get(0) instanceof KApply theMapLookup) {
-                                if (KLabels.MAP_LOOKUP.equals(theMapLookup.klabel())
-                                        && theMapLookup.size() == 2 && theMapLookup.items().get(1) instanceof KToken t) {
-                                    if (t.sort().equals(Sorts.KConfigVar())) {
-                                        Sort sort = Outer.parseSort(k.klabel().name().substring("project:".length()));
-                                        configurationVariableDefaultSorts.put(t.s(), sort);
-                                        if (sort.equals(Sorts.K())) {
-                                          sort = Sorts.KItem();
-                                        }
-                                        String str = "declaredConfigVar_" + t.s().substring(1) + "='" + sort.toString() + "'\n";
-                                        sb.append(str);
-                                        String astr = "    '" + t.s().substring(1) + "'\n";
-                                        arr.append(astr);
-                                    }
-                                }
-                            }
-                            super.apply(k);
+  private void initializeConfigurationVariableDefaultSorts(FileUtil files) {
+    StringBuilder sb = new StringBuilder();
+    sb.append("#!/usr/bin/env bash\n\n");
+    StringBuilder arr = new StringBuilder("declaredConfigVars=(\n");
+    // searching for #SemanticCastTo(Map:lookup(_, #token(, KConfigVar)))
+    Collections.stream(kompiledDefinition.mainModule().rules())
+        .forEach(
+            r -> {
+              new VisitK() {
+                @Override
+                public void apply(KApply k) {
+                  if (k.klabel().name().startsWith("project:")
+                      && k.items().size() == 1
+                      && k.items().get(0) instanceof KApply theMapLookup) {
+                    if (KLabels.MAP_LOOKUP.equals(theMapLookup.klabel())
+                        && theMapLookup.size() == 2
+                        && theMapLookup.items().get(1) instanceof KToken t) {
+                      if (t.sort().equals(Sorts.KConfigVar())) {
+                        Sort sort =
+                            Outer.parseSort(k.klabel().name().substring("project:".length()));
+                        configurationVariableDefaultSorts.put(t.s(), sort);
+                        if (sort.equals(Sorts.K())) {
+                          sort = Sorts.KItem();
                         }
-                    }.apply(r.body());
-                });
-        sb.append(arr);
-        sb.append(")\n");
-
-        for (Production prod : iterable(kompiledDefinition.mainModule().productions())) {
-            if (prod.att().contains(Att.CELL()) && prod.att().contains(Att.PARSER())) {
-                String att = prod.att().get(Att.PARSER());
-                String[][] parts = StringUtil.splitTwoDimensionalAtt(att);
-                for (String[] part : parts) {
-                    if (part.length != 2) {
-                        throw KEMException.compilerError("Invalid value for parser attribute: " + att, prod);
+                        String str =
+                            "declaredConfigVar_"
+                                + t.s().substring(1)
+                                + "='"
+                                + sort.toString()
+                                + "'\n";
+                        sb.append(str);
+                        String astr = "    '" + t.s().substring(1) + "'\n";
+                        arr.append(astr);
+                      }
                     }
-                    String name = part[0];
-                    String module = part[1];
-                    sb.append("declaredConfigVarModule_" + name + "='" + module + "'\n");
+                  }
+                  super.apply(k);
                 }
-            }
-        }
+              }.apply(r.body());
+            });
+    sb.append(arr);
+    sb.append(")\n");
 
-        files.saveToKompiled("configVars.sh", sb.toString());
+    for (Production prod : iterable(kompiledDefinition.mainModule().productions())) {
+      if (prod.att().contains(Att.CELL()) && prod.att().contains(Att.PARSER())) {
+        String att = prod.att().get(Att.PARSER());
+        String[][] parts = StringUtil.splitTwoDimensionalAtt(att);
+        for (String[] part : parts) {
+          if (part.length != 2) {
+            throw KEMException.compilerError("Invalid value for parser attribute: " + att, prod);
+          }
+          String name = part[0];
+          String module = part[1];
+          sb.append("declaredConfigVarModule_" + name + "='" + module + "'\n");
+        }
+      }
     }
 
-    /**
-     * The parsed but uncompiled definition
-     */
-    public Definition getParsedDefinition() {
-        return parsedDefinition;
-    }
+    files.saveToKompiled("configVars.sh", sb.toString());
+  }
 
-    /**
-     * A module containing the compiled definition
-     */
-    public Module executionModule() {
-        return kompiledDefinition.mainModule();
-    }
+  /** The parsed but uncompiled definition */
+  public Definition getParsedDefinition() {
+    return parsedDefinition;
+  }
 
-    public String mainSyntaxModuleName() { return parsedDefinition.att().getOptional(Att.SYNTAX_MODULE()).get(); }
-
-    /**
-     * @return the module used for generating the program (i.e. ground) parser for the module named moduleName
-     * It automatically generates this module unless the user has already defined a module postfixed with
-     * {@link RuleGrammarGenerator#POSTFIX}. In latter case, it uses the user-defined module.
-     */
-    public Option programParsingModuleFor(String moduleName, KExceptionManager kem) {
-        RuleGrammarGenerator gen = new RuleGrammarGenerator(parsedDefinition);
-
-        Option userProgramParsingModule = parsedDefinition.getModule(moduleName + RuleGrammarGenerator.POSTFIX);
-        if (userProgramParsingModule.isDefined()) {
-            return userProgramParsingModule;
-        } else {
-            Option moduleOption = parsedDefinition.getModule(moduleName);
-            Option programParsingModuleOption = moduleOption.isDefined() ?
-                    Option.apply(gen.getProgramsGrammar(moduleOption.get())) :
-                    Option.empty();
-            return programParsingModuleOption;
-        }
-    }
+  /** A module containing the compiled definition */
+  public Module executionModule() {
+    return kompiledDefinition.mainModule();
+  }
 
-    public Option ruleParsingModuleFor(String moduleName) {
-        RuleGrammarGenerator gen = new RuleGrammarGenerator(kompiledDefinition);
+  public String mainSyntaxModuleName() {
+    return parsedDefinition.att().getOptional(Att.SYNTAX_MODULE()).get();
+  }
 
-        Option moduleOption = kompiledDefinition.getModule(moduleName);
-        if (!moduleOption.isDefined())
-            return Option.empty();
-        return Option.apply(gen.getRuleGrammar(moduleOption.get()));
-    }
+  /**
+   * @return the module used for generating the program (i.e. ground) parser for the module named
+   *     moduleName It automatically generates this module unless the user has already defined a
+   *     module postfixed with {@link RuleGrammarGenerator#POSTFIX}. In latter case, it uses the
+   *     user-defined module.
+   */
+  public Option programParsingModuleFor(String moduleName, KExceptionManager kem) {
+    RuleGrammarGenerator gen = new RuleGrammarGenerator(parsedDefinition);
 
-    public Module languageParsingModule() { return languageParsingModule; }
-
-    /**
-     * Creates a parser for a module and use it to parse a term.
-     *
-     * @return the parsed term.
-     */
-
-    public K parseSingleTerm(Module module, Sort programStartSymbol, String startSymbolLocation, KExceptionManager kem, FileUtil files, String s, Source source, boolean partialParseDebug) {
-        try (ParseInModule parseInModule = RuleGrammarGenerator.getCombinedGrammar(module, true, files, partialParseDebug)) {
-            Tuple2, K>, Set> res = parseInModule.parseString(s, programStartSymbol, startSymbolLocation, source);
-            kem.addAllKException(res._2().stream().map(e -> e.getKException()).collect(Collectors.toSet()));
-            if (res._1().isLeft()) {
-                throw res._1().left().get().iterator().next();
-            }
-            return new TreeNodesToKORE(Outer::parseSort, true).down(res._1().right().get());
-        }
+    Option userProgramParsingModule =
+        parsedDefinition.getModule(moduleName + RuleGrammarGenerator.POSTFIX);
+    if (userProgramParsingModule.isDefined()) {
+      return userProgramParsingModule;
+    } else {
+      Option moduleOption = parsedDefinition.getModule(moduleName);
+      Option programParsingModuleOption =
+          moduleOption.isDefined()
+              ? Option.apply(gen.getProgramsGrammar(moduleOption.get()))
+              : Option.empty();
+      return programParsingModuleOption;
     }
+  }
 
-    public String showTokens(Module module, FileUtil files, String s, Source source) {
-        try (ParseInModule parseInModule = RuleGrammarGenerator.getCombinedGrammar(module, true, files)) {
-            return parseInModule.tokenizeString(s, source);
-        }
-    }
+  public Option ruleParsingModuleFor(String moduleName) {
+    RuleGrammarGenerator gen = new RuleGrammarGenerator(kompiledDefinition);
 
-    public Module getExtensionModule(Module module, FileUtil files) {
-        return RuleGrammarGenerator.getCombinedGrammar(module, true, files).getExtensionModule();
-    }
+    Option moduleOption = kompiledDefinition.getModule(moduleName);
+    if (!moduleOption.isDefined()) return Option.empty();
+    return Option.apply(gen.getRuleGrammar(moduleOption.get()));
+  }
+
+  public Module languageParsingModule() {
+    return languageParsingModule;
+  }
 
-    public Rule compilePatternIfAbsent(FileUtil files, KExceptionManager kem, String pattern, Source source) {
-        return cachedcompiledPatterns.computeIfAbsent(pattern, p -> new Kompile(kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, files, kem).parseAndCompileRule(this, p, source,
-                Optional.of(parsePatternIfAbsent(files, kem, pattern, source))));
+  /**
+   * Creates a parser for a module and use it to parse a term.
+   *
+   * @return the parsed term.
+   */
+  public K parseSingleTerm(
+      Module module,
+      Sort programStartSymbol,
+      String startSymbolLocation,
+      KExceptionManager kem,
+      FileUtil files,
+      String s,
+      Source source,
+      boolean partialParseDebug) {
+    try (ParseInModule parseInModule =
+        RuleGrammarGenerator.getCombinedGrammar(module, true, files, partialParseDebug)) {
+      Tuple2, K>, Set> res =
+          parseInModule.parseString(s, programStartSymbol, startSymbolLocation, source);
+      kem.addAllKException(
+          res._2().stream().map(e -> e.getKException()).collect(Collectors.toSet()));
+      if (res._1().isLeft()) {
+        throw res._1().left().get().iterator().next();
+      }
+      return new TreeNodesToKORE(Outer::parseSort, true).down(res._1().right().get());
     }
+  }
 
-    public Rule parsePatternIfAbsent(FileUtil files, KExceptionManager kem, String pattern, Source source) {
-        return cachedParsedPatterns.computeIfAbsent(pattern, p -> new Kompile(kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, files, kem).parseRule(this, p, source));
+  public String showTokens(Module module, FileUtil files, String s, Source source) {
+    try (ParseInModule parseInModule =
+        RuleGrammarGenerator.getCombinedGrammar(module, true, files)) {
+      return parseInModule.tokenizeString(s, source);
     }
+  }
+
+  public Module getExtensionModule(Module module, FileUtil files) {
+    return RuleGrammarGenerator.getCombinedGrammar(module, true, files).getExtensionModule();
+  }
+
+  public Rule compilePatternIfAbsent(
+      FileUtil files, KExceptionManager kem, String pattern, Source source) {
+    return cachedcompiledPatterns.computeIfAbsent(
+        pattern,
+        p ->
+            new Kompile(
+                    kompileOptions,
+                    outerParsingOptions,
+                    innerParsingOptions,
+                    globalOptions,
+                    files,
+                    kem)
+                .parseAndCompileRule(
+                    this,
+                    p,
+                    source,
+                    Optional.of(parsePatternIfAbsent(files, kem, pattern, source))));
+  }
+
+  public Rule parsePatternIfAbsent(
+      FileUtil files, KExceptionManager kem, String pattern, Source source) {
+    return cachedParsedPatterns.computeIfAbsent(
+        pattern,
+        p ->
+            new Kompile(
+                    kompileOptions,
+                    outerParsingOptions,
+                    innerParsingOptions,
+                    globalOptions,
+                    files,
+                    kem)
+                .parseRule(this, p, source));
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/DefinitionParsing.java b/kernel/src/main/java/org/kframework/kompile/DefinitionParsing.java
index 9134b70efe3..9c3d537ea02 100644
--- a/kernel/src/main/java/org/kframework/kompile/DefinitionParsing.java
+++ b/kernel/src/main/java/org/kframework/kompile/DefinitionParsing.java
@@ -1,8 +1,27 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kompile;
 
+import static org.kframework.Collections.*;
+import static org.kframework.builtin.KLabels.*;
+import static org.kframework.definition.Constructors.*;
+import static org.kframework.definition.Constructors.Module;
+import static org.kframework.kore.KORE.*;
+
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.apache.commons.collections4.ListUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.kframework.Collections;
@@ -53,643 +72,937 @@
 import scala.collection.Set;
 import scala.util.Either;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static org.kframework.Collections.*;
-import static org.kframework.builtin.KLabels.*;
-import static org.kframework.definition.Constructors.Module;
-import static org.kframework.definition.Constructors.*;
-import static org.kframework.kore.KORE.*;
-
 /**
- * A bundle of code doing various aspects of definition parsing.
- * TODO: In major need of refactoring.
- * @cos refactored this code out of Kompile but none (or close to none) of it was originally written by him.
+ * A bundle of code doing various aspects of definition parsing. TODO: In major need of refactoring.
+ *
+ * @cos refactored this code out of Kompile but none (or close to none) of it was originally written
+ *     by him.
  */
 public class DefinitionParsing {
-    public static final Sort START_SYMBOL = Sorts.RuleContent();
-    public static final String rule = "rule";
-    public static final String claim = "claim";
-    public static final String configuration = "config";
-    public static final String alias = "alias";
-    public static final String context = "context";
-    private final File cacheFile;
-    private final boolean autoImportDomains;
-    private final KompileOptions options;
-    private final GlobalOptions globalOptions;
-    private final OuterParsingOptions outerParsingOptions;
-
-    private final KExceptionManager kem;
-    private final FileUtil files;
-    private final ParserUtils parser;
-    private final boolean cacheParses;
-    private final BinaryLoader loader;
-    private final Stopwatch sw;
-
-    public final AtomicInteger parsedBubbles = new AtomicInteger(0);
-    public final AtomicInteger cachedBubbles = new AtomicInteger(0);
-    private final boolean profileRules;
-    private final List lookupDirectories;
-    private final InnerParsingOptions innerParsingOptions;
-
-    public DefinitionParsing(
-            List lookupDirectories,
-            KompileOptions options,
-            OuterParsingOptions outerParsingOptions,
-            InnerParsingOptions innerParsingOptions,
-            GlobalOptions globalOptions,
-            KExceptionManager kem,
-            FileUtil files,
-            ParserUtils parser,
-            boolean cacheParses,
-            File cacheFile,
-            Stopwatch sw) {
-        this.lookupDirectories = lookupDirectories;
-        this.options = options;
-        this.globalOptions = globalOptions;
-        this.outerParsingOptions = outerParsingOptions;
-        this.innerParsingOptions = innerParsingOptions;
-        this.kem = kem;
-        this.files = files;
-        this.parser = parser;
-        this.cacheParses = cacheParses;
-        this.cacheFile = cacheFile;
-        this.autoImportDomains = !outerParsingOptions.noPrelude;
-        this.loader = new BinaryLoader(this.kem);
-        this.profileRules = innerParsingOptions.profileRules != null;
-        this.sw = sw;
+  public static final Sort START_SYMBOL = Sorts.RuleContent();
+  public static final String rule = "rule";
+  public static final String claim = "claim";
+  public static final String configuration = "config";
+  public static final String alias = "alias";
+  public static final String context = "context";
+  private final File cacheFile;
+  private final boolean autoImportDomains;
+  private final KompileOptions options;
+  private final GlobalOptions globalOptions;
+  private final OuterParsingOptions outerParsingOptions;
+
+  private final KExceptionManager kem;
+  private final FileUtil files;
+  private final ParserUtils parser;
+  private final boolean cacheParses;
+  private final BinaryLoader loader;
+  private final Stopwatch sw;
+
+  public final AtomicInteger parsedBubbles = new AtomicInteger(0);
+  public final AtomicInteger cachedBubbles = new AtomicInteger(0);
+  private final boolean profileRules;
+  private final List lookupDirectories;
+  private final InnerParsingOptions innerParsingOptions;
+
+  public DefinitionParsing(
+      List lookupDirectories,
+      KompileOptions options,
+      OuterParsingOptions outerParsingOptions,
+      InnerParsingOptions innerParsingOptions,
+      GlobalOptions globalOptions,
+      KExceptionManager kem,
+      FileUtil files,
+      ParserUtils parser,
+      boolean cacheParses,
+      File cacheFile,
+      Stopwatch sw) {
+    this.lookupDirectories = lookupDirectories;
+    this.options = options;
+    this.globalOptions = globalOptions;
+    this.outerParsingOptions = outerParsingOptions;
+    this.innerParsingOptions = innerParsingOptions;
+    this.kem = kem;
+    this.files = files;
+    this.parser = parser;
+    this.cacheParses = cacheParses;
+    this.cacheFile = cacheFile;
+    this.autoImportDomains = !outerParsingOptions.noPrelude;
+    this.loader = new BinaryLoader(this.kem);
+    this.profileRules = innerParsingOptions.profileRules != null;
+    this.sw = sw;
+  }
+
+  public java.util.Set parseModules(
+      CompiledDefinition definition,
+      String mainModule,
+      String entryPointModule,
+      File definitionFile,
+      java.util.Set excludeModules,
+      boolean readOnlyCache,
+      boolean useCachedScanner) {
+    Definition def =
+        parser.loadDefinition(
+            mainModule,
+            mutable(definition.getParsedDefinition().modules()),
+            FileUtil.load(definitionFile),
+            Source.apply(definitionFile.getAbsolutePath()),
+            definitionFile.getParentFile(),
+            ListUtils.union(Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), lookupDirectories),
+            options.preprocess,
+            options.bisonLists);
+
+    if (!def.getModule(mainModule).isDefined()) {
+      throw KEMException.criticalError("Module " + mainModule + " does not exist.");
     }
-
-    public java.util.Set parseModules(CompiledDefinition definition, String mainModule, String entryPointModule, File definitionFile, java.util.Set excludeModules, boolean readOnlyCache, boolean useCachedScanner) {
-        Definition def = parser.loadDefinition(
-                mainModule,
-                mutable(definition.getParsedDefinition().modules()),
-                FileUtil.load(definitionFile),
-                Source.apply(definitionFile.getAbsolutePath()),
-                definitionFile.getParentFile(),
-                ListUtils.union(Lists.newArrayList(Kompile.BUILTIN_DIRECTORY),
-                  lookupDirectories),
-                options.preprocess,
-                options.bisonLists);
-
-        if (!def.getModule(mainModule).isDefined()) {
-          throw KEMException.criticalError("Module " + mainModule + " does not exist.");
-        }
-        if (!def.getModule(entryPointModule).isDefined()) {
-          throw KEMException.criticalError("Module " + entryPointModule + " does not exist.");
-        }
-        if (profileRules) // create the temp dir ahead of parsing to avoid a race condition
-            files.resolveTemp(".");
-        Stream modules = Stream.of(def.getModule(mainModule).get());
-        modules = Stream.concat(modules, stream(def.getModule(mainModule).get().importedModules()));
-        modules = Stream.concat(modules, Stream.of(def.getModule(entryPointModule).get()));
-        modules = Stream.concat(modules, stream(def.getModule(entryPointModule).get().importedModules()));
-        modules = Stream.concat(modules,
-                stream(def.entryModules()).filter(m -> stream(m.sentences()).noneMatch(s -> s instanceof Bubble)));
-        def = Definition(def.mainModule(), modules.collect(Collections.toSet()), def.att());
-
-        def = Kompile.excludeModulesByTag(excludeModules, entryPointModule).apply(def);
-        sw.printIntermediate("Outer parsing [" + def.modules().size() + " modules]");
-
-        errors = java.util.Collections.synchronizedSet(Sets.newHashSet());
-        caches = loadCaches();
-
-        try {
-          def = resolveConfigBubbles(def);
-        } catch (KEMException e) {
-            errors.add(e);
-            throwExceptionIfThereAreErrors();
-            throw new AssertionError("should not reach this statement");
-        }
-
-        def = resolveNonConfigBubbles(def, false, useCachedScanner);
-        saveTimings();
-        if (! readOnlyCache) {
-            saveCaches();
-        }
-        throwExceptionIfThereAreErrors();
-        return mutable(def.entryModules());
+    if (!def.getModule(entryPointModule).isDefined()) {
+      throw KEMException.criticalError("Module " + entryPointModule + " does not exist.");
     }
-
-    public Map loadCaches() {
-        Map result;
-        //noinspection unchecked
-        result = cacheParses ? loader.loadCache(Map.class, cacheFile) : null;
-        if (result == null) {
-            result = new HashMap<>();
-        }
-        return result;
+    if (profileRules) // create the temp dir ahead of parsing to avoid a race condition
+    files.resolveTemp(".");
+    Stream modules = Stream.of(def.getModule(mainModule).get());
+    modules = Stream.concat(modules, stream(def.getModule(mainModule).get().importedModules()));
+    modules = Stream.concat(modules, Stream.of(def.getModule(entryPointModule).get()));
+    modules =
+        Stream.concat(modules, stream(def.getModule(entryPointModule).get().importedModules()));
+    modules =
+        Stream.concat(
+            modules,
+            stream(def.entryModules())
+                .filter(m -> stream(m.sentences()).noneMatch(s -> s instanceof Bubble)));
+    def = Definition(def.mainModule(), modules.collect(Collections.toSet()), def.att());
+
+    def = Kompile.excludeModulesByTag(excludeModules, entryPointModule).apply(def);
+    sw.printIntermediate("Outer parsing [" + def.modules().size() + " modules]");
+
+    errors = java.util.Collections.synchronizedSet(Sets.newHashSet());
+    caches = loadCaches();
+
+    try {
+      def = resolveConfigBubbles(def);
+    } catch (KEMException e) {
+      errors.add(e);
+      throwExceptionIfThereAreErrors();
+      throw new AssertionError("should not reach this statement");
     }
 
-    private void saveCachesAndReportParsingErrors() {
-        saveCaches();
-        throwExceptionIfThereAreErrors();
+    def = resolveNonConfigBubbles(def, false, useCachedScanner);
+    saveTimings();
+    if (!readOnlyCache) {
+      saveCaches();
     }
-
-    private void saveCaches() {
-        if (cacheParses) {
-            loader.saveOrDie(cacheFile, caches);
-        }
+    throwExceptionIfThereAreErrors();
+    return mutable(def.entryModules());
+  }
+
+  public Map loadCaches() {
+    Map result;
+    //noinspection unchecked
+    result = cacheParses ? loader.loadCache(Map.class, cacheFile) : null;
+    if (result == null) {
+      result = new HashMap<>();
     }
+    return result;
+  }
 
-    public Definition parseDefinitionAndResolveBubbles(File definitionFile, String mainModuleName, String mainProgramsModule, java.util.Set excludedModuleTags) {
-        Definition parsedDefinition = parseDefinition(definitionFile, mainModuleName, mainProgramsModule);
-        Stream modules = Stream.of(parsedDefinition.mainModule());
-        modules = Stream.concat(modules, stream(parsedDefinition.mainModule().importedModules()));
-        Option syntaxModule = parsedDefinition.getModule(mainProgramsModule);
-        if (syntaxModule.isDefined()) {
-            modules = Stream.concat(modules, Stream.of(syntaxModule.get()));
-            modules = Stream.concat(modules, stream(syntaxModule.get().importedModules()));
-        }
-        modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("K-REFLECTION").get()));
-        modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("STDIN-STREAM").get()));
-        modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("STDOUT-STREAM").get()));
-        modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("MAP").get()));
-        modules = Stream.concat(modules,
-                stream(parsedDefinition.entryModules()).filter(m -> stream(m.sentences()).noneMatch(s -> s instanceof Bubble)));
-        Definition trimmed = Definition(parsedDefinition.mainModule(), modules.collect(Collections.toSet()),
-                parsedDefinition.att());
-        trimmed = Kompile.excludeModulesByTag(excludedModuleTags, mainProgramsModule).apply(trimmed);
-        sw.printIntermediate("Outer parsing [" + trimmed.modules().size() + " modules]");
-        if (profileRules) // create the temp dir ahead of parsing to avoid a race condition
-            files.resolveTemp(".");
-        Definition afterResolvingConfigBubbles = resolveConfigBubbles(trimmed, parsedDefinition.getModule("DEFAULT-CONFIGURATION").get());
-        sw.printIntermediate("Parse configurations [" + parsedBubbles.get() + "/" + (parsedBubbles.get() + cachedBubbles.get()) + " declarations]");
-        parsedBubbles.set(0);
-        cachedBubbles.set(0);
-        Definition afterResolvingAllOtherBubbles = resolveNonConfigBubbles(afterResolvingConfigBubbles, true, false);
-        sw.printIntermediate("Parse rules [" + parsedBubbles.get() + "/" + (parsedBubbles.get() + cachedBubbles.get()) + " rules]");
-        saveTimings();
-        saveCachesAndReportParsingErrors();
-        return afterResolvingAllOtherBubbles;
-    }
+  private void saveCachesAndReportParsingErrors() {
+    saveCaches();
+    throwExceptionIfThereAreErrors();
+  }
 
-    private void throwExceptionIfThereAreErrors() {
-        if (!errors.isEmpty()) {
-            kem.addAllKException(errors.stream().map(e -> e.exception).collect(Collectors.toList()));
-            throw KEMException.compilerError("Had " + errors.size() + " parsing errors.");
-        }
+  private void saveCaches() {
+    if (cacheParses) {
+      loader.saveOrDie(cacheFile, caches);
     }
-
-    public Definition parseDefinition(File definitionFile, String mainModuleName, String mainProgramsModule) {
-        Definition definition = parser.loadDefinition(
-                mainModuleName,
-                mainProgramsModule, FileUtil.load(definitionFile),
-                definitionFile,
-                definitionFile.getParentFile(),
-                ListUtils.union(lookupDirectories,
-                        Lists.newArrayList(Kompile.BUILTIN_DIRECTORY)),
-                autoImportDomains,
-                options.preprocess,
-                options.bisonLists);
-        Module m = definition.mainModule();
-        return options.coverage ? DefinitionTransformer.from(mod -> mod.equals(m) ? Module(m.name(), (Set)m.imports().$bar(Set(Import(definition.getModule("K-IO").get(), true))), m.localSentences(), m.att()) : mod, "add implicit modules").apply(definition) : definition;
+  }
+
+  public Definition parseDefinitionAndResolveBubbles(
+      File definitionFile,
+      String mainModuleName,
+      String mainProgramsModule,
+      java.util.Set excludedModuleTags) {
+    Definition parsedDefinition =
+        parseDefinition(definitionFile, mainModuleName, mainProgramsModule);
+    Stream modules = Stream.of(parsedDefinition.mainModule());
+    modules = Stream.concat(modules, stream(parsedDefinition.mainModule().importedModules()));
+    Option syntaxModule = parsedDefinition.getModule(mainProgramsModule);
+    if (syntaxModule.isDefined()) {
+      modules = Stream.concat(modules, Stream.of(syntaxModule.get()));
+      modules = Stream.concat(modules, stream(syntaxModule.get().importedModules()));
     }
-
-    protected Definition resolveConfigBubbles(Definition definition, Module defaultConfiguration) {
-        Definition definitionWithConfigBubble = DefinitionTransformer.from(mod -> {
-            if (mod.name().equals(definition.mainModule().name())) {
-                boolean hasConfigDecl = stream(mod.sentences())
-                        .anyMatch(s -> s instanceof Bubble && ((Bubble) s).sentenceType().equals(configuration));
-                if (!hasConfigDecl) {
-                    return Module(mod.name(), mod.imports().$bar(Set(Import(defaultConfiguration, true))).seq(), mod.localSentences(), mod.att());
-                }
-            }
-            return mod;
-        }, "adding default configuration").apply(definition);
-
-        Module mapModule = definitionWithConfigBubble.getModule("MAP")
-                .getOrElse(() -> { throw KEMException.compilerError("Module MAP must be visible at the configuration declaration"); });
-        Definition definitionWithMapForConfig = DefinitionTransformer.from(mod -> {
-            boolean hasConfigDecl = stream(mod.localSentences())
-                    .anyMatch(s -> s instanceof Bubble && ((Bubble) s).sentenceType().equals(configuration));
-            if (hasConfigDecl) {
-                return Module(mod.name(), mod.imports().$bar(Set(Import(mapModule, true))).seq(), mod.localSentences(), mod.att());
-            }
-            return mod;
-        }, "adding MAP to modules with configs").apply(definitionWithConfigBubble);
-
-        errors = java.util.Collections.synchronizedSet(Sets.newHashSet());
-        caches = loadCaches();
-
-        Definition result;
-        try {
-            result = resolveConfigBubbles(definitionWithMapForConfig);
-        } catch (KEMException e) {
-            errors.add(e);
-            throwExceptionIfThereAreErrors();
-            throw new AssertionError("should not reach this statement");
-        }
-        throwExceptionIfThereAreErrors();
-        return result;
+    modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("K-REFLECTION").get()));
+    modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("STDIN-STREAM").get()));
+    modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("STDOUT-STREAM").get()));
+    modules = Stream.concat(modules, Stream.of(parsedDefinition.getModule("MAP").get()));
+    modules =
+        Stream.concat(
+            modules,
+            stream(parsedDefinition.entryModules())
+                .filter(m -> stream(m.sentences()).noneMatch(s -> s instanceof Bubble)));
+    Definition trimmed =
+        Definition(
+            parsedDefinition.mainModule(),
+            modules.collect(Collections.toSet()),
+            parsedDefinition.att());
+    trimmed = Kompile.excludeModulesByTag(excludedModuleTags, mainProgramsModule).apply(trimmed);
+    sw.printIntermediate("Outer parsing [" + trimmed.modules().size() + " modules]");
+    if (profileRules) // create the temp dir ahead of parsing to avoid a race condition
+    files.resolveTemp(".");
+    Definition afterResolvingConfigBubbles =
+        resolveConfigBubbles(trimmed, parsedDefinition.getModule("DEFAULT-CONFIGURATION").get());
+    sw.printIntermediate(
+        "Parse configurations ["
+            + parsedBubbles.get()
+            + "/"
+            + (parsedBubbles.get() + cachedBubbles.get())
+            + " declarations]");
+    parsedBubbles.set(0);
+    cachedBubbles.set(0);
+    Definition afterResolvingAllOtherBubbles =
+        resolveNonConfigBubbles(afterResolvingConfigBubbles, true, false);
+    sw.printIntermediate(
+        "Parse rules ["
+            + parsedBubbles.get()
+            + "/"
+            + (parsedBubbles.get() + cachedBubbles.get())
+            + " rules]");
+    saveTimings();
+    saveCachesAndReportParsingErrors();
+    return afterResolvingAllOtherBubbles;
+  }
+
+  private void throwExceptionIfThereAreErrors() {
+    if (!errors.isEmpty()) {
+      kem.addAllKException(errors.stream().map(e -> e.exception).collect(Collectors.toList()));
+      throw KEMException.compilerError("Had " + errors.size() + " parsing errors.");
     }
-
-    Map caches;
-    private java.util.Set errors;
-
-    public java.util.Set errors() {
-        return errors;
+  }
+
+  public Definition parseDefinition(
+      File definitionFile, String mainModuleName, String mainProgramsModule) {
+    Definition definition =
+        parser.loadDefinition(
+            mainModuleName,
+            mainProgramsModule,
+            FileUtil.load(definitionFile),
+            definitionFile,
+            definitionFile.getParentFile(),
+            ListUtils.union(lookupDirectories, Lists.newArrayList(Kompile.BUILTIN_DIRECTORY)),
+            autoImportDomains,
+            options.preprocess,
+            options.bisonLists);
+    Module m = definition.mainModule();
+    return options.coverage
+        ? DefinitionTransformer.from(
+                mod ->
+                    mod.equals(m)
+                        ? Module(
+                            m.name(),
+                            (Set)
+                                m.imports()
+                                    .$bar(Set(Import(definition.getModule("K-IO").get(), true))),
+                            m.localSentences(),
+                            m.att())
+                        : mod,
+                "add implicit modules")
+            .apply(definition)
+        : definition;
+  }
+
+  protected Definition resolveConfigBubbles(Definition definition, Module defaultConfiguration) {
+    Definition definitionWithConfigBubble =
+        DefinitionTransformer.from(
+                mod -> {
+                  if (mod.name().equals(definition.mainModule().name())) {
+                    boolean hasConfigDecl =
+                        stream(mod.sentences())
+                            .anyMatch(
+                                s ->
+                                    s instanceof Bubble
+                                        && ((Bubble) s).sentenceType().equals(configuration));
+                    if (!hasConfigDecl) {
+                      return Module(
+                          mod.name(),
+                          mod.imports().$bar(Set(Import(defaultConfiguration, true))).seq(),
+                          mod.localSentences(),
+                          mod.att());
+                    }
+                  }
+                  return mod;
+                },
+                "adding default configuration")
+            .apply(definition);
+
+    Module mapModule =
+        definitionWithConfigBubble
+            .getModule("MAP")
+            .getOrElse(
+                () -> {
+                  throw KEMException.compilerError(
+                      "Module MAP must be visible at the configuration declaration");
+                });
+    Definition definitionWithMapForConfig =
+        DefinitionTransformer.from(
+                mod -> {
+                  boolean hasConfigDecl =
+                      stream(mod.localSentences())
+                          .anyMatch(
+                              s ->
+                                  s instanceof Bubble
+                                      && ((Bubble) s).sentenceType().equals(configuration));
+                  if (hasConfigDecl) {
+                    return Module(
+                        mod.name(),
+                        mod.imports().$bar(Set(Import(mapModule, true))).seq(),
+                        mod.localSentences(),
+                        mod.att());
+                  }
+                  return mod;
+                },
+                "adding MAP to modules with configs")
+            .apply(definitionWithConfigBubble);
+
+    errors = java.util.Collections.synchronizedSet(Sets.newHashSet());
+    caches = loadCaches();
+
+    Definition result;
+    try {
+      result = resolveConfigBubbles(definitionWithMapForConfig);
+    } catch (KEMException e) {
+      errors.add(e);
+      throwExceptionIfThereAreErrors();
+      throw new AssertionError("should not reach this statement");
     }
-
-    private void checkConfigCells(Definition defWithParsedConfigs) {
-        // check for duplicate  cell declarations
-        List kcells = new ArrayList<>();
-        stream(defWithParsedConfigs.mainModule().sentences())
-                .filter(s -> s instanceof Configuration)
-                .forEach(s -> new VisitK() {
-                    @Override
-                    public void apply(KApply k) {
-                        if (k.klabel().equals(KLabel("#configCell"))) {
-                            KToken kt = (KToken) k.klist().items().get(0);
-                            assert kt.sort().equals(Sorts.CellName());
-                            if (kt.s().equals("k"))
-                                kcells.add(k);
-                            else if (kt.s().equals(GENERATED_TOP_CELL_NAME) || kt.s().equals(GENERATED_COUNTER_CELL_NAME)) {
-                                // check for definitions of generated cell names
-                                errors.add(KEMException.compilerError("Cell name <" + kt.s() + "> is reserved by K.", kt));
-                            }
-                        }
-                        super.apply(k);
+    throwExceptionIfThereAreErrors();
+    return result;
+  }
+
+  Map caches;
+  private java.util.Set errors;
+
+  public java.util.Set errors() {
+    return errors;
+  }
+
+  private void checkConfigCells(Definition defWithParsedConfigs) {
+    // check for duplicate  cell declarations
+    List kcells = new ArrayList<>();
+    stream(defWithParsedConfigs.mainModule().sentences())
+        .filter(s -> s instanceof Configuration)
+        .forEach(
+            s ->
+                new VisitK() {
+                  @Override
+                  public void apply(KApply k) {
+                    if (k.klabel().equals(KLabel("#configCell"))) {
+                      KToken kt = (KToken) k.klist().items().get(0);
+                      assert kt.sort().equals(Sorts.CellName());
+                      if (kt.s().equals("k")) kcells.add(k);
+                      else if (kt.s().equals(GENERATED_TOP_CELL_NAME)
+                          || kt.s().equals(GENERATED_COUNTER_CELL_NAME)) {
+                        // check for definitions of generated cell names
+                        errors.add(
+                            KEMException.compilerError(
+                                "Cell name <" + kt.s() + "> is reserved by K.", kt));
+                      }
                     }
+                    super.apply(k);
+                  }
                 }.apply(((Configuration) s).body()));
-        if (kcells.size() <= 1) {
-            return;
-        }
-        for (K kCellDecl: kcells) {
-            this.errors.add(KEMException.compilerError("Multiple K cell declarations detected. Only one  cell declaration is allowed.", kCellDecl));
-        }
-        throwExceptionIfThereAreErrors();
+    if (kcells.size() <= 1) {
+      return;
     }
-
-    private Definition resolveConfigBubbles(Definition def) {
-        Definition defWithCaches = resolveCachedBubbles(def, false);
-        RuleGrammarGenerator gen = new RuleGrammarGenerator(def);
-
-        // parse config bubbles in parallel
-        // step 1 - use scala parallel streams to generate parsers
-        // step 2 - use java parallel streams to parse sentences
-        // this avoids creation of extra (costly) threads at the cost
-        // of a small thread contention between the two thread pools
-        Map parsed = defWithCaches.parMap(m -> {
-            if (stream(m.localSentences()).noneMatch(s -> s instanceof Bubble && ((Bubble) s).sentenceType().equals(configuration)))
+    for (K kCellDecl : kcells) {
+      this.errors.add(
+          KEMException.compilerError(
+              "Multiple K cell declarations detected. Only one  cell declaration is allowed.",
+              kCellDecl));
+    }
+    throwExceptionIfThereAreErrors();
+  }
+
+  private Definition resolveConfigBubbles(Definition def) {
+    Definition defWithCaches = resolveCachedBubbles(def, false);
+    RuleGrammarGenerator gen = new RuleGrammarGenerator(def);
+
+    // parse config bubbles in parallel
+    // step 1 - use scala parallel streams to generate parsers
+    // step 2 - use java parallel streams to parse sentences
+    // this avoids creation of extra (costly) threads at the cost
+    // of a small thread contention between the two thread pools
+    Map parsed =
+        defWithCaches.parMap(
+            m -> {
+              if (stream(m.localSentences())
+                  .noneMatch(
+                      s ->
+                          s instanceof Bubble && ((Bubble) s).sentenceType().equals(configuration)))
                 return m;
-            Module configParserModule = gen.getConfigGrammar(m);
-            ParseCache cache = loadCache(configParserModule);
-            try (ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(cache.module(), true, profileRules, files, options.debugTypeInference)) {
-                // each parser gets its own scanner because config labels can conflict with user tokens
+              Module configParserModule = gen.getConfigGrammar(m);
+              ParseCache cache = loadCache(configParserModule);
+              try (ParseInModule parser =
+                  RuleGrammarGenerator.getCombinedGrammar(
+                      cache.module(), true, profileRules, files, options.debugTypeInference)) {
+                // each parser gets its own scanner because config labels can conflict with user
+                // tokens
                 parser.getScanner(globalOptions);
                 parser.initialize();
 
-                java.util.Set parsedSet = stream(m.localSentences())
-                        .filter(s -> s instanceof Bubble && ((Bubble) s).sentenceType().equals(configuration))
+                java.util.Set parsedSet =
+                    stream(m.localSentences())
+                        .filter(
+                            s ->
+                                s instanceof Bubble
+                                    && ((Bubble) s).sentenceType().equals(configuration))
                         .map(b -> (Bubble) b)
                         .parallel()
-                        .flatMap(b -> parseBubble(parser, cache.cache(), b)
-                                .map(p -> upSentence(p, b.sentenceType())))
+                        .flatMap(
+                            b ->
+                                parseBubble(parser, cache.cache(), b)
+                                    .map(p -> upSentence(p, b.sentenceType())))
                         .collect(Collectors.toSet());
-                Set allSent = m.localSentences().$bar(immutable(parsedSet)).filter(s -> !(s instanceof Bubble && ((Bubble) s).sentenceType().equals(configuration))).seq();
+                Set allSent =
+                    m.localSentences()
+                        .$bar(immutable(parsedSet))
+                        .filter(
+                            s ->
+                                !(s instanceof Bubble
+                                    && ((Bubble) s).sentenceType().equals(configuration)))
+                        .seq();
                 return Module(m.name(), m.imports(), allSent, m.att());
-            }
-        });
-
-        Definition defWithParsedConfigs = DefinitionTransformer.from(m ->
-                Module(m.name(), m.imports(), parsed.get(m.name()).localSentences(), m.att()),
-                "replace configs").apply(defWithCaches);
-
-        checkConfigCells(defWithParsedConfigs);
-
-        // replace config bubbles with the generated syntax and rules
-        return DefinitionTransformer.from(m -> {
-            if (stream(m.localSentences()).noneMatch(s -> s instanceof Configuration
-                    || (s instanceof SyntaxSort && s.att().contains(Att.TEMPORARY_CELL_SORT_DECL()))))
-              return m;
-
-            Set importedConfigurationSortsSubsortedToCell = stream(m.productions())
-                  .filter(p -> p.att().contains(Att.CELL()))
-                  .map(p -> Production(Seq(), Sorts.Cell(), Seq(NonTerminal(p.sort())))).collect(toSet());
-
-            Module module = Module(m.name(), m.imports(),
-                  (Set) m.localSentences().$bar(importedConfigurationSortsSubsortedToCell),
-                  m.att());
+              }
+            });
+
+    Definition defWithParsedConfigs =
+        DefinitionTransformer.from(
+                m -> Module(m.name(), m.imports(), parsed.get(m.name()).localSentences(), m.att()),
+                "replace configs")
+            .apply(defWithCaches);
+
+    checkConfigCells(defWithParsedConfigs);
+
+    // replace config bubbles with the generated syntax and rules
+    return DefinitionTransformer.from(
+            m -> {
+              if (stream(m.localSentences())
+                  .noneMatch(
+                      s ->
+                          s instanceof Configuration
+                              || (s instanceof SyntaxSort
+                                  && s.att().contains(Att.TEMPORARY_CELL_SORT_DECL())))) return m;
+
+              Set importedConfigurationSortsSubsortedToCell =
+                  stream(m.productions())
+                      .filter(p -> p.att().contains(Att.CELL()))
+                      .map(p -> Production(Seq(), Sorts.Cell(), Seq(NonTerminal(p.sort()))))
+                      .collect(toSet());
 
-            Module extMod = RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(module), true, profileRules, files, options.debugTypeInference).getExtensionModule();
-            Set configDeclProductions = stream(module.localSentences())
+              Module module =
+                  Module(
+                      m.name(),
+                      m.imports(),
+                      (Set)
+                          m.localSentences().$bar(importedConfigurationSortsSubsortedToCell),
+                      m.att());
+
+              Module extMod =
+                  RuleGrammarGenerator.getCombinedGrammar(
+                          gen.getConfigGrammar(module),
+                          true,
+                          profileRules,
+                          files,
+                          options.debugTypeInference)
+                      .getExtensionModule();
+              Set configDeclProductions =
+                  stream(module.localSentences())
                       .filter(s -> s instanceof Configuration)
                       .map(b -> (Configuration) b)
-                      .flatMap(configDecl ->
-                              stream(GenerateSentencesFromConfigDecl.gen(configDecl.body(), configDecl.ensures(), configDecl.att(), extMod)))
+                      .flatMap(
+                          configDecl ->
+                              stream(
+                                  GenerateSentencesFromConfigDecl.gen(
+                                      configDecl.body(),
+                                      configDecl.ensures(),
+                                      configDecl.att(),
+                                      extMod)))
                       .collect(toSet());
 
-            Set stc = m.localSentences()
-                    .$bar(configDeclProductions)
-                    .filter(s -> !(s instanceof Configuration))
-                    .filter(s -> !(s instanceof SyntaxSort && s.att().contains(Att.TEMPORARY_CELL_SORT_DECL()))).seq();
-            Module newM = Module(m.name(), m.imports(), stc, m.att());
-            newM.checkSorts(); // ensure all the Cell sorts are defined
-            return newM;
-        }, "expand configs").apply(defWithParsedConfigs);
-    }
-
-    private Definition resolveNonConfigBubbles(Definition defWithConfig, boolean serializeScanner, boolean deserializeScanner) {
-        Definition defWithCaches = resolveCachedBubbles(defWithConfig, true);
-        RuleGrammarGenerator gen = new RuleGrammarGenerator(defWithCaches);
-        Module ruleParserModule = gen.getRuleGrammar(defWithCaches.mainModule());
-        ParseCache cache = loadCache(ruleParserModule);
-        try (ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(cache.module(), true, profileRules, false, true, files, options.debugTypeInference, false)) {
-            Scanner scanner;
-            if (deserializeScanner) {
-                scanner = new Scanner(parser, globalOptions, files.resolveKompiled("scanner"));
-                parser.setScanner(scanner);
-            } else {
-                scanner = parser.getScanner(globalOptions);
-                if (serializeScanner) {
-                    scanner.serialize(files.resolveKompiled("scanner"));
-                }
-            }
-            final Scanner realScanner = scanner;
-            Map parsed = defWithCaches.parMap(m -> this.resolveNonConfigBubbles(m, realScanner, gen));
-            return DefinitionTransformer.from(m -> Module(m.name(), m.imports(), parsed.get(m.name()).localSentences(), m.att()), "parsing rules").apply(defWithConfig);
+              Set stc =
+                  m.localSentences()
+                      .$bar(configDeclProductions)
+                      .filter(s -> !(s instanceof Configuration))
+                      .filter(
+                          s ->
+                              !(s instanceof SyntaxSort
+                                  && s.att().contains(Att.TEMPORARY_CELL_SORT_DECL())))
+                      .seq();
+              Module newM = Module(m.name(), m.imports(), stc, m.att());
+              newM.checkSorts(); // ensure all the Cell sorts are defined
+              return newM;
+            },
+            "expand configs")
+        .apply(defWithParsedConfigs);
+  }
+
+  private Definition resolveNonConfigBubbles(
+      Definition defWithConfig, boolean serializeScanner, boolean deserializeScanner) {
+    Definition defWithCaches = resolveCachedBubbles(defWithConfig, true);
+    RuleGrammarGenerator gen = new RuleGrammarGenerator(defWithCaches);
+    Module ruleParserModule = gen.getRuleGrammar(defWithCaches.mainModule());
+    ParseCache cache = loadCache(ruleParserModule);
+    try (ParseInModule parser =
+        RuleGrammarGenerator.getCombinedGrammar(
+            cache.module(),
+            true,
+            profileRules,
+            false,
+            true,
+            files,
+            options.debugTypeInference,
+            false)) {
+      Scanner scanner;
+      if (deserializeScanner) {
+        scanner = new Scanner(parser, globalOptions, files.resolveKompiled("scanner"));
+        parser.setScanner(scanner);
+      } else {
+        scanner = parser.getScanner(globalOptions);
+        if (serializeScanner) {
+          scanner.serialize(files.resolveKompiled("scanner"));
         }
+      }
+      final Scanner realScanner = scanner;
+      Map parsed =
+          defWithCaches.parMap(m -> this.resolveNonConfigBubbles(m, realScanner, gen));
+      return DefinitionTransformer.from(
+              m -> Module(m.name(), m.imports(), parsed.get(m.name()).localSentences(), m.att()),
+              "parsing rules")
+          .apply(defWithConfig);
     }
-
-    private Module resolveNonConfigBubbles(Module module, Scanner scanner, RuleGrammarGenerator gen) {
-        if (stream(module.localSentences()).noneMatch(s -> s instanceof Bubble))
-            return module;
-
-        Module ruleParserModule = gen.getRuleGrammar(module);
-        // this scanner is not good for this module, so we must generate a new scanner.
-        boolean needNewScanner = !scanner.getModule().importedModuleNames().contains(module.name());
-
-        ParseCache cache = loadCache(ruleParserModule);
-        try (ParseInModule parser = needNewScanner ?
-                RuleGrammarGenerator.getCombinedGrammar(cache.module(), true, profileRules, files, options.debugTypeInference) :
-                RuleGrammarGenerator.getCombinedGrammar(cache.module(), scanner, true, profileRules, false, files, options.debugTypeInference, false)) {
-            if (needNewScanner)
-                parser.getScanner(globalOptions);
-            parser.initialize();
-
-            Set parsedSet = stream(module.localSentences())
-                    .parallel()
-                    .filter(s -> s instanceof Bubble)
-                    .map(b -> (Bubble) b)
-                    .flatMap(b -> parseBubble(parser, cache.cache(), b)
-                            .map(p -> upSentence(p, b.sentenceType())))
-                    .collect(Collections.toSet());
-
-            if (needNewScanner) {
-                parser.getScanner().close();//required for Windows.
-            }
-
-            return Module(module.name(), module.imports(),
-                    stream((Set) module.localSentences().$bar(parsedSet)).filter(b -> !(b instanceof Bubble)).collect(Collections.toSet()), module.att());
-        }
+  }
+
+  private Module resolveNonConfigBubbles(Module module, Scanner scanner, RuleGrammarGenerator gen) {
+    if (stream(module.localSentences()).noneMatch(s -> s instanceof Bubble)) return module;
+
+    Module ruleParserModule = gen.getRuleGrammar(module);
+    // this scanner is not good for this module, so we must generate a new scanner.
+    boolean needNewScanner = !scanner.getModule().importedModuleNames().contains(module.name());
+
+    ParseCache cache = loadCache(ruleParserModule);
+    try (ParseInModule parser =
+        needNewScanner
+            ? RuleGrammarGenerator.getCombinedGrammar(
+                cache.module(), true, profileRules, files, options.debugTypeInference)
+            : RuleGrammarGenerator.getCombinedGrammar(
+                cache.module(),
+                scanner,
+                true,
+                profileRules,
+                false,
+                files,
+                options.debugTypeInference,
+                false)) {
+      if (needNewScanner) parser.getScanner(globalOptions);
+      parser.initialize();
+
+      Set parsedSet =
+          stream(module.localSentences())
+              .parallel()
+              .filter(s -> s instanceof Bubble)
+              .map(b -> (Bubble) b)
+              .flatMap(
+                  b ->
+                      parseBubble(parser, cache.cache(), b)
+                          .map(p -> upSentence(p, b.sentenceType())))
+              .collect(Collections.toSet());
+
+      if (needNewScanner) {
+        parser.getScanner().close(); // required for Windows.
+      }
+
+      return Module(
+          module.name(),
+          module.imports(),
+          stream((Set) module.localSentences().$bar(parsedSet))
+              .filter(b -> !(b instanceof Bubble))
+              .collect(Collections.toSet()),
+          module.att());
     }
-
-    /**
-     * Replace all the targeted Bubbles from the definition if they can be found in caches.
-     * @param def    The Definition with Bubbles.
-     * @param isRule true if it should target non config Bubbles, false if it should parse only config bubbles
-     * @return A new Definition object with Bubbles replaced by the appropriate Sentence type.
-     */
-    private Definition resolveCachedBubbles(Definition def, boolean isRule) {
-        RuleGrammarGenerator gen = new RuleGrammarGenerator(def);
-        return DefinitionTransformer.from(m -> {
-            if (stream(m.localSentences()).noneMatch(s -> s instanceof Bubble && (isRule || ((Bubble) s).sentenceType().equals(configuration))))
+  }
+
+  /**
+   * Replace all the targeted Bubbles from the definition if they can be found in caches.
+   *
+   * @param def The Definition with Bubbles.
+   * @param isRule true if it should target non config Bubbles, false if it should parse only config
+   *     bubbles
+   * @return A new Definition object with Bubbles replaced by the appropriate Sentence type.
+   */
+  private Definition resolveCachedBubbles(Definition def, boolean isRule) {
+    RuleGrammarGenerator gen = new RuleGrammarGenerator(def);
+    return DefinitionTransformer.from(
+            m -> {
+              if (stream(m.localSentences())
+                  .noneMatch(
+                      s ->
+                          s instanceof Bubble
+                              && (isRule || ((Bubble) s).sentenceType().equals(configuration))))
                 return m;
-            ParseCache cache = isRule ? loadCache(gen.getRuleGrammar(m)) : loadCache(gen.getConfigGrammar(m));
-
-            Map fromCache = stream(m.localSentences())
-                    .filter(s -> s instanceof Bubble && (isRule || ((Bubble) s).sentenceType().equals(configuration)))
-                    .map(b -> (Bubble) b)
-                    .flatMap(b -> {
-                        if (cache.cache().containsKey(b.contents()) && cache.cache().get(b.contents()).parse() != null) {
-                            ParsedSentence parse = updateLocation(cache.cache().get(b.contents()), b);
-                            Att termAtt = parse.parse().att().remove(Source.class).remove(Location.class).remove(Production.class);
-                            Att bubbleAtt = b.att().remove(Source.class).remove(Location.class).remove(Att.CONTENT_START_LINE(), Integer.class).remove(Att.CONTENT_START_COLUMN(), Integer.class);
-                            if (!termAtt.equals(bubbleAtt)) // invalidate cache if attributes changed
-                                return Stream.of();
-                            cachedBubbles.getAndIncrement();
-                            registerWarnings(parse.warnings());
-                            KApply k = (KApply) new TreeNodesToKORE(Outer::parseSort, true).down(parse.parse());
-                            return Stream.of(Pair.of(b, upSentence(k, b.sentenceType())));
-                        }
-                        return Stream.of();
-                    }).collect(Collectors.toMap(Pair::getKey, Pair::getValue));
-
-            if (!fromCache.isEmpty()) {
-                Set stc = m.localSentences()
+              ParseCache cache =
+                  isRule ? loadCache(gen.getRuleGrammar(m)) : loadCache(gen.getConfigGrammar(m));
+
+              Map fromCache =
+                  stream(m.localSentences())
+                      .filter(
+                          s ->
+                              s instanceof Bubble
+                                  && (isRule || ((Bubble) s).sentenceType().equals(configuration)))
+                      .map(b -> (Bubble) b)
+                      .flatMap(
+                          b -> {
+                            if (cache.cache().containsKey(b.contents())
+                                && cache.cache().get(b.contents()).parse() != null) {
+                              ParsedSentence parse =
+                                  updateLocation(cache.cache().get(b.contents()), b);
+                              Att termAtt =
+                                  parse
+                                      .parse()
+                                      .att()
+                                      .remove(Source.class)
+                                      .remove(Location.class)
+                                      .remove(Production.class);
+                              Att bubbleAtt =
+                                  b.att()
+                                      .remove(Source.class)
+                                      .remove(Location.class)
+                                      .remove(Att.CONTENT_START_LINE(), Integer.class)
+                                      .remove(Att.CONTENT_START_COLUMN(), Integer.class);
+                              if (!termAtt.equals(
+                                  bubbleAtt)) // invalidate cache if attributes changed
+                              return Stream.of();
+                              cachedBubbles.getAndIncrement();
+                              registerWarnings(parse.warnings());
+                              KApply k =
+                                  (KApply)
+                                      new TreeNodesToKORE(Outer::parseSort, true)
+                                          .down(parse.parse());
+                              return Stream.of(Pair.of(b, upSentence(k, b.sentenceType())));
+                            }
+                            return Stream.of();
+                          })
+                      .collect(Collectors.toMap(Pair::getKey, Pair::getValue));
+
+              if (!fromCache.isEmpty()) {
+                Set stc =
+                    m.localSentences()
                         .$bar(immutable(Sets.newHashSet(fromCache.values())))
-                        .filter(s -> !(s instanceof Bubble && fromCache.containsKey(s))).seq();
+                        .filter(s -> !(s instanceof Bubble && fromCache.containsKey(s)))
+                        .seq();
                 return Module(m.name(), m.imports(), stc, m.att());
-            }
-            return m;
-        }, "load cached bubbles").apply(def);
-    }
-
-    public static ParsedSentence updateLocation(ParsedSentence parse, Bubble b) {
-        int newStartLine = b.att().get(Att.CONTENT_START_LINE(), Integer.class);
-        int newStartColumn = b.att().get(Att.CONTENT_START_COLUMN(), Integer.class);
-        int oldStartLine = parse.startLine();
-        int oldStartColumn = parse.startColumn();
-        if (oldStartLine != newStartLine || oldStartColumn != newStartColumn || !parse.source().equals(b.source().get())) {
-            int lineOffset = newStartLine - oldStartLine;
-            int columnOffset = newStartColumn - oldStartColumn;
-            K k = parse.parse() != null ? new AddAttRec(a -> {
-                Location loc = a.get(Location.class);
-                Location newLoc = updateLocation(oldStartLine, lineOffset, columnOffset, loc);
-                return a.remove(Source.class).remove(Location.class).add(Location.class, newLoc)
-                        .add(Source.class, b.source().orElseThrow(() -> new AssertionError("Expecting bubble to have source location!")));
-            }).apply(parse.parse()) : null;
-            java.util.Set warnings = parse.warnings().stream().map(ex -> ex.withLocation(updateLocation(oldStartLine, lineOffset, columnOffset, ex.exception.getLocation()),
-                            b.source().orElseThrow(() -> new AssertionError("Expecting bubble to have source location!"))))
-                    .collect(Collectors.toSet());
-            java.util.Set errors = parse.errors().stream().map(ex -> ex.withLocation(updateLocation(oldStartLine, lineOffset, columnOffset, ex.exception.getLocation()),
-                            b.source().orElseThrow(() -> new AssertionError("Expecting bubble to have source location!"))))
-                    .collect(Collectors.toSet());
-            return new ParsedSentence(k, warnings, errors, newStartLine, newStartColumn, parse.source());
-        }
-        return parse;
-    }
-
-    private static Location updateLocation(int oldStartLine, int lineOffset, int columnOffset, Location loc) {
-        return Location.apply(
-                loc.startLine() + lineOffset,
-                // only the first line can have column offset, otherwise it will trigger a cache miss
-                oldStartLine == loc.startLine() ? loc.startColumn() + columnOffset : loc.startColumn(),
-                loc.endLine() + lineOffset,
-                oldStartLine == loc.endLine() ? loc.endColumn() + columnOffset : loc.endColumn()
-        );
-    }
-
-    private void registerWarnings(java.util.Set warnings) {
-        if (kem.options.warnings2errors) {
-            for (KEMException err : warnings) {
-                if (kem.options.includesExceptionType(err.exception.getType())) {
-                    errors.add(KEMException.asError(err));
-                }
-            }
-        } else {
-            kem.addAllKException(warnings.stream().map(KEMException::getKException).collect(Collectors.toList()));
-        }
+              }
+              return m;
+            },
+            "load cached bubbles")
+        .apply(def);
+  }
+
+  public static ParsedSentence updateLocation(ParsedSentence parse, Bubble b) {
+    int newStartLine = b.att().get(Att.CONTENT_START_LINE(), Integer.class);
+    int newStartColumn = b.att().get(Att.CONTENT_START_COLUMN(), Integer.class);
+    int oldStartLine = parse.startLine();
+    int oldStartColumn = parse.startColumn();
+    if (oldStartLine != newStartLine
+        || oldStartColumn != newStartColumn
+        || !parse.source().equals(b.source().get())) {
+      int lineOffset = newStartLine - oldStartLine;
+      int columnOffset = newStartColumn - oldStartColumn;
+      K k =
+          parse.parse() != null
+              ? new AddAttRec(
+                      a -> {
+                        Location loc = a.get(Location.class);
+                        Location newLoc =
+                            updateLocation(oldStartLine, lineOffset, columnOffset, loc);
+                        return a.remove(Source.class)
+                            .remove(Location.class)
+                            .add(Location.class, newLoc)
+                            .add(
+                                Source.class,
+                                b.source()
+                                    .orElseThrow(
+                                        () ->
+                                            new AssertionError(
+                                                "Expecting bubble to have source location!")));
+                      })
+                  .apply(parse.parse())
+              : null;
+      java.util.Set warnings =
+          parse.warnings().stream()
+              .map(
+                  ex ->
+                      ex.withLocation(
+                          updateLocation(
+                              oldStartLine, lineOffset, columnOffset, ex.exception.getLocation()),
+                          b.source()
+                              .orElseThrow(
+                                  () ->
+                                      new AssertionError(
+                                          "Expecting bubble to have source location!"))))
+              .collect(Collectors.toSet());
+      java.util.Set errors =
+          parse.errors().stream()
+              .map(
+                  ex ->
+                      ex.withLocation(
+                          updateLocation(
+                              oldStartLine, lineOffset, columnOffset, ex.exception.getLocation()),
+                          b.source()
+                              .orElseThrow(
+                                  () ->
+                                      new AssertionError(
+                                          "Expecting bubble to have source location!"))))
+              .collect(Collectors.toSet());
+      return new ParsedSentence(k, warnings, errors, newStartLine, newStartColumn, parse.source());
     }
-
-    public Rule parseRule(CompiledDefinition compiledDef, String contents, Source source) {
-        errors = java.util.Collections.synchronizedSet(Sets.newHashSet());
-        RuleGrammarGenerator gen = new RuleGrammarGenerator(compiledDef.kompiledDefinition);
-        try (ParseInModule parser = RuleGrammarGenerator
-                .getCombinedGrammar(gen.getRuleGrammar(compiledDef.getParsedDefinition().mainModule()), true, profileRules, false, true, files, options.debugTypeInference, false)) {
-            parser.setScanner(new Scanner(parser, globalOptions, files.resolveKompiled("scanner")));
-            java.util.Set res = parseBubble(parser, new HashMap<>(),
-                    new Bubble(rule, contents, Att().add(Att.CONTENT_START_LINE(), 1)
-                            .add(Att.CONTENT_START_COLUMN(), 1).add(Source.class, source)))
-                    .collect(Collectors.toSet());
-            if (!errors.isEmpty()) {
-                throw errors.iterator().next();
-            }
-            return upRule(res.iterator().next());
+    return parse;
+  }
+
+  private static Location updateLocation(
+      int oldStartLine, int lineOffset, int columnOffset, Location loc) {
+    return Location.apply(
+        loc.startLine() + lineOffset,
+        // only the first line can have column offset, otherwise it will trigger a cache miss
+        oldStartLine == loc.startLine() ? loc.startColumn() + columnOffset : loc.startColumn(),
+        loc.endLine() + lineOffset,
+        oldStartLine == loc.endLine() ? loc.endColumn() + columnOffset : loc.endColumn());
+  }
+
+  private void registerWarnings(java.util.Set warnings) {
+    if (kem.options.warnings2errors) {
+      for (KEMException err : warnings) {
+        if (kem.options.includesExceptionType(err.exception.getType())) {
+          errors.add(KEMException.asError(err));
         }
+      }
+    } else {
+      kem.addAllKException(
+          warnings.stream().map(KEMException::getKException).collect(Collectors.toList()));
     }
-
-    private Sentence upSentence(K contents, String sentenceType) {
-        switch (sentenceType) {
-        case claim:         return upClaim(contents);
-        case rule:          return upRule(contents);
-        case context:       return upContext(contents);
-        case alias:         return upAlias(contents);
-        case configuration: return upConfiguration(contents);
-        }
-        throw new AssertionError("Unexpected sentence type: " + sentenceType);
+  }
+
+  public Rule parseRule(CompiledDefinition compiledDef, String contents, Source source) {
+    errors = java.util.Collections.synchronizedSet(Sets.newHashSet());
+    RuleGrammarGenerator gen = new RuleGrammarGenerator(compiledDef.kompiledDefinition);
+    try (ParseInModule parser =
+        RuleGrammarGenerator.getCombinedGrammar(
+            gen.getRuleGrammar(compiledDef.getParsedDefinition().mainModule()),
+            true,
+            profileRules,
+            false,
+            true,
+            files,
+            options.debugTypeInference,
+            false)) {
+      parser.setScanner(new Scanner(parser, globalOptions, files.resolveKompiled("scanner")));
+      java.util.Set res =
+          parseBubble(
+                  parser,
+                  new HashMap<>(),
+                  new Bubble(
+                      rule,
+                      contents,
+                      Att()
+                          .add(Att.CONTENT_START_LINE(), 1)
+                          .add(Att.CONTENT_START_COLUMN(), 1)
+                          .add(Source.class, source)))
+              .collect(Collectors.toSet());
+      if (!errors.isEmpty()) {
+        throw errors.iterator().next();
+      }
+      return upRule(res.iterator().next());
     }
-
-    private Claim upClaim(K contents) {
-        KApply ruleContents = (KApply) contents;
-        List items = ruleContents.klist().items();
-        return switch (ruleContents.klabel().name()) {
-            case "#ruleNoConditions" -> Claim(items.get(0), BooleanUtils.TRUE, BooleanUtils.TRUE, ruleContents.att());
-            case "#ruleRequires" -> Claim(items.get(0), items.get(1), BooleanUtils.TRUE, ruleContents.att());
-            case "#ruleEnsures" -> Claim(items.get(0), BooleanUtils.TRUE, items.get(1), ruleContents.att());
-            case "#ruleRequiresEnsures" -> Claim(items.get(0), items.get(1), items.get(2), ruleContents.att());
-            default -> throw new AssertionError("Wrong KLabel for claim content");
-        };
+  }
+
+  private Sentence upSentence(K contents, String sentenceType) {
+    switch (sentenceType) {
+      case claim:
+        return upClaim(contents);
+      case rule:
+        return upRule(contents);
+      case context:
+        return upContext(contents);
+      case alias:
+        return upAlias(contents);
+      case configuration:
+        return upConfiguration(contents);
     }
-
-    private Rule upRule(K contents) {
-        KApply ruleContents = (KApply) contents;
-        List items = ruleContents.klist().items();
-        return switch (ruleContents.klabel().name()) {
-            case "#ruleNoConditions" -> Rule(items.get(0), BooleanUtils.TRUE, BooleanUtils.TRUE, ruleContents.att());
-            case "#ruleRequires" -> Rule(items.get(0), items.get(1), BooleanUtils.TRUE, ruleContents.att());
-            case "#ruleEnsures" -> Rule(items.get(0), BooleanUtils.TRUE, items.get(1), ruleContents.att());
-            case "#ruleRequiresEnsures" -> Rule(items.get(0), items.get(1), items.get(2), ruleContents.att());
-            default -> throw new AssertionError("Wrong KLabel for rule content");
-        };
+    throw new AssertionError("Unexpected sentence type: " + sentenceType);
+  }
+
+  private Claim upClaim(K contents) {
+    KApply ruleContents = (KApply) contents;
+    List items = ruleContents.klist().items();
+    return switch (ruleContents.klabel().name()) {
+      case "#ruleNoConditions" -> Claim(
+          items.get(0), BooleanUtils.TRUE, BooleanUtils.TRUE, ruleContents.att());
+      case "#ruleRequires" -> Claim(
+          items.get(0), items.get(1), BooleanUtils.TRUE, ruleContents.att());
+      case "#ruleEnsures" -> Claim(
+          items.get(0), BooleanUtils.TRUE, items.get(1), ruleContents.att());
+      case "#ruleRequiresEnsures" -> Claim(
+          items.get(0), items.get(1), items.get(2), ruleContents.att());
+      default -> throw new AssertionError("Wrong KLabel for claim content");
+    };
+  }
+
+  private Rule upRule(K contents) {
+    KApply ruleContents = (KApply) contents;
+    List items = ruleContents.klist().items();
+    return switch (ruleContents.klabel().name()) {
+      case "#ruleNoConditions" -> Rule(
+          items.get(0), BooleanUtils.TRUE, BooleanUtils.TRUE, ruleContents.att());
+      case "#ruleRequires" -> Rule(
+          items.get(0), items.get(1), BooleanUtils.TRUE, ruleContents.att());
+      case "#ruleEnsures" -> Rule(
+          items.get(0), BooleanUtils.TRUE, items.get(1), ruleContents.att());
+      case "#ruleRequiresEnsures" -> Rule(
+          items.get(0), items.get(1), items.get(2), ruleContents.att());
+      default -> throw new AssertionError("Wrong KLabel for rule content");
+    };
+  }
+
+  private Context upContext(K contents) {
+    KApply ruleContents = (KApply) contents;
+    List items = ruleContents.klist().items();
+    return switch (ruleContents.klabel().name()) {
+      case "#ruleNoConditions" -> Context(items.get(0), BooleanUtils.TRUE, ruleContents.att());
+      case "#ruleRequires" -> Context(items.get(0), items.get(1), ruleContents.att());
+      default -> throw KEMException.criticalError(
+          "Illegal context with ensures clause detected.", contents);
+    };
+  }
+
+  private ContextAlias upAlias(K contents) {
+    KApply ruleContents = (KApply) contents;
+    List items = ruleContents.klist().items();
+    return switch (ruleContents.klabel().name()) {
+      case "#ruleNoConditions" -> ContextAlias(items.get(0), BooleanUtils.TRUE, ruleContents.att());
+      case "#ruleRequires" -> ContextAlias(items.get(0), items.get(1), ruleContents.att());
+      default -> throw KEMException.criticalError(
+          "Illegal context alias with ensures clause detected.", contents);
+    };
+  }
+
+  private Configuration upConfiguration(K contents) {
+    KApply configContents = (KApply) contents;
+    List items = configContents.klist().items();
+    return switch (configContents.klabel().name()) {
+      case "#ruleNoConditions" -> Configuration(
+          items.get(0), BooleanUtils.TRUE, configContents.att());
+      case "#ruleEnsures" -> Configuration(items.get(0), items.get(1), configContents.att());
+      default -> throw KEMException.compilerError(
+          "Illegal configuration with requires clause detected.", configContents);
+    };
+  }
+
+  private ParseCache loadCache(Module parser) {
+    ParseCache cachedParser = caches.get(parser.name());
+    if (cachedParser == null
+        || !equalsSyntax(cachedParser.module().signature(), parser.signature())) {
+      cachedParser =
+          new ParseCache(parser, true, java.util.Collections.synchronizedMap(new HashMap<>()));
+      caches.put(parser.name(), cachedParser);
     }
-
-    private Context upContext(K contents) {
-        KApply ruleContents = (KApply) contents;
-        List items = ruleContents.klist().items();
-        return switch (ruleContents.klabel().name()) {
-            case "#ruleNoConditions" -> Context(items.get(0), BooleanUtils.TRUE, ruleContents.att());
-            case "#ruleRequires" -> Context(items.get(0), items.get(1), ruleContents.att());
-            default -> throw KEMException.criticalError("Illegal context with ensures clause detected.", contents);
-        };
+    return cachedParser;
+  }
+
+  private boolean equalsSyntax(Module _this, Module that) {
+    if (!_this.productions().equals(that.productions())) return false;
+    if (!_this.priorities().equals(that.priorities())) return false;
+    if (!_this.leftAssoc().equals(that.leftAssoc())) return false;
+    if (!_this.rightAssoc().equals(that.rightAssoc())) return false;
+    return _this.sortDeclarations().equals(that.sortDeclarations());
+  }
+
+  private Stream parseBubble(
+      ParseInModule pim, Map cache, Bubble b) {
+    int startLine = b.att().get(Att.CONTENT_START_LINE(), Integer.class);
+    int startColumn = b.att().get(Att.CONTENT_START_COLUMN(), Integer.class);
+    Source source = b.att().get(Source.class);
+    boolean isAnywhere =
+        b.att().contains(Att.ANYWHERE())
+            || b.att().contains(Att.SIMPLIFICATION())
+            || ExpandMacros.isMacro(b);
+    Tuple2, K>, java.util.Set> result =
+        pim.parseString(
+            b.contents(),
+            START_SYMBOL,
+            "bubble parsing",
+            pim.getScanner(),
+            source,
+            startLine,
+            startColumn,
+            true,
+            isAnywhere);
+    parsedBubbles.getAndIncrement();
+    registerWarnings(result._2());
+    if (result._1().isRight()) {
+      KApply k = (KApply) result._1().right().get();
+      k =
+          KApply(
+              k.klabel(),
+              k.klist(),
+              k.att()
+                  .addAll(
+                      b.att()
+                          .remove(Att.CONTENT_START_LINE(), Integer.class)
+                          .remove(Att.CONTENT_START_COLUMN(), Integer.class)
+                          .remove(Source.class)
+                          .remove(Location.class)));
+      cache.put(
+          b.contents(),
+          new ParsedSentence(
+              k, new HashSet<>(result._2()), new HashSet<>(), startLine, startColumn, source));
+      k = (KApply) new TreeNodesToKORE(Outer::parseSort, true).down(k);
+      return Stream.of(k);
+    } else {
+      cache.put(
+          b.contents(),
+          new ParsedSentence(
+              null,
+              new HashSet<>(result._2()),
+              result._1().left().get(),
+              startLine,
+              startColumn,
+              source));
+      errors.addAll(result._1().left().get());
+      return Stream.empty();
     }
-
-    private ContextAlias upAlias(K contents) {
-        KApply ruleContents = (KApply) contents;
-        List items = ruleContents.klist().items();
-        return switch (ruleContents.klabel().name()) {
-            case "#ruleNoConditions" -> ContextAlias(items.get(0), BooleanUtils.TRUE, ruleContents.att());
-            case "#ruleRequires" -> ContextAlias(items.get(0), items.get(1), ruleContents.att());
-            default -> throw KEMException.criticalError("Illegal context alias with ensures clause detected.", contents);
-        };
-    }
-
-    private Configuration upConfiguration(K contents) {
-        KApply configContents = (KApply) contents;
-        List items = configContents.klist().items();
-        return switch (configContents.klabel().name()) {
-            case "#ruleNoConditions" -> Configuration(items.get(0), BooleanUtils.TRUE, configContents.att());
-            case "#ruleEnsures" -> Configuration(items.get(0), items.get(1), configContents.att());
-            default -> throw KEMException.compilerError("Illegal configuration with requires clause detected.", configContents);
-        };
-    }
-
-    private ParseCache loadCache(Module parser) {
-        ParseCache cachedParser = caches.get(parser.name());
-        if (cachedParser == null || !equalsSyntax(cachedParser.module().signature(), parser.signature())) {
-            cachedParser = new ParseCache(parser, true, java.util.Collections.synchronizedMap(new HashMap<>()));
-            caches.put(parser.name(), cachedParser);
-        }
-        return cachedParser;
-    }
-
-    private boolean equalsSyntax(Module _this, Module that) {
-        if (!_this.productions().equals(that.productions())) return false;
-        if (!_this.priorities().equals(that.priorities())) return false;
-        if (!_this.leftAssoc().equals(that.leftAssoc())) return false;
-        if (!_this.rightAssoc().equals(that.rightAssoc())) return false;
-        return _this.sortDeclarations().equals(that.sortDeclarations());
-    }
-
-    private Stream parseBubble(ParseInModule pim, Map cache, Bubble b) {
-        int startLine = b.att().get(Att.CONTENT_START_LINE(), Integer.class);
-        int startColumn = b.att().get(Att.CONTENT_START_COLUMN(), Integer.class);
-        Source source = b.att().get(Source.class);
-        boolean isAnywhere = b.att().contains(Att.ANYWHERE()) || b.att().contains(Att.SIMPLIFICATION()) || ExpandMacros.isMacro(b);
-        Tuple2, K>, java.util.Set> result =
-                pim.parseString(b.contents(), START_SYMBOL, "bubble parsing", pim.getScanner(), source, startLine, startColumn, true, isAnywhere);
-        parsedBubbles.getAndIncrement();
-        registerWarnings(result._2());
-        if (result._1().isRight()) {
-            KApply k = (KApply) result._1().right().get();
-            k = KApply(k.klabel(), k.klist(), k.att().addAll(b.att().remove(Att.CONTENT_START_LINE(), Integer.class)
-                    .remove(Att.CONTENT_START_COLUMN(), Integer.class).remove(Source.class).remove(Location.class)));
-            cache.put(b.contents(), new ParsedSentence(k, new HashSet<>(result._2()), new HashSet<>(), startLine, startColumn, source));
-            k = (KApply) new TreeNodesToKORE(Outer::parseSort, true).down(k);
-            return Stream.of(k);
-        } else {
-            cache.put(b.contents(), new ParsedSentence(null, new HashSet<>(result._2()), result._1().left().get(), startLine, startColumn, source));
-            errors.addAll(result._1().left().get());
-            return Stream.empty();
-        }
-    }
-
-    // Save all the timing information collected during parsing in a single file specified at command line.
-    // Timing information is expected to have two parts:
-    // 1. the comparable part - path:lineNumber
-    // 2. the printable part which contains the timing information
-    // The comparable part is used to sort each entry to provide a stable output.
-    private void saveTimings() {
-        if (innerParsingOptions.profileRules != null) {
-            try {
-                List> msgs = new ArrayList<>();
-                for (File f : files.resolveTemp(".").listFiles()) {
-                    if (f.getName().matches("timing.+\\.log")) {
-                        BufferedReader br = new BufferedReader(new FileReader(f));
-                        String path = br.readLine();
-                        String msg = br.readLine();
-                        msgs.add(Tuple2.apply(path, msg));
-                    }
-                }
-                msgs.sort(Comparator.comparing(Tuple2::_1));
-                FileUtil.save(new File(innerParsingOptions.profileRules),
-                        msgs.stream().map(Tuple2::_2).collect(Collectors.joining("\n")));
-            } catch (IOException e) {
-                throw KEMException.internalError("Failed to open timing.log", e);
-            }
+  }
+
+  // Save all the timing information collected during parsing in a single file specified at command
+  // line.
+  // Timing information is expected to have two parts:
+  // 1. the comparable part - path:lineNumber
+  // 2. the printable part which contains the timing information
+  // The comparable part is used to sort each entry to provide a stable output.
+  private void saveTimings() {
+    if (innerParsingOptions.profileRules != null) {
+      try {
+        List> msgs = new ArrayList<>();
+        for (File f : files.resolveTemp(".").listFiles()) {
+          if (f.getName().matches("timing.+\\.log")) {
+            BufferedReader br = new BufferedReader(new FileReader(f));
+            String path = br.readLine();
+            String msg = br.readLine();
+            msgs.add(Tuple2.apply(path, msg));
+          }
         }
+        msgs.sort(Comparator.comparing(Tuple2::_1));
+        FileUtil.save(
+            new File(innerParsingOptions.profileRules),
+            msgs.stream().map(Tuple2::_2).collect(Collectors.joining("\n")));
+      } catch (IOException e) {
+        throw KEMException.internalError("Failed to open timing.log", e);
+      }
     }
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/Kompile.java b/kernel/src/main/java/org/kframework/kompile/Kompile.java
index 266c8a8d0b8..f75ab4047c1 100644
--- a/kernel/src/main/java/org/kframework/kompile/Kompile.java
+++ b/kernel/src/main/java/org/kframework/kompile/Kompile.java
@@ -1,18 +1,41 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kompile;
 
+import static org.kframework.Collections.*;
+import static org.kframework.definition.Constructors.*;
+import static org.kframework.kore.KORE.*;
+
 import com.google.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 import org.apache.commons.io.FileUtils;
 import org.kframework.attributes.Att;
-import org.kframework.attributes.Att.Key;
 import org.kframework.attributes.Location;
 import org.kframework.attributes.Source;
 import org.kframework.backend.Backends;
 import org.kframework.builtin.Sorts;
 import org.kframework.compile.*;
+import org.kframework.compile.checks.CheckAnonymous;
 import org.kframework.compile.checks.CheckAssoc;
 import org.kframework.compile.checks.CheckAtt;
-import org.kframework.compile.checks.CheckAnonymous;
 import org.kframework.compile.checks.CheckConfigurationCells;
 import org.kframework.compile.checks.CheckFunctions;
 import org.kframework.compile.checks.CheckHOLE;
@@ -34,10 +57,10 @@
 import org.kframework.kore.Sort;
 import org.kframework.main.GlobalOptions;
 import org.kframework.parser.InputModes;
-import org.kframework.parser.json.JsonParser;
 import org.kframework.parser.KRead;
 import org.kframework.parser.ParserUtils;
 import org.kframework.parser.inner.RuleGrammarGenerator;
+import org.kframework.parser.json.JsonParser;
 import org.kframework.unparser.ToJson;
 import org.kframework.utils.OS;
 import org.kframework.utils.RunProcess;
@@ -49,537 +72,756 @@
 import org.kframework.utils.errorsystem.KExceptionManager;
 import org.kframework.utils.file.FileUtil;
 import org.kframework.utils.file.JarInfo;
-
 import org.kframework.utils.options.InnerParsingOptions;
 import org.kframework.utils.options.OuterParsingOptions;
-import scala.collection.JavaConverters;
 import scala.Function1;
 import scala.Option;
+import scala.collection.JavaConverters;
 import scala.collection.Seq;
 import scala.collection.Set$;
 
-import java.io.File;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Predicate;
-import java.util.function.UnaryOperator;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import static org.kframework.Collections.*;
-import static org.kframework.definition.Constructors.*;
-import static org.kframework.kore.KORE.*;
-
 /**
- * The new compilation pipeline. Everything is just wired together and will need clean-up once we deside on design.
- * Tracked by #1442.
+ * The new compilation pipeline. Everything is just wired together and will need clean-up once we
+ * deside on design. Tracked by #1442.
  */
 public class Kompile {
-    public static final File BUILTIN_DIRECTORY = JarInfo.getKIncludeDir().resolve("builtin").toFile();
-    public static final String REQUIRE_PRELUDE_K = "requires \"prelude.md\"\n";
-
-    public static final String CACHE_FILE_NAME = "cache.bin";
-
-
-    private final KompileOptions kompileOptions;
-    private final GlobalOptions globalOptions;
-    private final FileUtil files;
-    private final KExceptionManager kem;
-    private final ParserUtils parser;
-    private final Stopwatch sw;
-    private final DefinitionParsing definitionParsing;
-    private final OuterParsingOptions outerParsingOptions;
-    private final InnerParsingOptions innerParsingOptions;
-    java.util.Set errors;
-
-    public Kompile(KompileOptions kompileOptions, OuterParsingOptions outerParsingOptions, InnerParsingOptions innerParsingOptions, GlobalOptions globalOptions, FileUtil files, KExceptionManager kem, boolean cacheParses) {
-        this(kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, files, kem, new Stopwatch(globalOptions), cacheParses);
+  public static final File BUILTIN_DIRECTORY = JarInfo.getKIncludeDir().resolve("builtin").toFile();
+  public static final String REQUIRE_PRELUDE_K = "requires \"prelude.md\"\n";
+
+  public static final String CACHE_FILE_NAME = "cache.bin";
+
+  private final KompileOptions kompileOptions;
+  private final GlobalOptions globalOptions;
+  private final FileUtil files;
+  private final KExceptionManager kem;
+  private final ParserUtils parser;
+  private final Stopwatch sw;
+  private final DefinitionParsing definitionParsing;
+  private final OuterParsingOptions outerParsingOptions;
+  private final InnerParsingOptions innerParsingOptions;
+  java.util.Set errors;
+
+  public Kompile(
+      KompileOptions kompileOptions,
+      OuterParsingOptions outerParsingOptions,
+      InnerParsingOptions innerParsingOptions,
+      GlobalOptions globalOptions,
+      FileUtil files,
+      KExceptionManager kem,
+      boolean cacheParses) {
+    this(
+        kompileOptions,
+        outerParsingOptions,
+        innerParsingOptions,
+        globalOptions,
+        files,
+        kem,
+        new Stopwatch(globalOptions),
+        cacheParses);
+  }
+
+  public Kompile(
+      KompileOptions kompileOptions,
+      OuterParsingOptions outerParsingOptions,
+      InnerParsingOptions innerParsingOptions,
+      GlobalOptions globalOptions,
+      FileUtil files,
+      KExceptionManager kem) {
+    this(kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, files, kem, true);
+  }
+
+  @Inject
+  public Kompile(
+      KompileOptions kompileOptions,
+      OuterParsingOptions outerParsingOptions,
+      InnerParsingOptions innerParsingOptions,
+      GlobalOptions globalOptions,
+      FileUtil files,
+      KExceptionManager kem,
+      Stopwatch sw) {
+    this(
+        kompileOptions,
+        outerParsingOptions,
+        innerParsingOptions,
+        globalOptions,
+        files,
+        kem,
+        sw,
+        true);
+  }
+
+  public Kompile(
+      KompileOptions kompileOptions,
+      OuterParsingOptions outerParsingOptions,
+      InnerParsingOptions innerParsingOptions,
+      GlobalOptions globalOptions,
+      FileUtil files,
+      KExceptionManager kem,
+      Stopwatch sw,
+      boolean cacheParses) {
+    this.outerParsingOptions = outerParsingOptions;
+    this.innerParsingOptions = innerParsingOptions;
+    this.kompileOptions = kompileOptions;
+    this.globalOptions = globalOptions;
+    this.files = files;
+    this.kem = kem;
+    this.errors = new HashSet<>();
+    this.parser = new ParserUtils(files, kem, kem.options, outerParsingOptions);
+    List lookupDirectories =
+        this.outerParsingOptions.includes.stream()
+            .map(files::resolveWorkingDirectory)
+            .collect(Collectors.toList());
+    // these directories should be relative to the current working directory if we refer to them
+    // later after the WD has changed.
+    this.outerParsingOptions.includes =
+        lookupDirectories.stream().map(File::getAbsolutePath).collect(Collectors.toList());
+    File cacheFile =
+        kompileOptions.cacheFile != null
+            ? files.resolveWorkingDirectory(kompileOptions.cacheFile)
+            : files.resolveKompiled(CACHE_FILE_NAME);
+    this.definitionParsing =
+        new DefinitionParsing(
+            lookupDirectories,
+            kompileOptions,
+            outerParsingOptions,
+            innerParsingOptions,
+            globalOptions,
+            kem,
+            files,
+            parser,
+            cacheParses,
+            cacheFile,
+            sw);
+    this.sw = sw;
+  }
+
+  /**
+   * Executes the Kompile tool. This tool accesses a
+   *
+   * @param definitionFile
+   * @param mainModuleName
+   * @param mainProgramsModuleName
+   * @param programStartSymbol
+   * @return
+   */
+  public CompiledDefinition run(
+      File definitionFile,
+      String mainModuleName,
+      String mainProgramsModuleName,
+      Function pipeline,
+      Set excludedModuleTags) {
+    files.resolveKompiled(".").mkdirs();
+
+    Definition parsedDef =
+        parseDefinition(definitionFile, mainModuleName, mainProgramsModuleName, excludedModuleTags);
+
+    files.saveToKompiled("parsed.txt", parsedDef.toString());
+    checkDefinition(parsedDef, excludedModuleTags);
+    sw.printIntermediate("Validate definition");
+
+    Definition kompiledDefinition = pipeline.apply(parsedDef);
+    files.saveToKompiled("compiled.txt", kompiledDefinition.toString());
+    sw.printIntermediate("Apply compile pipeline");
+
+    // final check for sort correctness
+    for (Module m : mutable(kompiledDefinition.modules())) m.checkSorts();
+    if (kompileOptions.postProcess != null) {
+      kompiledDefinition = postProcessJSON(kompiledDefinition, kompileOptions.postProcess);
+      files.saveToKompiled("post-processed.txt", kompiledDefinition.toString());
     }
 
-    public Kompile(KompileOptions kompileOptions, OuterParsingOptions outerParsingOptions, InnerParsingOptions innerParsingOptions, GlobalOptions globalOptions, FileUtil files, KExceptionManager kem) {
-        this(kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, files, kem, true);
-    }
+    files.saveToKompiled("allRules.txt", ruleSourceMap(kompiledDefinition));
 
-    @Inject
-    public Kompile(KompileOptions kompileOptions, OuterParsingOptions outerParsingOptions, InnerParsingOptions innerParsingOptions, GlobalOptions globalOptions, FileUtil files, KExceptionManager kem, Stopwatch sw) {
-        this(kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, files, kem, sw, true);
+    if (kompileOptions.emitJson) {
+      Stopwatch sw = new Stopwatch(globalOptions);
+      files.saveToKompiled(
+          "parsed.json", new String(ToJson.apply(parsedDef), StandardCharsets.UTF_8));
+      files.saveToKompiled(
+          "compiled.json", new String(ToJson.apply(kompiledDefinition), StandardCharsets.UTF_8));
+      sw.printIntermediate("  Emit parsed & compiled JSON");
     }
 
-    public Kompile(KompileOptions kompileOptions, OuterParsingOptions outerParsingOptions, InnerParsingOptions innerParsingOptions, GlobalOptions globalOptions, FileUtil files, KExceptionManager kem, Stopwatch sw, boolean cacheParses) {
-        this.outerParsingOptions = outerParsingOptions;
-        this.innerParsingOptions = innerParsingOptions;
-        this.kompileOptions = kompileOptions;
-        this.globalOptions = globalOptions;
-        this.files = files;
-        this.kem = kem;
-        this.errors = new HashSet<>();
-        this.parser = new ParserUtils(files, kem, kem.options, outerParsingOptions);
-        List lookupDirectories = this.outerParsingOptions.includes.stream().map(files::resolveWorkingDirectory).collect(Collectors.toList());
-        // these directories should be relative to the current working directory if we refer to them later after the WD has changed.
-        this.outerParsingOptions.includes = lookupDirectories.stream().map(File::getAbsolutePath).collect(Collectors.toList());
-        File cacheFile = kompileOptions.cacheFile != null
-                ? files.resolveWorkingDirectory(kompileOptions.cacheFile) : files.resolveKompiled(CACHE_FILE_NAME);
-        this.definitionParsing = new DefinitionParsing(
-                lookupDirectories, kompileOptions, outerParsingOptions, innerParsingOptions, globalOptions, kem, files,
-                parser, cacheParses, cacheFile, sw);
-        this.sw = sw;
-    }
-
-    /**
-     * Executes the Kompile tool. This tool accesses a
-     *
-     * @param definitionFile
-     * @param mainModuleName
-     * @param mainProgramsModuleName
-     * @param programStartSymbol
-     * @return
-     */
-    public CompiledDefinition run(File definitionFile, String mainModuleName, String mainProgramsModuleName, Function pipeline, Set excludedModuleTags) {
-        files.resolveKompiled(".").mkdirs();
-
-        Definition parsedDef = parseDefinition(definitionFile, mainModuleName, mainProgramsModuleName, excludedModuleTags);
-
-        files.saveToKompiled("parsed.txt", parsedDef.toString());
-        checkDefinition(parsedDef, excludedModuleTags);
-        sw.printIntermediate("Validate definition");
-
-        Definition kompiledDefinition = pipeline.apply(parsedDef);
-        files.saveToKompiled("compiled.txt", kompiledDefinition.toString());
-        sw.printIntermediate("Apply compile pipeline");
-
-        // final check for sort correctness
-        for (Module m : mutable(kompiledDefinition.modules()))
-            m.checkSorts();
-        if (kompileOptions.postProcess != null) {
-            kompiledDefinition = postProcessJSON(kompiledDefinition, kompileOptions.postProcess);
-            files.saveToKompiled("post-processed.txt", kompiledDefinition.toString());
-        }
-
-        files.saveToKompiled("allRules.txt", ruleSourceMap(kompiledDefinition));
+    ConfigurationInfoFromModule configInfo =
+        new ConfigurationInfoFromModule(kompiledDefinition.mainModule());
 
-        if (kompileOptions.emitJson) {
-            Stopwatch sw = new Stopwatch(globalOptions);
-            files.saveToKompiled("parsed.json",   new String(ToJson.apply(parsedDef), StandardCharsets.UTF_8));
-            files.saveToKompiled("compiled.json", new String(ToJson.apply(kompiledDefinition), StandardCharsets.UTF_8));
-            sw.printIntermediate("  Emit parsed & compiled JSON");
-        }
-
-        ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(kompiledDefinition.mainModule());
-
-        boolean isKast = excludedModuleTags.contains(Att.KORE());
-        Sort rootCell;
-        if (isKast) {
-          rootCell = configInfo.getRootCell();
-        } else {
-          rootCell = Sorts.GeneratedTopCell();
+    boolean isKast = excludedModuleTags.contains(Att.KORE());
+    Sort rootCell;
+    if (isKast) {
+      rootCell = configInfo.getRootCell();
+    } else {
+      rootCell = Sorts.GeneratedTopCell();
+    }
+    CompiledDefinition def =
+        new CompiledDefinition(
+            kompileOptions,
+            kompileOptions.outerParsing,
+            kompileOptions.innerParsing,
+            globalOptions,
+            parsedDef,
+            kompiledDefinition,
+            files,
+            kem,
+            configInfo.getDefaultCell(rootCell).klabel());
+
+    if (kompileOptions.genBisonParser || kompileOptions.genGlrBisonParser) {
+      if (def.configurationVariableDefaultSorts.containsKey("$PGM")) {
+        String filename =
+            getBisonParserFilename(def.programStartSymbol.name(), def.mainSyntaxModuleName());
+        File outputFile = files.resolveKompiled(filename);
+        File linkFile = files.resolveKompiled("parser_PGM");
+        new KRead(kem, files, InputModes.PROGRAM, globalOptions)
+            .createBisonParser(
+                def.programParsingModuleFor(def.mainSyntaxModuleName(), kem).get(),
+                def.programStartSymbol,
+                outputFile,
+                kompileOptions.genGlrBisonParser,
+                kompileOptions.bisonFile,
+                kompileOptions.bisonStackMaxDepth,
+                kompileOptions.genBisonParserLibrary);
+        try {
+          linkFile.delete();
+          Files.createSymbolicLink(
+              linkFile.toPath(),
+              files.resolveKompiled(".").toPath().relativize(outputFile.toPath()));
+        } catch (IOException e) {
+          throw KEMException.internalError("Cannot write to kompiled directory.", e);
         }
-        CompiledDefinition def = new CompiledDefinition(kompileOptions, kompileOptions.outerParsing, kompileOptions.innerParsing, globalOptions, parsedDef, kompiledDefinition, files, kem, configInfo.getDefaultCell(rootCell).klabel());
-
-        if (kompileOptions.genBisonParser || kompileOptions.genGlrBisonParser) {
-            if (def.configurationVariableDefaultSorts.containsKey("$PGM")) {
-                String filename = getBisonParserFilename(def.programStartSymbol.name(), def.mainSyntaxModuleName());
-                File outputFile = files.resolveKompiled(filename);
-                File linkFile = files.resolveKompiled("parser_PGM");
-                new KRead(kem, files, InputModes.PROGRAM, globalOptions).createBisonParser(def.programParsingModuleFor(def.mainSyntaxModuleName(), kem).get(), def.programStartSymbol, outputFile, kompileOptions.genGlrBisonParser, kompileOptions.bisonFile, kompileOptions.bisonStackMaxDepth, kompileOptions.genBisonParserLibrary);
-                try {
-                    linkFile.delete();
-                    Files.createSymbolicLink(linkFile.toPath(), files.resolveKompiled(".").toPath().relativize(outputFile.toPath()));
-                } catch (IOException e) {
-                    throw KEMException.internalError("Cannot write to kompiled directory.", e);
-                }
+      }
+      for (Production prod : iterable(kompiledDefinition.mainModule().productions())) {
+        if (prod.att().contains(Att.CELL()) && prod.att().contains(Att.PARSER())) {
+          String att = prod.att().get(Att.PARSER());
+          String[][] parts = StringUtil.splitTwoDimensionalAtt(att);
+          for (String[] part : parts) {
+            if (part.length != 2) {
+              throw KEMException.compilerError("Invalid value for parser attribute: " + att, prod);
             }
-            for (Production prod : iterable(kompiledDefinition.mainModule().productions())) {
-                if (prod.att().contains(Att.CELL()) && prod.att().contains(Att.PARSER())) {
-                    String att = prod.att().get(Att.PARSER());
-                    String[][] parts = StringUtil.splitTwoDimensionalAtt(att);
-                    for (String[] part : parts) {
-                        if (part.length != 2) {
-                            throw KEMException.compilerError("Invalid value for parser attribute: " + att, prod);
-                        }
-                        String name = part[0];
-                        String module = part[1];
-                        Option mod = def.programParsingModuleFor(module, kem);
-                        if (!mod.isDefined()) {
-                            throw KEMException.compilerError("Could not find module referenced by parser attribute: " + module, prod);
-                        }
-                        Sort sort = def.configurationVariableDefaultSorts.getOrDefault("$" + name, Sorts.K());
-                        String filename = getBisonParserFilename(sort.name(), module);
-                        File outputFile = files.resolveKompiled(filename);
-                        File linkFile = files.resolveKompiled("parser_" + name);
-                        new KRead(kem, files, InputModes.PROGRAM, globalOptions).createBisonParser(mod.get(), sort, outputFile, kompileOptions.genGlrBisonParser, null, kompileOptions.bisonStackMaxDepth, kompileOptions.genBisonParserLibrary);
-                        try {
-                            linkFile.delete();
-                            Files.createSymbolicLink(linkFile.toPath(), files.resolveKompiled(".").toPath().relativize(outputFile.toPath()));
-                        } catch (IOException e) {
-                            throw KEMException.internalError("Cannot write to kompiled directory.", e);
-                        }
-                    }
-                }
+            String name = part[0];
+            String module = part[1];
+            Option mod = def.programParsingModuleFor(module, kem);
+            if (!mod.isDefined()) {
+              throw KEMException.compilerError(
+                  "Could not find module referenced by parser attribute: " + module, prod);
             }
+            Sort sort = def.configurationVariableDefaultSorts.getOrDefault("$" + name, Sorts.K());
+            String filename = getBisonParserFilename(sort.name(), module);
+            File outputFile = files.resolveKompiled(filename);
+            File linkFile = files.resolveKompiled("parser_" + name);
+            new KRead(kem, files, InputModes.PROGRAM, globalOptions)
+                .createBisonParser(
+                    mod.get(),
+                    sort,
+                    outputFile,
+                    kompileOptions.genGlrBisonParser,
+                    null,
+                    kompileOptions.bisonStackMaxDepth,
+                    kompileOptions.genBisonParserLibrary);
+            try {
+              linkFile.delete();
+              Files.createSymbolicLink(
+                  linkFile.toPath(),
+                  files.resolveKompiled(".").toPath().relativize(outputFile.toPath()));
+            } catch (IOException e) {
+              throw KEMException.internalError("Cannot write to kompiled directory.", e);
+            }
+          }
         }
-
-        return def;
+      }
     }
 
-    private String getBisonParserFilename(String sort, String module) {
-        String baseName = "parser_" + sort + "_" + module;
+    return def;
+  }
 
-        if (kompileOptions.genBisonParserLibrary) {
-            return "lib" + baseName + OS.current().getSharedLibraryExtension();
-        } else {
-            return baseName;
-        }
-    }
+  private String getBisonParserFilename(String sort, String module) {
+    String baseName = "parser_" + sort + "_" + module;
 
-    private Definition postProcessJSON(Definition defn, String postProcess) {
-        List command = new ArrayList<>(Arrays.asList(postProcess.split(" ")));
-        Map environment = new HashMap<>();
-        File compiledJson;
-        try {
-            String inputDefinition = new String(ToJson.apply(defn), StandardCharsets.UTF_8);
-            compiledJson = files.resolveTemp("post-process-compiled.json");
-            FileUtils.writeStringToFile(compiledJson, inputDefinition);
-        } catch (UnsupportedEncodingException e) {
-            throw KEMException.criticalError("Could not encode definition to JSON!");
-        } catch (IOException e) {
-            throw KEMException.criticalError("Could not make temporary file!");
-        }
-        command.add(compiledJson.getAbsolutePath());
-        RunProcess.ProcessOutput output = RunProcess.execute(environment, files.getProcessBuilder(), command.toArray(new String[command.size()]));
-        sw.printIntermediate("Post process JSON: " + String.join(" ", command));
-        if (output.exitCode() != 0) {
-            throw KEMException.criticalError("Post-processing returned a non-zero exit code: "
-                    + output.exitCode() + "\nStdout:\n" + new String(output.stdout()) + "\nStderr:\n" + new String(output.stderr()));
-        }
-        return JsonParser.parseDefinition(new String(output.stdout()));
+    if (kompileOptions.genBisonParserLibrary) {
+      return "lib" + baseName + OS.current().getSharedLibraryExtension();
+    } else {
+      return baseName;
     }
-
-    private static String ruleSourceMap(Definition def) {
-        List ruleLocs = new ArrayList();
-        for (Sentence s: JavaConverters.setAsJavaSet(def.mainModule().sentences())) {
-            if (s instanceof RuleOrClaim) {
-                var optFile = s.att().getOptional(Source.class);
-                var optLine = s.att().getOptional(Location.class);
-                var optCol  = s.att().getOptional(Location.class);
-                var optId   = s.att().getOptional(Att.UNIQUE_ID());
-                if (optFile.isPresent() && optLine.isPresent() && optCol.isPresent() && optId.isPresent()) {
-                    String file = optFile.get().source();
-                    int line    = optLine.get().startLine();
-                    int col     = optCol.get().startColumn();
-                    String loc  = file + ":" + line + ":" + col;
-                    String id   = optId.get();
-                    ruleLocs.add(id + " " + loc);
-                }
-            }
-        }
-        return String.join("\n", ruleLocs);
+  }
+
+  private Definition postProcessJSON(Definition defn, String postProcess) {
+    List command = new ArrayList<>(Arrays.asList(postProcess.split(" ")));
+    Map environment = new HashMap<>();
+    File compiledJson;
+    try {
+      String inputDefinition = new String(ToJson.apply(defn), StandardCharsets.UTF_8);
+      compiledJson = files.resolveTemp("post-process-compiled.json");
+      FileUtils.writeStringToFile(compiledJson, inputDefinition);
+    } catch (UnsupportedEncodingException e) {
+      throw KEMException.criticalError("Could not encode definition to JSON!");
+    } catch (IOException e) {
+      throw KEMException.criticalError("Could not make temporary file!");
     }
-
-    public Definition parseDefinition(File definitionFile, String mainModuleName, String mainProgramsModule, Set excludedModuleTags) {
-        return definitionParsing.parseDefinitionAndResolveBubbles(definitionFile, mainModuleName, mainProgramsModule, excludedModuleTags);
+    command.add(compiledJson.getAbsolutePath());
+    RunProcess.ProcessOutput output =
+        RunProcess.execute(
+            environment, files.getProcessBuilder(), command.toArray(new String[command.size()]));
+    sw.printIntermediate("Post process JSON: " + String.join(" ", command));
+    if (output.exitCode() != 0) {
+      throw KEMException.criticalError(
+          "Post-processing returned a non-zero exit code: "
+              + output.exitCode()
+              + "\nStdout:\n"
+              + new String(output.stdout())
+              + "\nStderr:\n"
+              + new String(output.stderr()));
     }
-
-    private static Module filterStreamModules(Module input) {
-        if (input.name().equals("STDIN-STREAM") || input.name().equals("STDOUT-STREAM")) {
-            return Module(input.name(), Set(), Set(), input.att());
+    return JsonParser.parseDefinition(new String(output.stdout()));
+  }
+
+  private static String ruleSourceMap(Definition def) {
+    List ruleLocs = new ArrayList();
+    for (Sentence s : JavaConverters.setAsJavaSet(def.mainModule().sentences())) {
+      if (s instanceof RuleOrClaim) {
+        var optFile = s.att().getOptional(Source.class);
+        var optLine = s.att().getOptional(Location.class);
+        var optCol = s.att().getOptional(Location.class);
+        var optId = s.att().getOptional(Att.UNIQUE_ID());
+        if (optFile.isPresent() && optLine.isPresent() && optCol.isPresent() && optId.isPresent()) {
+          String file = optFile.get().source();
+          int line = optLine.get().startLine();
+          int col = optCol.get().startColumn();
+          String loc = file + ":" + line + ":" + col;
+          String id = optId.get();
+          ruleLocs.add(id + " " + loc);
         }
-        return input;
-    }
-
-    public static Definition resolveIOStreams(KExceptionManager kem,Definition d) {
-        return DefinitionTransformer.from(new ResolveIOStreams(d, kem)::resolve, "resolving io streams")
-                .andThen(DefinitionTransformer.from(Kompile::filterStreamModules, "resolving io streams"))
-                .apply(d);
+      }
     }
-
-    private static Module excludeModulesByTag(Set excludedModuleTags, Module mod) {
-        Predicate f = _import -> excludedModuleTags.stream().noneMatch(tag -> _import.module().att().contains(tag));
-        Set newImports = stream(mod.imports()).filter(f).collect(Collectors.toSet());
-        return Module(mod.name(), immutable(newImports), mod.localSentences(), mod.att());
+    return String.join("\n", ruleLocs);
+  }
+
+  public Definition parseDefinition(
+      File definitionFile,
+      String mainModuleName,
+      String mainProgramsModule,
+      Set excludedModuleTags) {
+    return definitionParsing.parseDefinitionAndResolveBubbles(
+        definitionFile, mainModuleName, mainProgramsModule, excludedModuleTags);
+  }
+
+  private static Module filterStreamModules(Module input) {
+    if (input.name().equals("STDIN-STREAM") || input.name().equals("STDOUT-STREAM")) {
+      return Module(input.name(), Set(), Set(), input.att());
     }
-
-    private static Definition excludeModulesByTag(Set excludedModuleTags, String syntaxModule, Definition d) {
-        for (Att.Key k : excludedModuleTags) {
-            if (d.mainModule().att().contains(k)) {
-                throw KEMException.compilerError("Main module " + d.mainModule().name() + " has excluded attribute [" + k + "].");
-            }
-            d.getModule(syntaxModule).map(m -> {
+    return input;
+  }
+
+  public static Definition resolveIOStreams(KExceptionManager kem, Definition d) {
+    return DefinitionTransformer.from(new ResolveIOStreams(d, kem)::resolve, "resolving io streams")
+        .andThen(DefinitionTransformer.from(Kompile::filterStreamModules, "resolving io streams"))
+        .apply(d);
+  }
+
+  private static Module excludeModulesByTag(Set excludedModuleTags, Module mod) {
+    Predicate f =
+        _import ->
+            excludedModuleTags.stream().noneMatch(tag -> _import.module().att().contains(tag));
+    Set newImports = stream(mod.imports()).filter(f).collect(Collectors.toSet());
+    return Module(mod.name(), immutable(newImports), mod.localSentences(), mod.att());
+  }
+
+  private static Definition excludeModulesByTag(
+      Set excludedModuleTags, String syntaxModule, Definition d) {
+    for (Att.Key k : excludedModuleTags) {
+      if (d.mainModule().att().contains(k)) {
+        throw KEMException.compilerError(
+            "Main module " + d.mainModule().name() + " has excluded attribute [" + k + "].");
+      }
+      d.getModule(syntaxModule)
+          .map(
+              m -> {
                 if (m.att().contains(k)) {
-                    throw KEMException.compilerError("Syntax module " + m.name() + " has excluded attribute [" + k + "].");
+                  throw KEMException.compilerError(
+                      "Syntax module " + m.name() + " has excluded attribute [" + k + "].");
                 }
                 return null;
-            });
-        }
-
-        return Definition(d.mainModule(), immutable(stream(d.entryModules()).filter(mod -> excludedModuleTags.stream().noneMatch(tag -> mod.att().contains(tag))).collect(Collectors.toSet())), d.att());
-    }
-
-    public static Function1 excludeModulesByTag(Set excludedModuleTags, String syntaxModule) {
-        Function1 excludeModules = d -> excludeModulesByTag(excludedModuleTags, syntaxModule, d);
-        DefinitionTransformer walkModules = DefinitionTransformer.from(mod -> excludeModulesByTag(excludedModuleTags, mod), "remove modules based on attributes");
-
-        return excludeModules.andThen(walkModules);
+              });
     }
 
-    public static Sentence removePolyKLabels(Sentence s) {
-      if (s instanceof Production p) {
-          if (!p.isSyntacticSubsort() && p.params().nonEmpty()) {
-            p = p.substitute(immutable(Collections.nCopies(p.params().size(), Sorts.K())));
-            return Production(p.klabel().map(KLabel::head), Seq(), p.sort(), p.items(), p.att());
-        }
+    return Definition(
+        d.mainModule(),
+        immutable(
+            stream(d.entryModules())
+                .filter(
+                    mod -> excludedModuleTags.stream().noneMatch(tag -> mod.att().contains(tag)))
+                .collect(Collectors.toSet())),
+        d.att());
+  }
+
+  public static Function1 excludeModulesByTag(
+      Set excludedModuleTags, String syntaxModule) {
+    Function1 excludeModules =
+        d -> excludeModulesByTag(excludedModuleTags, syntaxModule, d);
+    DefinitionTransformer walkModules =
+        DefinitionTransformer.from(
+            mod -> excludeModulesByTag(excludedModuleTags, mod),
+            "remove modules based on attributes");
+
+    return excludeModules.andThen(walkModules);
+  }
+
+  public static Sentence removePolyKLabels(Sentence s) {
+    if (s instanceof Production p) {
+      if (!p.isSyntacticSubsort() && p.params().nonEmpty()) {
+        p = p.substitute(immutable(Collections.nCopies(p.params().size(), Sorts.K())));
+        return Production(p.klabel().map(KLabel::head), Seq(), p.sort(), p.items(), p.att());
       }
-      return s;
     }
-
-    public static Module subsortKItem(Module module) {
-        java.util.Set prods = new HashSet<>();
-        for (Sort srt : iterable(module.allSorts())) {
-            if (!RuleGrammarGenerator.isParserSort(srt)) {
-                // KItem ::= Sort
-                Production prod = Production(Seq(), Sorts.KItem(), Seq(NonTerminal(srt)), Att());
-                if (!module.sentences().contains(prod)) {
-                    prods.add(prod);
-                }
-            }
-        }
-        if (prods.isEmpty()) {
-            return module;
-        } else {
-            return Module(module.name(), module.imports(), Stream.concat(stream(module.localSentences()), prods.stream())
-                    .collect(org.kframework.Collections.toSet()), module.att());
+    return s;
+  }
+
+  public static Module subsortKItem(Module module) {
+    java.util.Set prods = new HashSet<>();
+    for (Sort srt : iterable(module.allSorts())) {
+      if (!RuleGrammarGenerator.isParserSort(srt)) {
+        // KItem ::= Sort
+        Production prod = Production(Seq(), Sorts.KItem(), Seq(NonTerminal(srt)), Att());
+        if (!module.sentences().contains(prod)) {
+          prods.add(prod);
         }
+      }
     }
-
-    public Rule parseAndCompileRule(CompiledDefinition compiledDef, String contents, Source source, Optional parsedRule) {
-        Rule parsed = parsedRule.orElseGet(() -> parseRule(compiledDef, contents, source));
-        return compileRule(compiledDef.kompiledDefinition, parsed);
-    }
-
-    public Rule parseRule(CompiledDefinition compiledDef, String contents, Source source) {
-        return definitionParsing.parseRule(compiledDef, contents, source);
-    }
-
-    private void checkDefinition(Definition parsedDef, Set excludedModuleTags) {
-        scala.collection.Set modules = parsedDef.modules();
-        Module mainModule = parsedDef.mainModule();
-        Option kModule = parsedDef.getModule("K");
-        definitionChecks(stream(modules).collect(Collectors.toSet()));
-        structuralChecks(modules, mainModule, kModule, excludedModuleTags);
+    if (prods.isEmpty()) {
+      return module;
+    } else {
+      return Module(
+          module.name(),
+          module.imports(),
+          Stream.concat(stream(module.localSentences()), prods.stream())
+              .collect(org.kframework.Collections.toSet()),
+          module.att());
     }
-
-    // checks that are not verified in the prover
-    public void definitionChecks(Set modules) {
-        modules.forEach(m -> stream(m.localSentences()).forEach(s -> {
-            // Check that the `claim` keyword is not used in the definition.
-            if (s instanceof Claim)
-                errors.add(KEMException.compilerError("Claims are not allowed in the definition.", s));
-        }));
-    }
-
-    // Extra checks just for the prover specification.
-    public Module proverChecks(Module specModule, Module mainDefModule) {
-        // check rogue syntax in spec module
-        Set toCheck = mutable(specModule.sentences().$minus$minus(mainDefModule.sentences()));
-        for (Sentence s : toCheck)
-            if (s.isSyntax() && !s.att().contains(Att.TOKEN()))
-                kem.registerCompilerWarning(ExceptionType.FUTURE_ERROR, errors,
-                        "Found syntax declaration in proof module. This will not be visible from the main module.", s);
-
-        // TODO: remove once transition to claim rules is done
-        // transform rules into claims if
-        // - they are in the spec modules but not in the definition modules
-        // - they don't contain the `simplification` attribute
-        ModuleTransformer mt = ModuleTransformer.fromSentenceTransformer((m, s) -> {
-            if (m.name().equals(mainDefModule.name()) || mainDefModule.importedModuleNames().contains(m.name()))
-                return s;
-            if (s instanceof Rule && !s.att().contains(Att.SIMPLIFICATION())) {
-                kem.registerCompilerWarning(KException.ExceptionType.FUTURE_ERROR, errors, "Deprecated: use claim instead of rule to specify proof objectives.", s);
-                return new Claim(((Rule) s).body(), ((Rule) s).requires(), ((Rule) s).ensures(), s.att());
-            }
-            return s;
-        }, "rules to claim");
-        return mt.apply(specModule);
-    }
-
-    // Extra checks just for the prover specification.
-    public void proverChecksX(Module specModule, Module mainDefModule) {
-        // check rogue syntax in spec module
-        Set toCheck = mutable(specModule.sentences().$minus$minus(mainDefModule.sentences()));
-        for (Sentence s : toCheck)
-            if (s.isSyntax() && (!s.att().contains(Att.TOKEN()) || !mainDefModule.allSorts().contains(((Production) s).sort())))
-                errors.add(KEMException.compilerError("Found syntax declaration in proof module. Only tokens for existing sorts are allowed.", s));
-
-        ModuleTransformer mt = ModuleTransformer.fromSentenceTransformer((m, s) -> {
-            if (m.name().equals(mainDefModule.name()) || mainDefModule.importedModuleNames().contains(m.name()))
-                return s;
-            if (!(s instanceof Claim || s.isSyntax())) {
+  }
+
+  public Rule parseAndCompileRule(
+      CompiledDefinition compiledDef, String contents, Source source, Optional parsedRule) {
+    Rule parsed = parsedRule.orElseGet(() -> parseRule(compiledDef, contents, source));
+    return compileRule(compiledDef.kompiledDefinition, parsed);
+  }
+
+  public Rule parseRule(CompiledDefinition compiledDef, String contents, Source source) {
+    return definitionParsing.parseRule(compiledDef, contents, source);
+  }
+
+  private void checkDefinition(Definition parsedDef, Set excludedModuleTags) {
+    scala.collection.Set modules = parsedDef.modules();
+    Module mainModule = parsedDef.mainModule();
+    Option kModule = parsedDef.getModule("K");
+    definitionChecks(stream(modules).collect(Collectors.toSet()));
+    structuralChecks(modules, mainModule, kModule, excludedModuleTags);
+  }
+
+  // checks that are not verified in the prover
+  public void definitionChecks(Set modules) {
+    modules.forEach(
+        m ->
+            stream(m.localSentences())
+                .forEach(
+                    s -> {
+                      // Check that the `claim` keyword is not used in the definition.
+                      if (s instanceof Claim)
+                        errors.add(
+                            KEMException.compilerError(
+                                "Claims are not allowed in the definition.", s));
+                    }));
+  }
+
+  // Extra checks just for the prover specification.
+  public Module proverChecks(Module specModule, Module mainDefModule) {
+    // check rogue syntax in spec module
+    Set toCheck = mutable(specModule.sentences().$minus$minus(mainDefModule.sentences()));
+    for (Sentence s : toCheck)
+      if (s.isSyntax() && !s.att().contains(Att.TOKEN()))
+        kem.registerCompilerWarning(
+            ExceptionType.FUTURE_ERROR,
+            errors,
+            "Found syntax declaration in proof module. This will not be visible from the main"
+                + " module.",
+            s);
+
+    // TODO: remove once transition to claim rules is done
+    // transform rules into claims if
+    // - they are in the spec modules but not in the definition modules
+    // - they don't contain the `simplification` attribute
+    ModuleTransformer mt =
+        ModuleTransformer.fromSentenceTransformer(
+            (m, s) -> {
+              if (m.name().equals(mainDefModule.name())
+                  || mainDefModule.importedModuleNames().contains(m.name())) return s;
+              if (s instanceof Rule && !s.att().contains(Att.SIMPLIFICATION())) {
+                kem.registerCompilerWarning(
+                    KException.ExceptionType.FUTURE_ERROR,
+                    errors,
+                    "Deprecated: use claim instead of rule to specify proof objectives.",
+                    s);
+                return new Claim(
+                    ((Rule) s).body(), ((Rule) s).requires(), ((Rule) s).ensures(), s.att());
+              }
+              return s;
+            },
+            "rules to claim");
+    return mt.apply(specModule);
+  }
+
+  // Extra checks just for the prover specification.
+  public void proverChecksX(Module specModule, Module mainDefModule) {
+    // check rogue syntax in spec module
+    Set toCheck = mutable(specModule.sentences().$minus$minus(mainDefModule.sentences()));
+    for (Sentence s : toCheck)
+      if (s.isSyntax()
+          && (!s.att().contains(Att.TOKEN())
+              || !mainDefModule.allSorts().contains(((Production) s).sort())))
+        errors.add(
+            KEMException.compilerError(
+                "Found syntax declaration in proof module. Only tokens for existing sorts are"
+                    + " allowed.",
+                s));
+
+    ModuleTransformer mt =
+        ModuleTransformer.fromSentenceTransformer(
+            (m, s) -> {
+              if (m.name().equals(mainDefModule.name())
+                  || mainDefModule.importedModuleNames().contains(m.name())) return s;
+              if (!(s instanceof Claim || s.isSyntax())) {
                 if (s instanceof Rule && !s.att().contains(Att.SIMPLIFICATION()))
-                    errors.add(KEMException.compilerError("Only claims and simplification rules are allowed in proof modules.", s));
-            }
-            return s;
-        }, "rules in spec module");
-        mt.apply(specModule);
-    }
+                  errors.add(
+                      KEMException.compilerError(
+                          "Only claims and simplification rules are allowed in proof modules.", s));
+              }
+              return s;
+            },
+            "rules in spec module");
+    mt.apply(specModule);
+  }
+
+  public void structuralChecks(
+      scala.collection.Set modules,
+      Module mainModule,
+      Option kModule,
+      Set excludedModuleTags) {
+    checkAnywhereRules(modules);
+    boolean isSymbolic = excludedModuleTags.contains(Att.CONCRETE());
+    boolean isKast = excludedModuleTags.contains(Att.KORE());
+    CheckRHSVariables checkRHSVariables =
+        new CheckRHSVariables(errors, !isSymbolic, kompileOptions.backend);
+    stream(modules).forEach(m -> stream(m.localSentences()).forEach(checkRHSVariables::check));
+
+    stream(modules)
+        .forEach(
+            m -> {
+              CheckAtt checkAtt = new CheckAtt(errors, kem, m, isSymbolic && isKast);
+              checkAtt.checkUnrecognizedModuleAtts();
+              stream(m.localSentences()).forEach(checkAtt::check);
+            });
 
-    public void structuralChecks(scala.collection.Set modules, Module mainModule, Option kModule, Set excludedModuleTags) {
-        checkAnywhereRules(modules);
-        boolean isSymbolic = excludedModuleTags.contains(Att.CONCRETE());
-        boolean isKast = excludedModuleTags.contains(Att.KORE());
-        CheckRHSVariables checkRHSVariables = new CheckRHSVariables(errors, !isSymbolic, kompileOptions.backend);
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(checkRHSVariables::check));
+    stream(modules)
+        .forEach(
+            m ->
+                stream(m.localSentences())
+                    .forEach(new CheckConfigurationCells(errors, m, isSymbolic && isKast)::check));
 
-        stream(modules).forEach(m -> {
-            CheckAtt checkAtt = new CheckAtt(errors, kem, m, isSymbolic && isKast);
-            checkAtt.checkUnrecognizedModuleAtts();
-            stream(m.localSentences()).forEach(checkAtt::check);
-        });
+    stream(modules)
+        .forEach(
+            m -> stream(m.localSentences()).forEach(new CheckSortTopUniqueness(errors, m)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckConfigurationCells(errors, m, isSymbolic && isKast)::check));
+    stream(modules)
+        .forEach(m -> stream(m.localSentences()).forEach(new CheckStreams(errors, m)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckSortTopUniqueness(errors, m)::check));
+    stream(modules)
+        .forEach(m -> stream(m.localSentences()).forEach(new CheckRewrite(errors, m)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckStreams(errors, m)::check));
+    stream(modules)
+        .forEach(m -> stream(m.localSentences()).forEach(new CheckHOLE(errors, m)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckRewrite(errors, m)::check));
+    if (!(isSymbolic && isKast)) { // if it's not the java backend
+      stream(modules)
+          .forEach(m -> stream(m.localSentences()).forEach(new CheckTokens(errors, m)::check));
+    }
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckHOLE(errors, m)::check));
+    stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckK(errors)::check));
 
-        if (!(isSymbolic && isKast)) { // if it's not the java backend
-            stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckTokens(errors, m)::check));
-        }
+    stream(modules)
+        .forEach(m -> stream(m.localSentences()).forEach(new CheckFunctions(errors, m)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckK(errors)::check));
+    stream(modules)
+        .forEach(
+            m -> stream(m.localSentences()).forEach(new CheckAnonymous(errors, m, kem)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(
-              new CheckFunctions(errors, m)::check));
+    stream(modules)
+        .forEach(
+            m -> stream(m.localSentences()).forEach(new CheckSyntaxGroups(errors, m, kem)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckAnonymous(errors, m, kem)::check));
+    stream(modules)
+        .forEach(m -> stream(m.localSentences()).forEach(new CheckAssoc(errors, m)::check));
 
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckSyntaxGroups(errors, m, kem)::check));
-
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckAssoc(errors, m)::check));
+    Set moduleNames = new HashSet<>();
+    stream(modules)
+        .forEach(
+            m -> {
+              if (moduleNames.contains(m.name())) {
+                errors.add(
+                    KEMException.compilerError("Found multiple modules with name: " + m.name()));
+              }
+              moduleNames.add(m.name());
+            });
 
-        Set moduleNames = new HashSet<>();
-        stream(modules).forEach(m -> {
-            if (moduleNames.contains(m.name())) {
-                errors.add(KEMException.compilerError("Found multiple modules with name: " + m.name()));
-            }
-            moduleNames.add(m.name());
-        });
-
-        CheckKLabels checkKLabels = new CheckKLabels(errors, kem, files, kompileOptions.extraConcreteRuleLabels);
-        Set checkedModules = new HashSet<>();
-        // only check imported modules because otherwise we might have false positives
-        Consumer checkModuleKLabels = m -> {
-            if (!checkedModules.contains(m.name())) {
-                stream(m.localSentences()).forEach(s -> checkKLabels.check(s, m));
-            }
-            checkedModules.add(m.name());
+    CheckKLabels checkKLabels =
+        new CheckKLabels(errors, kem, files, kompileOptions.extraConcreteRuleLabels);
+    Set checkedModules = new HashSet<>();
+    // only check imported modules because otherwise we might have false positives
+    Consumer checkModuleKLabels =
+        m -> {
+          if (!checkedModules.contains(m.name())) {
+            stream(m.localSentences()).forEach(s -> checkKLabels.check(s, m));
+          }
+          checkedModules.add(m.name());
         };
 
-        if (kModule.nonEmpty()) {
-            stream(kModule.get().importedModules()).forEach(checkModuleKLabels);
-            checkModuleKLabels.accept(kModule.get());
-        }
-        stream(mainModule.importedModules()).forEach(checkModuleKLabels);
-        checkModuleKLabels.accept(mainModule);
-        checkKLabels.check(mainModule);
-
-        stream(modules).forEach(m -> stream(m.localSentences()).forEach(new CheckLabels(errors)::check));
-
-        checkIsSortPredicates(modules);
-
-        if (!errors.isEmpty()) {
-            kem.addAllKException(errors.stream().map(e -> e.exception).collect(Collectors.toList()));
-            throw KEMException.compilerError("Had " + errors.size() + " structural errors.");
-        }
-    }
-
-    private void checkAnywhereRules(scala.collection.Set modules) {
-        if (kompileOptions.backend.equals(Backends.HASKELL) && !kompileOptions.allowAnywhereRulesHaskell) {
-            errors.addAll(stream(modules).flatMap(m -> stream(m.localSentences()).flatMap(s -> {
-                if (s instanceof Rule && s.att().contains(Att.ANYWHERE()))
-                    return Stream.of(KEMException.compilerError(Att.ANYWHERE() + " is not supported by the " + Backends.HASKELL + " backend.", s));
-                return Stream.empty();
-            })).collect(Collectors.toSet()));
-        }
-    }
-
-    private void checkIsSortPredicates(scala.collection.Set modules) {
-        Set generatedIsSorts =
-                stream(modules)
-                        .flatMap(m -> stream(m.definedSorts()))
-                        .map(s -> "is" + s.toString())
-                        .collect(Collectors.toSet());
-
-        stream(modules)
-                .flatMap(m -> stream(m.productionsForSort().getOrElse(Sorts.Bool().head(), Set$.MODULE$::empty)))
-                .collect(Collectors.toSet())
-                .stream()
-                .forEach(prod -> {
-                    Seq items = prod.items();
-                    if (items.size() < 3) {
-                        return;
-                    }
-                    ProductionItem first = items.head();
-                    ProductionItem second = items.tail().head();
-                    ProductionItem last = items.last();
-                    // Check if the production is of the form isSort ( ... )
-                    if ((first instanceof Terminal) && (second instanceof Terminal) && (last instanceof Terminal) &&
-                            generatedIsSorts.contains(((Terminal) first).value()) &&
-                            ((Terminal) second).value().equals("(") && ((Terminal) last).value().equals(")")) {
-                        errors.add(
-                                KEMException.compilerError(
-                                        "Syntax declaration conflicts with automatically generated " +
-                                                ((Terminal) first).value() + " predicate.", prod));
-                    }
-                });
+    if (kModule.nonEmpty()) {
+      stream(kModule.get().importedModules()).forEach(checkModuleKLabels);
+      checkModuleKLabels.accept(kModule.get());
     }
+    stream(mainModule.importedModules()).forEach(checkModuleKLabels);
+    checkModuleKLabels.accept(mainModule);
+    checkKLabels.check(mainModule);
 
-    public static Definition addSemanticsModule(Definition d) {
-        java.util.Set allModules = mutable(d.modules());
+    stream(modules)
+        .forEach(m -> stream(m.localSentences()).forEach(new CheckLabels(errors)::check));
 
-        Module languageParsingModule = Constructors.Module("LANGUAGE-PARSING",
-                Set(Import(d.mainModule(), true),
-                        Import(d.getModule(d.att().get(Att.SYNTAX_MODULE())).get(), true),
-                        Import(d.getModule("K-TERM").get(), true),
-                        Import(d.getModule(RuleGrammarGenerator.ID_PROGRAM_PARSING).get(), true)), Set(), Att());
-        allModules.add(languageParsingModule);
-        return Constructors.Definition(d.mainModule(), immutable(allModules), d.att());
-    }
+    checkIsSortPredicates(modules);
 
-    public Rule compileRule(Definition compiledDef, Rule parsedRule) {
-        return (Rule) UnaryOperator.identity()
-                .andThen(new ResolveAnonVar()::resolve)
-                .andThen(new ResolveSemanticCasts(false)::resolve)
-                .andThen(s -> concretizeSentence(s, compiledDef))
-                .apply(parsedRule);
+    if (!errors.isEmpty()) {
+      kem.addAllKException(errors.stream().map(e -> e.exception).collect(Collectors.toList()));
+      throw KEMException.compilerError("Had " + errors.size() + " structural errors.");
     }
-
-    public Set parseModules(CompiledDefinition definition, String mainModule, String entryPointModule, File definitionFile, Set excludedModuleTags, boolean readOnlyCache, boolean useCachedScanner) {
-        Set modules = definitionParsing.parseModules(definition, mainModule, entryPointModule, definitionFile, excludedModuleTags, readOnlyCache, useCachedScanner);
-        int totalBubbles = definitionParsing.parsedBubbles.get() + definitionParsing.cachedBubbles.get();
-        sw.printIntermediate("Parse spec modules [" + definitionParsing.parsedBubbles.get() + "/" + totalBubbles + " rules]");
-        return modules;
+  }
+
+  private void checkAnywhereRules(scala.collection.Set modules) {
+    if (kompileOptions.backend.equals(Backends.HASKELL)
+        && !kompileOptions.allowAnywhereRulesHaskell) {
+      errors.addAll(
+          stream(modules)
+              .flatMap(
+                  m ->
+                      stream(m.localSentences())
+                          .flatMap(
+                              s -> {
+                                if (s instanceof Rule && s.att().contains(Att.ANYWHERE()))
+                                  return Stream.of(
+                                      KEMException.compilerError(
+                                          Att.ANYWHERE()
+                                              + " is not supported by the "
+                                              + Backends.HASKELL
+                                              + " backend.",
+                                          s));
+                                return Stream.empty();
+                              }))
+              .collect(Collectors.toSet()));
     }
+  }
 
-    private Sentence concretizeSentence(Sentence s, Definition input) {
-        ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(input.mainModule());
-        LabelInfo labelInfo = new LabelInfoFromModule(input.mainModule());
-        SortInfo sortInfo = SortInfo.fromModule(input.mainModule());
-        return new ConcretizeCells(configInfo, labelInfo, sortInfo, input.mainModule()).concretize(input.mainModule(), s);
-    }
+  private void checkIsSortPredicates(scala.collection.Set modules) {
+    Set generatedIsSorts =
+        stream(modules)
+            .flatMap(m -> stream(m.definedSorts()))
+            .map(s -> "is" + s.toString())
+            .collect(Collectors.toSet());
+
+    stream(modules)
+        .flatMap(
+            m ->
+                stream(
+                    m.productionsForSort()
+                        .getOrElse(Sorts.Bool().head(), Set$.MODULE$::empty)))
+        .collect(Collectors.toSet())
+        .stream()
+        .forEach(
+            prod -> {
+              Seq items = prod.items();
+              if (items.size() < 3) {
+                return;
+              }
+              ProductionItem first = items.head();
+              ProductionItem second = items.tail().head();
+              ProductionItem last = items.last();
+              // Check if the production is of the form isSort ( ... )
+              if ((first instanceof Terminal)
+                  && (second instanceof Terminal)
+                  && (last instanceof Terminal)
+                  && generatedIsSorts.contains(((Terminal) first).value())
+                  && ((Terminal) second).value().equals("(")
+                  && ((Terminal) last).value().equals(")")) {
+                errors.add(
+                    KEMException.compilerError(
+                        "Syntax declaration conflicts with automatically generated "
+                            + ((Terminal) first).value()
+                            + " predicate.",
+                        prod));
+              }
+            });
+  }
+
+  public static Definition addSemanticsModule(Definition d) {
+    java.util.Set allModules = mutable(d.modules());
+
+    Module languageParsingModule =
+        Constructors.Module(
+            "LANGUAGE-PARSING",
+            Set(
+                Import(d.mainModule(), true),
+                Import(d.getModule(d.att().get(Att.SYNTAX_MODULE())).get(), true),
+                Import(d.getModule("K-TERM").get(), true),
+                Import(d.getModule(RuleGrammarGenerator.ID_PROGRAM_PARSING).get(), true)),
+            Set(),
+            Att());
+    allModules.add(languageParsingModule);
+    return Constructors.Definition(d.mainModule(), immutable(allModules), d.att());
+  }
+
+  public Rule compileRule(Definition compiledDef, Rule parsedRule) {
+    return (Rule)
+        UnaryOperator.identity()
+            .andThen(new ResolveAnonVar()::resolve)
+            .andThen(new ResolveSemanticCasts(false)::resolve)
+            .andThen(s -> concretizeSentence(s, compiledDef))
+            .apply(parsedRule);
+  }
+
+  public Set parseModules(
+      CompiledDefinition definition,
+      String mainModule,
+      String entryPointModule,
+      File definitionFile,
+      Set excludedModuleTags,
+      boolean readOnlyCache,
+      boolean useCachedScanner) {
+    Set modules =
+        definitionParsing.parseModules(
+            definition,
+            mainModule,
+            entryPointModule,
+            definitionFile,
+            excludedModuleTags,
+            readOnlyCache,
+            useCachedScanner);
+    int totalBubbles =
+        definitionParsing.parsedBubbles.get() + definitionParsing.cachedBubbles.get();
+    sw.printIntermediate(
+        "Parse spec modules ["
+            + definitionParsing.parsedBubbles.get()
+            + "/"
+            + totalBubbles
+            + " rules]");
+    return modules;
+  }
+
+  private Sentence concretizeSentence(Sentence s, Definition input) {
+    ConfigurationInfoFromModule configInfo = new ConfigurationInfoFromModule(input.mainModule());
+    LabelInfo labelInfo = new LabelInfoFromModule(input.mainModule());
+    SortInfo sortInfo = SortInfo.fromModule(input.mainModule());
+    return new ConcretizeCells(configInfo, labelInfo, sortInfo, input.mainModule())
+        .concretize(input.mainModule(), s);
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/KompileFrontEnd.java b/kernel/src/main/java/org/kframework/kompile/KompileFrontEnd.java
index 2bf3aaabfaa..f6da03a19f3 100644
--- a/kernel/src/main/java/org/kframework/kompile/KompileFrontEnd.java
+++ b/kernel/src/main/java/org/kframework/kompile/KompileFrontEnd.java
@@ -4,6 +4,8 @@
 import com.google.inject.Inject;
 import com.google.inject.Module;
 import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.List;
 import org.kframework.compile.Backend;
 import org.kframework.main.FrontEnd;
 import org.kframework.main.GlobalOptions;
@@ -19,77 +21,88 @@
 import org.kframework.utils.options.InnerParsingOptions;
 import org.kframework.utils.options.OuterParsingOptions;
 
-import java.util.ArrayList;
-import java.util.List;
-
 public class KompileFrontEnd extends FrontEnd {
 
-    public static List getModules() {
-        List modules = new ArrayList<>();
-        modules.add(new KompileModule());
-        modules.add(new JCommanderModule());
-        modules.add(new CommonModule());
-        return modules;
-    }
+  public static List getModules() {
+    List modules = new ArrayList<>();
+    modules.add(new KompileModule());
+    modules.add(new JCommanderModule());
+    modules.add(new CommonModule());
+    return modules;
+  }
 
+  private final KompileOptions options;
+  private final OuterParsingOptions outerOptions;
+  private final InnerParsingOptions innerOptions;
+  private final Provider koreBackend;
+  private final Stopwatch sw;
+  private final KExceptionManager kem;
+  private final BinaryLoader loader;
+  private final Provider files;
 
-    private final KompileOptions options;
-    private final OuterParsingOptions outerOptions;
-    private final InnerParsingOptions innerOptions;
-    private final Provider koreBackend;
-    private final Stopwatch sw;
-    private final KExceptionManager kem;
-    private final BinaryLoader loader;
-    private final Provider files;
+  @Inject
+  KompileFrontEnd(
+      KompileOptions options,
+      OuterParsingOptions outerOptions,
+      InnerParsingOptions innerOptions,
+      GlobalOptions globalOptions,
+      @Usage String usage,
+      Provider koreBackend,
+      Stopwatch sw,
+      KExceptionManager kem,
+      BinaryLoader loader,
+      JarInfo jarInfo,
+      Provider files) {
+    super(kem, globalOptions, usage, jarInfo, files);
+    this.options = options;
+    this.outerOptions = outerOptions;
+    this.innerOptions = innerOptions;
+    this.koreBackend = koreBackend;
+    this.sw = sw;
+    this.kem = kem;
+    this.loader = loader;
+    this.files = files;
+  }
 
-    @Inject
-    KompileFrontEnd(
-            KompileOptions options,
-            OuterParsingOptions outerOptions,
-            InnerParsingOptions innerOptions,
-            GlobalOptions globalOptions,
-            @Usage String usage,
-            Provider koreBackend,
-            Stopwatch sw,
-            KExceptionManager kem,
-            BinaryLoader loader,
-            JarInfo jarInfo,
-            Provider files) {
-        super(kem, globalOptions, usage, jarInfo, files);
-        this.options = options;
-        this.outerOptions = outerOptions;
-        this.innerOptions = innerOptions;
-        this.koreBackend = koreBackend;
-        this.sw = sw;
-        this.kem = kem;
-        this.loader = loader;
-        this.files = files;
+  @Override
+  public int run() {
+    if (!outerOptions.mainDefinitionFile(files.get()).exists()) {
+      throw KEMException.criticalError(
+          "Definition file doesn't exist: "
+              + outerOptions.mainDefinitionFile(files.get()).getAbsolutePath());
     }
 
-    @Override
-    public int run() {
-        if (!outerOptions.mainDefinitionFile(files.get()).exists()) {
-            throw KEMException.criticalError("Definition file doesn't exist: " +
-                    outerOptions.mainDefinitionFile(files.get()).getAbsolutePath());
-        }
-
-        Kompile kompile = new Kompile(options, outerOptions, innerOptions, globalOptions, files.get(), kem, sw, innerOptions.profileRules == null);
-        Backend backend = koreBackend.get();
-        CompiledDefinition def = kompile.run(outerOptions.mainDefinitionFile(files.get()), options.mainModule(files.get()), options.syntaxModule(files.get()), backend.steps(), backend.excludedModuleTags());
-        kompile = null;
-        files.get().saveToKompiled("mainModule.txt", def.executionModule().name());
-        files.get().saveToKompiled("mainSyntaxModule.txt", def.mainSyntaxModuleName());
-        sw.printIntermediate("Kompile to kore");
-        loader.saveOrDie(files.get().resolveKompiled("compiled.bin"), def);
-        files.get().saveToKompiled("backend.txt", options.backend); // used by the krun script
-        sw.printIntermediate("Save to disk");
-        Backend.Holder h = new Backend.Holder(def);
-        def = null;
-        backend.accept(h);
-        sw.printIntermediate("Backend");
-        loader.saveOrDie(files.get().resolveKompiled("timestamp"), "");
-        sw.printTotal("Total");
-        return 0;
-    }
+    Kompile kompile =
+        new Kompile(
+            options,
+            outerOptions,
+            innerOptions,
+            globalOptions,
+            files.get(),
+            kem,
+            sw,
+            innerOptions.profileRules == null);
+    Backend backend = koreBackend.get();
+    CompiledDefinition def =
+        kompile.run(
+            outerOptions.mainDefinitionFile(files.get()),
+            options.mainModule(files.get()),
+            options.syntaxModule(files.get()),
+            backend.steps(),
+            backend.excludedModuleTags());
+    kompile = null;
+    files.get().saveToKompiled("mainModule.txt", def.executionModule().name());
+    files.get().saveToKompiled("mainSyntaxModule.txt", def.mainSyntaxModuleName());
+    sw.printIntermediate("Kompile to kore");
+    loader.saveOrDie(files.get().resolveKompiled("compiled.bin"), def);
+    files.get().saveToKompiled("backend.txt", options.backend); // used by the krun script
+    sw.printIntermediate("Save to disk");
+    Backend.Holder h = new Backend.Holder(def);
+    def = null;
+    backend.accept(h);
+    sw.printIntermediate("Backend");
+    loader.saveOrDie(files.get().resolveKompiled("timestamp"), "");
+    sw.printTotal("Total");
+    return 0;
+  }
 }
-
diff --git a/kernel/src/main/java/org/kframework/kompile/KompileModule.java b/kernel/src/main/java/org/kframework/kompile/KompileModule.java
index 3757d7c6432..9bf8acaabc7 100644
--- a/kernel/src/main/java/org/kframework/kompile/KompileModule.java
+++ b/kernel/src/main/java/org/kframework/kompile/KompileModule.java
@@ -4,7 +4,6 @@
 import com.google.inject.AbstractModule;
 import com.google.inject.Provides;
 import com.google.inject.multibindings.Multibinder;
-import com.google.inject.name.Named;
 import org.kframework.main.FrontEnd;
 import org.kframework.main.GlobalOptions;
 import org.kframework.main.Tool;
@@ -16,42 +15,47 @@
 import org.kframework.utils.options.OutputDirectoryOptions;
 import org.kframework.utils.options.SMTOptions;
 
-import java.util.List;
-
 public class KompileModule extends AbstractModule {
 
-    public KompileModule() {
-    }
-
-    @Override
-    protected void configure() {
-        binder().requireAtInjectOnConstructors();
-        bind(FrontEnd.class).to(KompileFrontEnd.class);
-        bind(Tool.class).toInstance(Tool.KOMPILE);
-
-        install(new OuterParsingModule());
-        install(new BackendModule());
-
-        Multibinder optionsBinder = Multibinder.newSetBinder(binder(), Object.class, Options.class);
-        optionsBinder.addBinding().to(KompileOptions.class);
-    }
-
-    @Provides
-    SMTOptions smtOptions(KompileOptions options) {
-        return options.smt;
-    }
-
-    @Provides @RequestScoped
-    GlobalOptions globalOptions(KompileOptions options) {
-        return options.getGlobalOptions_UseOnlyInGuiceProvider();
-    }
-
-    @Provides
-    OuterParsingOptions outerParsingOptions(KompileOptions options) { return options.outerParsing; }
-
-    @Provides
-    InnerParsingOptions innerParsingOptions(KompileOptions options) { return options.innerParsing; }
-
-    @Provides
-    OutputDirectoryOptions outputDirectoryOptions(KompileOptions options) { return options.outputDirectory; }
+  public KompileModule() {}
+
+  @Override
+  protected void configure() {
+    binder().requireAtInjectOnConstructors();
+    bind(FrontEnd.class).to(KompileFrontEnd.class);
+    bind(Tool.class).toInstance(Tool.KOMPILE);
+
+    install(new OuterParsingModule());
+    install(new BackendModule());
+
+    Multibinder optionsBinder =
+        Multibinder.newSetBinder(binder(), Object.class, Options.class);
+    optionsBinder.addBinding().to(KompileOptions.class);
+  }
+
+  @Provides
+  SMTOptions smtOptions(KompileOptions options) {
+    return options.smt;
+  }
+
+  @Provides
+  @RequestScoped
+  GlobalOptions globalOptions(KompileOptions options) {
+    return options.getGlobalOptions_UseOnlyInGuiceProvider();
+  }
+
+  @Provides
+  OuterParsingOptions outerParsingOptions(KompileOptions options) {
+    return options.outerParsing;
+  }
+
+  @Provides
+  InnerParsingOptions innerParsingOptions(KompileOptions options) {
+    return options.innerParsing;
+  }
+
+  @Provides
+  OutputDirectoryOptions outputDirectoryOptions(KompileOptions options) {
+    return options.outputDirectory;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/KompileOptions.java b/kernel/src/main/java/org/kframework/kompile/KompileOptions.java
index ba96c409fdd..fb5cbd39b8e 100644
--- a/kernel/src/main/java/org/kframework/kompile/KompileOptions.java
+++ b/kernel/src/main/java/org/kframework/kompile/KompileOptions.java
@@ -1,13 +1,17 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.kompile;
 
+import static org.kframework.kompile.Kompile.CACHE_FILE_NAME;
+
 import com.beust.jcommander.Parameter;
 import com.beust.jcommander.ParametersDelegate;
 import com.google.inject.Inject;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
 import org.apache.commons.io.FilenameUtils;
 import org.kframework.backend.Backends;
 import org.kframework.main.GlobalOptions;
-import org.kframework.utils.errorsystem.KEMException;
 import org.kframework.utils.file.FileUtil;
 import org.kframework.utils.inject.RequestScoped;
 import org.kframework.utils.options.InnerParsingOptions;
@@ -16,136 +20,228 @@
 import org.kframework.utils.options.SMTOptions;
 import org.kframework.utils.options.StringListConverter;
 
-import java.io.Serializable;
-import java.util.Collections;
-import java.util.List;
-
-import static org.kframework.kompile.Kompile.CACHE_FILE_NAME;
-
 @RequestScoped
 public class KompileOptions implements Serializable {
-    @Inject
-    public KompileOptions() {}
-
-    /**
-     * WARNING: this field will be non-null in kompile tool, but null when KompileOption is deserialized,
-     * as part of CompiledDefinition, in any other tool. usability depends on context.
-     */
-    @ParametersDelegate
-    private final transient GlobalOptions global = new GlobalOptions();
-
-    /**
-     * Use only in the Guice Provider method, so it can be replaced by GlobalOptions from other tools.
-     */
-    GlobalOptions getGlobalOptions_UseOnlyInGuiceProvider() {
-        return global;
+  @Inject
+  public KompileOptions() {}
+
+  /**
+   * WARNING: this field will be non-null in kompile tool, but null when KompileOption is
+   * deserialized, as part of CompiledDefinition, in any other tool. usability depends on context.
+   */
+  @ParametersDelegate private final transient GlobalOptions global = new GlobalOptions();
+
+  /**
+   * Use only in the Guice Provider method, so it can be replaced by GlobalOptions from other tools.
+   */
+  GlobalOptions getGlobalOptions_UseOnlyInGuiceProvider() {
+    return global;
+  }
+
+  @ParametersDelegate public OuterParsingOptions outerParsing = new OuterParsingOptions();
+
+  @ParametersDelegate public transient InnerParsingOptions innerParsing = new InnerParsingOptions();
+
+  @ParametersDelegate public OutputDirectoryOptions outputDirectory = new OutputDirectoryOptions();
+
+  // Common options
+  @Parameter(
+      names = "--backend",
+      description =
+          "Choose a backend.  is one of [llvm|haskell|kore]. Each creates the kompiled K"
+              + " definition.",
+      descriptionKey = "backend")
+  public String backend = Backends.LLVM;
+
+  @Parameter(
+      names = "--main-module",
+      descriptionKey = "name",
+      description =
+          "Specify main module in which a program starts to execute. This information is used by"
+              + " 'krun'. The default is the name of the given K definition file without the"
+              + " extension (.k).")
+  private String mainModule;
+
+  public String mainModule(FileUtil files) {
+    if (mainModule == null) {
+      return FilenameUtils.getBaseName(outerParsing.mainDefinitionFile(files).getName())
+          .toUpperCase();
     }
-
-    @ParametersDelegate
-    public OuterParsingOptions outerParsing = new OuterParsingOptions();
-
-    @ParametersDelegate
-    public transient InnerParsingOptions innerParsing = new InnerParsingOptions();
-
-    @ParametersDelegate
-    public OutputDirectoryOptions outputDirectory = new OutputDirectoryOptions();
-
-    // Common options
-    @Parameter(names="--backend", description="Choose a backend.  is one of [llvm|haskell|kore]. Each creates the kompiled K definition.", descriptionKey = "backend")
-    public String backend = Backends.LLVM;
-
-    @Parameter(names="--main-module", descriptionKey = "name",
-            description="Specify main module in which a program starts to execute. This information is used by 'krun'. " +
-            "The default is the name of the given K definition file without the extension (.k).")
-    private String mainModule;
-
-    public String mainModule(FileUtil files) {
-        if (mainModule == null) {
-            return FilenameUtils.getBaseName(outerParsing.mainDefinitionFile(files).getName()).toUpperCase();
-        }
-        return mainModule;
+    return mainModule;
+  }
+
+  @Parameter(
+      names = "--syntax-module",
+      descriptionKey = "name",
+      description =
+          "Specify main module for syntax. This information is used by 'krun'. (Default:"
+              + " -SYNTAX).")
+  private String syntaxModule;
+
+  public String syntaxModule(FileUtil files) {
+    if (syntaxModule == null) {
+      return mainModule(files) + "-SYNTAX";
     }
-
-    @Parameter(names="--syntax-module", descriptionKey = "name",
-            description="Specify main module for syntax. This information is used by 'krun'. (Default: -SYNTAX).")
-    private String syntaxModule;
-
-    public String syntaxModule(FileUtil files) {
-        if (syntaxModule == null) {
-            return mainModule(files) + "-SYNTAX";
-        }
-        return syntaxModule;
-    }
-
-    @Parameter(names="--coverage", description="Generate coverage data when executing semantics.")
-    public boolean coverage;
-
-    @Parameter(names="--hook-namespaces", listConverter=StringListConverter.class, description=" is a whitespace-separated list of namespaces to include in the hooks defined in the definition", descriptionKey = "string", hidden = true)
-    public List hookNamespaces = Collections.emptyList();
-
-    @Parameter(names="-O1", description="Optimize in ways that improve performance and code size, but interfere with debugging and increase compilation time slightly.")
-    public boolean optimize1;
-
-    @Parameter(names="-O2", description="Optimize further in ways that improve performance and code size, but interfere with debugging more and increase compilation time somewhat.")
-    public boolean optimize2;
-
-    @Parameter(names="-O3", description="Optimize aggressively in ways that significantly improve performance, but interfere with debugging significantly and also increase compilation time and code size substantially.")
-    public boolean optimize3;
-
-    @Parameter(names="-E", description="Perform outer parsing and then stop and pretty print the definition to standard output. Useful for converting a K definition into a completely self-contained file when reporting a bug.")
-    public boolean preprocess;
-
-    @Parameter(names="--bison-lists", description="Make List and NeList left associative. This is useful for creating Bison parsers that use bounded stack space.", hidden = true)
-    public boolean bisonLists;
-
-    @Parameter(names="--read-only-kompiled-directory", description="Files in the generated kompiled directory should be read-only to other frontend tools.", hidden = true)
-    public boolean readOnlyKompiledDirectory = false;
-
-    @Parameter(names="--concrete-rules", description="List of rule labels to be considered concrete, in addition to rules marked with `[concrete]` attribute", descriptionKey = "labels")
-    public List extraConcreteRuleLabels = Collections.emptyList();
-
-    @ParametersDelegate
-    public SMTOptions smt = new SMTOptions();
-
-    @Parameter(names="--cache-file", description="Location of parse cache file. Default is $KOMPILED_DIR/" + CACHE_FILE_NAME + ".", hidden = true)
-    public String cacheFile;
-
-    @Parameter(names="--emit-json", description="Emit JSON serialized version of parsed and kompiled definitions.")
-    public boolean emitJson = false;
-
-    @Parameter(names="--gen-bison-parser", description="Emit bison parser for the PGM configuration variable within the syntax module of your definition into the kompiled definition.")
-    public boolean genBisonParser;
-
-    @Parameter(names="--gen-glr-bison-parser", description="Emit GLR bison parser for the PGM configuration variable within the syntax module of your definition into the kompiled definition.")
-    public boolean genGlrBisonParser;
-
-    @Parameter(names="--bison-file", description="C file containing functions to link into bison parser.", descriptionKey = "file", hidden = true)
-    public String bisonFile;
-
-    @Parameter(names="--bison-stack-max-depth", description="Maximum size of bison parsing stack.", descriptionKey = "size", hidden = true)
-    public long bisonStackMaxDepth = 10000;
-
-    @Parameter(names="--bison-parser-library", description="Generate a shared library rather than an executable for Bison parsers", hidden = true)
-    public boolean genBisonParserLibrary;
-
-    public static final String DEFAULT_TRANSITION = "transition";
-
-    @Parameter(names="--top-cell", description="Choose the top configuration cell when more than one is provided. Does nothing if only one top cell exists.")
-    public String topCell;
-
-    @Parameter(names="--debug-type-inference", description="Filename and source line of rule to debug type inference for. This is generally an option used only by maintainers.", descriptionKey = "file", hidden = true)
-    public String debugTypeInference;
-
-    @Parameter(names={"--post-process"}, description="JSON KAST => JSON KAST converter to run on definition after kompile pipeline.", descriptionKey = "command", hidden = true)
-    public String postProcess;
-
-    // TODO(dwightguth): remove this when it is no longer needed
-    @Parameter(names={"--disable-ceil-simplification-rules"}, description="Disable all rules with the simplification attribute whose left-hand side has a #Ceil at the top.", hidden = true)
-    public boolean disableCeilSimplificationRules;
-
-    @Parameter(names={"--allow-anywhere-haskell"}, description="Disable error message for anywhere rules on the Haskell backend.", hidden = true)
-    public boolean allowAnywhereRulesHaskell;
-
-    @Parameter(names="--enable-kore-antileft", description="Enable generation of legacy antileft priority predicates ", hidden = true)
-    public boolean enableKoreAntileft;
+    return syntaxModule;
+  }
+
+  @Parameter(names = "--coverage", description = "Generate coverage data when executing semantics.")
+  public boolean coverage;
+
+  @Parameter(
+      names = "--hook-namespaces",
+      listConverter = StringListConverter.class,
+      description =
+          " is a whitespace-separated list of namespaces to include in the hooks defined in"
+              + " the definition",
+      descriptionKey = "string",
+      hidden = true)
+  public List hookNamespaces = Collections.emptyList();
+
+  @Parameter(
+      names = "-O1",
+      description =
+          "Optimize in ways that improve performance and code size, but interfere with debugging"
+              + " and increase compilation time slightly.")
+  public boolean optimize1;
+
+  @Parameter(
+      names = "-O2",
+      description =
+          "Optimize further in ways that improve performance and code size, but interfere with"
+              + " debugging more and increase compilation time somewhat.")
+  public boolean optimize2;
+
+  @Parameter(
+      names = "-O3",
+      description =
+          "Optimize aggressively in ways that significantly improve performance, but interfere with"
+              + " debugging significantly and also increase compilation time and code size"
+              + " substantially.")
+  public boolean optimize3;
+
+  @Parameter(
+      names = "-E",
+      description =
+          "Perform outer parsing and then stop and pretty print the definition to standard output."
+              + " Useful for converting a K definition into a completely self-contained file when"
+              + " reporting a bug.")
+  public boolean preprocess;
+
+  @Parameter(
+      names = "--bison-lists",
+      description =
+          "Make List and NeList left associative. This is useful for creating Bison parsers that"
+              + " use bounded stack space.",
+      hidden = true)
+  public boolean bisonLists;
+
+  @Parameter(
+      names = "--read-only-kompiled-directory",
+      description =
+          "Files in the generated kompiled directory should be read-only to other frontend tools.",
+      hidden = true)
+  public boolean readOnlyKompiledDirectory = false;
+
+  @Parameter(
+      names = "--concrete-rules",
+      description =
+          "List of rule labels to be considered concrete, in addition to rules marked with"
+              + " `[concrete]` attribute",
+      descriptionKey = "labels")
+  public List extraConcreteRuleLabels = Collections.emptyList();
+
+  @ParametersDelegate public SMTOptions smt = new SMTOptions();
+
+  @Parameter(
+      names = "--cache-file",
+      description =
+          "Location of parse cache file. Default is $KOMPILED_DIR/" + CACHE_FILE_NAME + ".",
+      hidden = true)
+  public String cacheFile;
+
+  @Parameter(
+      names = "--emit-json",
+      description = "Emit JSON serialized version of parsed and kompiled definitions.")
+  public boolean emitJson = false;
+
+  @Parameter(
+      names = "--gen-bison-parser",
+      description =
+          "Emit bison parser for the PGM configuration variable within the syntax module of your"
+              + " definition into the kompiled definition.")
+  public boolean genBisonParser;
+
+  @Parameter(
+      names = "--gen-glr-bison-parser",
+      description =
+          "Emit GLR bison parser for the PGM configuration variable within the syntax module of"
+              + " your definition into the kompiled definition.")
+  public boolean genGlrBisonParser;
+
+  @Parameter(
+      names = "--bison-file",
+      description = "C file containing functions to link into bison parser.",
+      descriptionKey = "file",
+      hidden = true)
+  public String bisonFile;
+
+  @Parameter(
+      names = "--bison-stack-max-depth",
+      description = "Maximum size of bison parsing stack.",
+      descriptionKey = "size",
+      hidden = true)
+  public long bisonStackMaxDepth = 10000;
+
+  @Parameter(
+      names = "--bison-parser-library",
+      description = "Generate a shared library rather than an executable for Bison parsers",
+      hidden = true)
+  public boolean genBisonParserLibrary;
+
+  public static final String DEFAULT_TRANSITION = "transition";
+
+  @Parameter(
+      names = "--top-cell",
+      description =
+          "Choose the top configuration cell when more than one is provided. Does nothing if only"
+              + " one top cell exists.")
+  public String topCell;
+
+  @Parameter(
+      names = "--debug-type-inference",
+      description =
+          "Filename and source line of rule to debug type inference for. This is generally an"
+              + " option used only by maintainers.",
+      descriptionKey = "file",
+      hidden = true)
+  public String debugTypeInference;
+
+  @Parameter(
+      names = {"--post-process"},
+      description = "JSON KAST => JSON KAST converter to run on definition after kompile pipeline.",
+      descriptionKey = "command",
+      hidden = true)
+  public String postProcess;
+
+  // TODO(dwightguth): remove this when it is no longer needed
+  @Parameter(
+      names = {"--disable-ceil-simplification-rules"},
+      description =
+          "Disable all rules with the simplification attribute whose left-hand side has a #Ceil at"
+              + " the top.",
+      hidden = true)
+  public boolean disableCeilSimplificationRules;
+
+  @Parameter(
+      names = {"--allow-anywhere-haskell"},
+      description = "Disable error message for anywhere rules on the Haskell backend.",
+      hidden = true)
+  public boolean allowAnywhereRulesHaskell;
+
+  @Parameter(
+      names = "--enable-kore-antileft",
+      description = "Enable generation of legacy antileft priority predicates ",
+      hidden = true)
+  public boolean enableKoreAntileft;
 }
diff --git a/kernel/src/main/java/org/kframework/kompile/KompileUsageFormatter.java b/kernel/src/main/java/org/kframework/kompile/KompileUsageFormatter.java
index f77bb3f154e..d82cab88997 100644
--- a/kernel/src/main/java/org/kframework/kompile/KompileUsageFormatter.java
+++ b/kernel/src/main/java/org/kframework/kompile/KompileUsageFormatter.java
@@ -3,422 +3,424 @@
 
 import com.beust.jcommander.*;
 import com.beust.jcommander.internal.Lists;
-
 import java.util.*;
 import java.util.ResourceBundle;
 
 /**
  * This is a customized `usage` for kompile based on DefaultUsageFormatter
  * https://github.com/cbeust/jcommander/blob/master/src/main/java/com/beust/jcommander/DefaultUsageFormatter.java
- * from the JCommander library. The only changes are related to printing
- * hidden options when --help-hidden is provided.
+ * from the JCommander library. The only changes are related to printing hidden options when
+ * --help-hidden is provided.
  *
- * Original licence:
+ * 

Original licence: * - * Copyright (C) 2010 the original author or authors. - * See the notice.md file distributed with this work for additional - * information regarding copyright ownership. + *

Copyright (C) 2010 the original author or authors. See the notice.md file distributed with + * this work for additional information regarding copyright ownership. * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + *

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + *

http://www.apache.org/licenses/LICENSE-2.0 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and + *

Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and * limitations under the License. * - * NOTICE: - * JCommander Copyright Notices - * Copyright 2010 Cedric Beust cedric@beust.com + *

NOTICE: JCommander Copyright Notices Copyright 2010 Cedric Beust cedric@beust.com */ public class KompileUsageFormatter implements IUsageFormatter { - private final JCommander commander; - private boolean helpHidden = false; - private boolean help = false; - - public KompileUsageFormatter(JCommander commander) { - this.commander = commander; - for (ParameterDescription pd : commander.getFields().values()) { - if (pd.getParameter().isHelp()) { - if (pd.getLongestName().equals("--help") && pd.isAssigned()) - help = true; - if (pd.getLongestName().equals("--help-hidden") && pd.isAssigned()) - helpHidden = true; - } - } + private final JCommander commander; + private boolean helpHidden = false; + private boolean help = false; + + public KompileUsageFormatter(JCommander commander) { + this.commander = commander; + for (ParameterDescription pd : commander.getFields().values()) { + if (pd.getParameter().isHelp()) { + if (pd.getLongestName().equals("--help") && pd.isAssigned()) help = true; + if (pd.getLongestName().equals("--help-hidden") && pd.isAssigned()) helpHidden = true; + } } - - /** - * Prints the usage to {@link JCommander#getConsole()} on the underlying commander instance. - */ - public final void usage(String commandName) { - StringBuilder sb = new StringBuilder(); - usage(commandName, sb); - commander.getConsole().println(sb.toString()); + } + + /** Prints the usage to {@link JCommander#getConsole()} on the underlying commander instance. */ + public final void usage(String commandName) { + StringBuilder sb = new StringBuilder(); + usage(commandName, sb); + commander.getConsole().println(sb.toString()); + } + + /** Store the usage for the argument command in the argument string builder. */ + public final void usage(String commandName, StringBuilder out) { + usage(commandName, out, ""); + } + + /** Store the usage in the argument string builder. */ + public final void usage(StringBuilder out) { + usage(out, ""); + } + + /** + * Store the usage for the command in the argument string builder, indenting every line with the + * value of indent. + */ + public final void usage(String commandName, StringBuilder out, String indent) { + String description = getCommandDescription(commandName); + JCommander jc = commander.findCommandByAlias(commandName); + + if (description != null) { + out.append(indent).append(description); + out.append("\n"); } - - /** - * Store the usage for the argument command in the argument string builder. - */ - public final void usage(String commandName, StringBuilder out) { - usage(commandName, out, ""); + jc.getUsageFormatter().usage(out, indent); + } + + /** + * Stores the usage in the argument string builder, with the argument indentation. This works by + * appending each portion of the help in the following order. Their outputs can be modified by + * overriding them in a subclass of this class. + * + *

    + *
  • Main line - {@link #appendMainLine(StringBuilder, boolean, boolean, int, String)} + *
  • Parameters - {@link #appendAllParametersDetails(StringBuilder, int, String, List)} + *
  • Commands - {@link #appendCommands(StringBuilder, int, int, String)} + *
+ */ + public void usage(StringBuilder out, String indent) { + if (commander.getDescriptions() == null) { + commander.createDescriptions(); } + boolean hasCommands = !commander.getCommands().isEmpty(); + boolean hasOptions = !commander.getDescriptions().isEmpty(); - /** - * Store the usage in the argument string builder. - */ - public final void usage(StringBuilder out) { - usage(out, ""); - } + // Indentation constants + final int descriptionIndent = 6; + final int indentCount = indent.length() + descriptionIndent; - /** - * Store the usage for the command in the argument string builder, indenting every line with the - * value of indent. - */ - public final void usage(String commandName, StringBuilder out, String indent) { - String description = getCommandDescription(commandName); - JCommander jc = commander.findCommandByAlias(commandName); - - if (description != null) { - out.append(indent).append(description); - out.append("\n"); - } - jc.getUsageFormatter().usage(out, indent); - } - - /** - * Stores the usage in the argument string builder, with the argument indentation. This works by appending - * each portion of the help in the following order. Their outputs can be modified by overriding them in a - * subclass of this class. - * - *
    - *
  • Main line - {@link #appendMainLine(StringBuilder, boolean, boolean, int, String)}
  • - *
  • Parameters - {@link #appendAllParametersDetails(StringBuilder, int, String, List)}
  • - *
  • Commands - {@link #appendCommands(StringBuilder, int, int, String)}
  • - *
- */ - public void usage(StringBuilder out, String indent) { - if (commander.getDescriptions() == null) { - commander.createDescriptions(); - } - boolean hasCommands = !commander.getCommands().isEmpty(); - boolean hasOptions = !commander.getDescriptions().isEmpty(); - - // Indentation constants - final int descriptionIndent = 6; - final int indentCount = indent.length() + descriptionIndent; - - // Append first line (aka main line) of the usage - appendMainLine(out, hasOptions, hasCommands, indentCount, indent); - - // Align the descriptions at the "longestName" column - int longestName = 0; - List sortedParameters = Lists.newArrayList(); - - for (ParameterDescription pd : commander.getFields().values()) { - if ((help && !pd.getParameter().hidden()) || (helpHidden && pd.getParameter().hidden())) { - sortedParameters.add(pd); - // + to have an extra space between the name and the description - int length = pd.getNames().length() + 2; - - if (length > longestName) { - longestName = length; - } - } - } + // Append first line (aka main line) of the usage + appendMainLine(out, hasOptions, hasCommands, indentCount, indent); - // Sort the options - sortedParameters.sort(commander.getParameterDescriptionComparator()); + // Align the descriptions at the "longestName" column + int longestName = 0; + List sortedParameters = Lists.newArrayList(); - // Append all the parameter names and descriptions - appendAllParametersDetails(out, indentCount, indent, sortedParameters); + for (ParameterDescription pd : commander.getFields().values()) { + if ((help && !pd.getParameter().hidden()) || (helpHidden && pd.getParameter().hidden())) { + sortedParameters.add(pd); + // + to have an extra space between the name and the description + int length = pd.getNames().length() + 2; - // Append commands if they were specified - if (hasCommands) { - appendCommands(out, indentCount, descriptionIndent, indent); + if (length > longestName) { + longestName = length; } + } } - /** - * Appends the main line segment of the usage to the argument string builder, indenting every - * line with indentCount-many indent. - * - * @param out the builder to append to - * @param hasOptions if the options section should be appended - * @param hasCommands if the comments section should be appended - * @param indentCount the amount of indentation to apply - * @param indent the indentation - */ - public void appendMainLine(StringBuilder out, boolean hasOptions, boolean hasCommands, int indentCount, - String indent) { - String programName = commander.getProgramDisplayName() != null - ? commander.getProgramDisplayName() : "
"; - StringBuilder mainLine = new StringBuilder(); - mainLine.append(indent).append("Usage: ").append(programName); - - if (hasOptions) { - mainLine.append(" [options] "); - } + // Sort the options + sortedParameters.sort(commander.getParameterDescriptionComparator()); - if (hasCommands) { - mainLine.append(indent).append(" [command] [command options]"); - } + // Append all the parameter names and descriptions + appendAllParametersDetails(out, indentCount, indent, sortedParameters); - //if (commander.getMainParameter() != null && commander.getMainParameter().getDescription() != null) { - // mainLine.append(" ").append(commander.getMainParameter().getDescription().getDescription()); - //} - wrapDescription(out, indentCount, mainLine.toString()); - out.append("\n"); + // Append commands if they were specified + if (hasCommands) { + appendCommands(out, indentCount, descriptionIndent, indent); + } + } + + /** + * Appends the main line segment of the usage to the argument string builder, indenting every line + * with indentCount-many indent. + * + * @param out the builder to append to + * @param hasOptions if the options section should be appended + * @param hasCommands if the comments section should be appended + * @param indentCount the amount of indentation to apply + * @param indent the indentation + */ + public void appendMainLine( + StringBuilder out, boolean hasOptions, boolean hasCommands, int indentCount, String indent) { + String programName = + commander.getProgramDisplayName() != null + ? commander.getProgramDisplayName() + : "
"; + StringBuilder mainLine = new StringBuilder(); + mainLine.append(indent).append("Usage: ").append(programName); + + if (hasOptions) { + mainLine.append(" [options] "); } - /** - * Appends the details of all parameters in the given order to the argument string builder, indenting every - * line with indentCount-many indent. - * - * @param out the builder to append to - * @param indentCount the amount of indentation to apply - * @param indent the indentation - * @param sortedParameters the parameters to append to the builder - */ - public void appendAllParametersDetails(StringBuilder out, int indentCount, String indent, - List sortedParameters) { - if (sortedParameters.size() > 0) { - out.append(indent).append(" Options:\n"); - } + if (hasCommands) { + mainLine.append(indent).append(" [command] [command options]"); + } - for (ParameterDescription pd : sortedParameters) { - WrappedParameter parameter = pd.getParameter(); - String description = pd.getDescription(); - boolean hasDescription = !description.isEmpty(); - String descriptionKey = pd.getParameter().getParameter().descriptionKey(); - descriptionKey = descriptionKey.isEmpty() ? "" : " <" + descriptionKey + ">"; - - // First line, command name - out.append(indent) - .append(" ") - .append(parameter.required() ? "* " : " ") - .append(pd.getLongestName()) - .append(descriptionKey) - .append(Arrays.stream(pd.getParameter().names()).count() > 1 ? ", " + pd.getParameter().names()[1] + descriptionKey : "") - .append("\n"); - - if (hasDescription) { - wrapDescription(out, indentCount, s(indentCount) + description); - } - Object def = pd.getDefault(); - - if (pd.isDynamicParameter()) { - String syntax = "Syntax: " + parameter.names()[0] + "key" + parameter.getAssignment() + "value"; - - if (hasDescription) { - out.append(newLineAndIndent(indentCount)); - } else { - out.append(s(indentCount)); - } - out.append(syntax); - } - - if (def != null && !pd.isHelp()) { - String displayedDef = Strings.isStringEmpty(def.toString()) ? "" : def.toString(); - String defaultText = "Default: " + (parameter.password() ? "********" : displayedDef); - - if (hasDescription) { - out.append(newLineAndIndent(indentCount)); - } else { - out.append(s(indentCount)); - } - out.append(defaultText); - } - Class type = pd.getParameterized().getType(); - - if (type.isEnum()) { - String valueList = EnumSet.allOf((Class) type).toString(); - String possibleValues = "Possible Values: " + valueList; - - // Prevent duplicate values list, since it is set as 'Options: [values]' if the description - // of an enum field is empty in ParameterDescription#init(..) - if (!description.contains("Options: " + valueList)) { - if (hasDescription) { - out.append(newLineAndIndent(indentCount)); - } else { - out.append(s(indentCount)); - } - out.append(possibleValues); - } - } - out.append("\n"); - } + // if (commander.getMainParameter() != null && commander.getMainParameter().getDescription() != + // null) { + // mainLine.append(" + // ").append(commander.getMainParameter().getDescription().getDescription()); + // } + wrapDescription(out, indentCount, mainLine.toString()); + out.append("\n"); + } + + /** + * Appends the details of all parameters in the given order to the argument string builder, + * indenting every line with indentCount-many indent. + * + * @param out the builder to append to + * @param indentCount the amount of indentation to apply + * @param indent the indentation + * @param sortedParameters the parameters to append to the builder + */ + public void appendAllParametersDetails( + StringBuilder out, + int indentCount, + String indent, + List sortedParameters) { + if (sortedParameters.size() > 0) { + out.append(indent).append(" Options:\n"); } - /** - * Appends the details of all commands to the argument string builder, indenting every line with - * indentCount-many indent. The commands are obtained from calling - * {@link JCommander#getRawCommands()} and the commands are resolved using - * {@link JCommander#findCommandByAlias(String)} on the underlying commander instance. - * - * @param out the builder to append to - * @param indentCount the amount of indentation to apply - * @param descriptionIndent the indentation for the description - * @param indent the indentation - */ - public void appendCommands(StringBuilder out, int indentCount, int descriptionIndent, String indent) { - boolean hasOnlyHiddenCommands = true; - for (Map.Entry commands : commander.getRawCommands().entrySet()) { - Object arg = commands.getValue().getObjects().get(0); - Parameters p = arg.getClass().getAnnotation(Parameters.class); - - if (p == null || ((help && !p.hidden()) || (helpHidden && p.hidden()))) - hasOnlyHiddenCommands = false; + for (ParameterDescription pd : sortedParameters) { + WrappedParameter parameter = pd.getParameter(); + String description = pd.getDescription(); + boolean hasDescription = !description.isEmpty(); + String descriptionKey = pd.getParameter().getParameter().descriptionKey(); + descriptionKey = descriptionKey.isEmpty() ? "" : " <" + descriptionKey + ">"; + + // First line, command name + out.append(indent) + .append(" ") + .append(parameter.required() ? "* " : " ") + .append(pd.getLongestName()) + .append(descriptionKey) + .append( + Arrays.stream(pd.getParameter().names()).count() > 1 + ? ", " + pd.getParameter().names()[1] + descriptionKey + : "") + .append("\n"); + + if (hasDescription) { + wrapDescription(out, indentCount, s(indentCount) + description); + } + Object def = pd.getDefault(); + + if (pd.isDynamicParameter()) { + String syntax = + "Syntax: " + parameter.names()[0] + "key" + parameter.getAssignment() + "value"; + + if (hasDescription) { + out.append(newLineAndIndent(indentCount)); + } else { + out.append(s(indentCount)); + } + out.append(syntax); + } + + if (def != null && !pd.isHelp()) { + String displayedDef = + Strings.isStringEmpty(def.toString()) ? "" : def.toString(); + String defaultText = "Default: " + (parameter.password() ? "********" : displayedDef); + + if (hasDescription) { + out.append(newLineAndIndent(indentCount)); + } else { + out.append(s(indentCount)); } + out.append(defaultText); + } + Class type = pd.getParameterized().getType(); + + if (type.isEnum()) { + String valueList = EnumSet.allOf((Class) type).toString(); + String possibleValues = "Possible Values: " + valueList; + + // Prevent duplicate values list, since it is set as 'Options: [values]' if the description + // of an enum field is empty in ParameterDescription#init(..) + if (!description.contains("Options: " + valueList)) { + if (hasDescription) { + out.append(newLineAndIndent(indentCount)); + } else { + out.append(s(indentCount)); + } + out.append(possibleValues); + } + } + out.append("\n"); + } + } + + /** + * Appends the details of all commands to the argument string builder, indenting every line with + * indentCount-many indent. The commands are obtained from calling {@link + * JCommander#getRawCommands()} and the commands are resolved using {@link + * JCommander#findCommandByAlias(String)} on the underlying commander instance. + * + * @param out the builder to append to + * @param indentCount the amount of indentation to apply + * @param descriptionIndent the indentation for the description + * @param indent the indentation + */ + public void appendCommands( + StringBuilder out, int indentCount, int descriptionIndent, String indent) { + boolean hasOnlyHiddenCommands = true; + for (Map.Entry commands : + commander.getRawCommands().entrySet()) { + Object arg = commands.getValue().getObjects().get(0); + Parameters p = arg.getClass().getAnnotation(Parameters.class); + + if (p == null || ((help && !p.hidden()) || (helpHidden && p.hidden()))) + hasOnlyHiddenCommands = false; + } - if (hasOnlyHiddenCommands) - return; + if (hasOnlyHiddenCommands) return; - out.append(indent + " Commands:\n"); + out.append(indent + " Commands:\n"); - // The magic value 3 is the number of spaces between the name of the option and its description - for (Map.Entry commands : commander.getRawCommands().entrySet()) { - Object arg = commands.getValue().getObjects().get(0); - Parameters p = arg.getClass().getAnnotation(Parameters.class); + // The magic value 3 is the number of spaces between the name of the option and its description + for (Map.Entry commands : + commander.getRawCommands().entrySet()) { + Object arg = commands.getValue().getObjects().get(0); + Parameters p = arg.getClass().getAnnotation(Parameters.class); - if (p == null || ((help && !p.hidden()) || (helpHidden && p.hidden()))) { - JCommander.ProgramName progName = commands.getKey(); - String dispName = progName.getDisplayName(); - String description = indent + s(4) + dispName + s(6) + getCommandDescription(progName.getName()); - wrapDescription(out, indentCount + descriptionIndent, description); - out.append("\n"); + if (p == null || ((help && !p.hidden()) || (helpHidden && p.hidden()))) { + JCommander.ProgramName progName = commands.getKey(); + String dispName = progName.getDisplayName(); + String description = + indent + s(4) + dispName + s(6) + getCommandDescription(progName.getName()); + wrapDescription(out, indentCount + descriptionIndent, description); + out.append("\n"); - // Options for this command - JCommander jc = commander.findCommandByAlias(progName.getName()); - jc.getUsageFormatter().usage(out, indent + s(6)); - out.append("\n"); - } - } + // Options for this command + JCommander jc = commander.findCommandByAlias(progName.getName()); + jc.getUsageFormatter().usage(out, indent + s(6)); + out.append("\n"); + } } - - /** - * Returns the description of the command corresponding to the argument command name. The commands are resolved - * by calling {@link JCommander#findCommandByAlias(String)}, and the default resource bundle used from - * {@link JCommander#getBundle()} on the underlying commander instance. - * - * @param commandName the name of the command to get the description for - * @return the description of the command. - */ - public String getCommandDescription(String commandName) { - JCommander jc = commander.findCommandByAlias(commandName); - - if (jc == null) { - throw new ParameterException("Asking description for unknown command: " + commandName); - } - Object arg = jc.getObjects().get(0); - Parameters p = arg.getClass().getAnnotation(Parameters.class); - java.util.ResourceBundle bundle; - String result = null; - - if (p != null) { - result = p.commandDescription(); - String bundleName = p.resourceBundle(); - - if (!bundleName.isEmpty()) { - bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); - } else { - bundle = commander.getBundle(); - } - - if (bundle != null) { - String descriptionKey = p.commandDescriptionKey(); - - if (!descriptionKey.isEmpty()) { - result = getI18nString(bundle, descriptionKey, p.commandDescription()); - } - } - } - return result; + } + + /** + * Returns the description of the command corresponding to the argument command name. The commands + * are resolved by calling {@link JCommander#findCommandByAlias(String)}, and the default resource + * bundle used from {@link JCommander#getBundle()} on the underlying commander instance. + * + * @param commandName the name of the command to get the description for + * @return the description of the command. + */ + public String getCommandDescription(String commandName) { + JCommander jc = commander.findCommandByAlias(commandName); + + if (jc == null) { + throw new ParameterException("Asking description for unknown command: " + commandName); } - - /** - * Wrap a potentially long line to the value obtained by calling {@link JCommander#getColumnSize()} on the - * underlying commander instance. - * - * @param out the output - * @param indent the indentation in spaces for lines after the first line. - * @param currentLineIndent the length of the indentation of the initial line - * @param description the text to wrap. No extra spaces are inserted before {@code - * description}. If the first line needs to be indented prepend the - * correct number of spaces to {@code description}. - */ - public void wrapDescription(StringBuilder out, int indent, int currentLineIndent, String description) { - int max = commander.getColumnSize(); - String[] words = description.split(" "); - int current = currentLineIndent; - - for (int i = 0; i < words.length; i++) { - String word = words[i]; - - if (word.length() > max || current + 1 + word.length() <= max) { - out.append(word); - current += word.length(); - - if (i != words.length - 1) { - out.append(" "); - current++; - } - } else { - out.append("\n").append(s(indent)).append(word).append(" "); - current = indent + word.length() + 1; - } + Object arg = jc.getObjects().get(0); + Parameters p = arg.getClass().getAnnotation(Parameters.class); + java.util.ResourceBundle bundle; + String result = null; + + if (p != null) { + result = p.commandDescription(); + String bundleName = p.resourceBundle(); + + if (!bundleName.isEmpty()) { + bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault()); + } else { + bundle = commander.getBundle(); + } + + if (bundle != null) { + String descriptionKey = p.commandDescriptionKey(); + + if (!descriptionKey.isEmpty()) { + result = getI18nString(bundle, descriptionKey, p.commandDescription()); } + } } - - /** - * Wrap a potentially long line to { @link #commander#getColumnSize()}. - * - * @param out the output - * @param indent the indentation in spaces for lines after the first line. - * @param description the text to wrap. No extra spaces are inserted before {@code - * description}. If the first line needs to be indented prepend the - * correct number of spaces to {@code description}. - * @see #wrapDescription(StringBuilder, int, int, String) - */ - public void wrapDescription(StringBuilder out, int indent, String description) { - wrapDescription(out, indent, 0, description); - } - - /** - * Returns the internationalized version of the string if available, otherwise it returns def. - * - * @return the internationalized version of the string if available, otherwise it returns def - */ - public static String getI18nString(ResourceBundle bundle, String key, String def) { - String s = bundle != null ? bundle.getString(key) : null; - return s != null ? s : def; - } - - /** - * Returns count-many spaces. - * - * @return count-many spaces - */ - public static String s(int count) { - StringBuilder result = new StringBuilder(); - - for (int i = 0; i < count; i++) { - result.append(" "); + return result; + } + + /** + * Wrap a potentially long line to the value obtained by calling {@link + * JCommander#getColumnSize()} on the underlying commander instance. + * + * @param out the output + * @param indent the indentation in spaces for lines after the first line. + * @param currentLineIndent the length of the indentation of the initial line + * @param description the text to wrap. No extra spaces are inserted before {@code description}. + * If the first line needs to be indented prepend the correct number of spaces to {@code + * description}. + */ + public void wrapDescription( + StringBuilder out, int indent, int currentLineIndent, String description) { + int max = commander.getColumnSize(); + String[] words = description.split(" "); + int current = currentLineIndent; + + for (int i = 0; i < words.length; i++) { + String word = words[i]; + + if (word.length() > max || current + 1 + word.length() <= max) { + out.append(word); + current += word.length(); + + if (i != words.length - 1) { + out.append(" "); + current++; } - return result.toString(); + } else { + out.append("\n").append(s(indent)).append(word).append(" "); + current = indent + word.length() + 1; + } } - - /** - * Returns new line followed by indent-many spaces. - * - * @return new line followed by indent-many spaces - */ - private static String newLineAndIndent(int indent) { - return "\n" + s(indent); + } + + /** + * Wrap a potentially long line to { @link #commander#getColumnSize()}. + * + * @param out the output + * @param indent the indentation in spaces for lines after the first line. + * @param description the text to wrap. No extra spaces are inserted before {@code description}. + * If the first line needs to be indented prepend the correct number of spaces to {@code + * description}. + * @see #wrapDescription(StringBuilder, int, int, String) + */ + public void wrapDescription(StringBuilder out, int indent, String description) { + wrapDescription(out, indent, 0, description); + } + + /** + * Returns the internationalized version of the string if available, otherwise it returns def. + * + * @return the internationalized version of the string if available, otherwise it returns def + */ + public static String getI18nString(ResourceBundle bundle, String key, String def) { + String s = bundle != null ? bundle.getString(key) : null; + return s != null ? s : def; + } + + /** + * Returns count-many spaces. + * + * @return count-many spaces + */ + public static String s(int count) { + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < count; i++) { + result.append(" "); } + return result.toString(); + } + + /** + * Returns new line followed by indent-many spaces. + * + * @return new line followed by indent-many spaces + */ + private static String newLineAndIndent(int indent) { + return "\n" + s(indent); + } } diff --git a/kernel/src/main/java/org/kframework/kore/convertors/KILTransformation.java b/kernel/src/main/java/org/kframework/kore/convertors/KILTransformation.java index 2a863b991ec..a62fb914812 100644 --- a/kernel/src/main/java/org/kframework/kore/convertors/KILTransformation.java +++ b/kernel/src/main/java/org/kframework/kore/convertors/KILTransformation.java @@ -6,42 +6,53 @@ import java.lang.invoke.MethodHandles; import java.lang.reflect.Method; import java.util.function.Function; - import org.kframework.kil.ASTNode; import org.kframework.utils.errorsystem.KEMException; public class KILTransformation implements Function { - @SuppressWarnings("serial") - static class VisitingException extends RuntimeException { - VisitingException(String message, Throwable e) { - super(message, e); - } + @SuppressWarnings("serial") + static class VisitingException extends RuntimeException { + VisitingException(String message, Throwable e) { + super(message, e); } + } - // DISABLE EXCEPTION CHECKING - public R apply(ASTNode t) { - try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Method visitMethod = this.getClass().getDeclaredMethod("apply", t.getClass()); - MethodHandle visitMethodHandle = lookup.unreflect(visitMethod); - return (R) visitMethodHandle.invoke(this, t); - } catch (NoSuchMethodException e) { - throw new VisitingException("Visitor " + this.getClass() - + " is missing a definition for visit(" + t.getClass() + ")" - + ". Encounteed when visiting " + makeErrorMessage(t), e); - // DISABLE EXCEPTION CHECKSTYLE - } catch (VisitingException | KEMException e) { - throw e; - } catch (Throwable e) { - throw new VisitingException(makeErrorMessage(t), e); - } - // ENABLE EXCEPTION CHECKSTYLE + // DISABLE EXCEPTION CHECKING + public R apply(ASTNode t) { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method visitMethod = this.getClass().getDeclaredMethod("apply", t.getClass()); + MethodHandle visitMethodHandle = lookup.unreflect(visitMethod); + return (R) visitMethodHandle.invoke(this, t); + } catch (NoSuchMethodException e) { + throw new VisitingException( + "Visitor " + + this.getClass() + + " is missing a definition for visit(" + + t.getClass() + + ")" + + ". Encounteed when visiting " + + makeErrorMessage(t), + e); + // DISABLE EXCEPTION CHECKSTYLE + } catch (VisitingException | KEMException e) { + throw e; + } catch (Throwable e) { + throw new VisitingException(makeErrorMessage(t), e); } - // ENABLE EXCEPTION CHECKING + // ENABLE EXCEPTION CHECKSTYLE + } - public String makeErrorMessage(ASTNode t) { - return t.toString() + " at location " + t.getLocation() + " in file " + t.getSource() - + " of class " + t.getClass().toString(); - } + // ENABLE EXCEPTION CHECKING + + public String makeErrorMessage(ASTNode t) { + return t.toString() + + " at location " + + t.getLocation() + + " in file " + + t.getSource() + + " of class " + + t.getClass().toString(); + } } diff --git a/kernel/src/main/java/org/kframework/kore/convertors/KILtoKORE.java b/kernel/src/main/java/org/kframework/kore/convertors/KILtoKORE.java index af9b5cbeecb..71f88cabb73 100644 --- a/kernel/src/main/java/org/kframework/kore/convertors/KILtoKORE.java +++ b/kernel/src/main/java/org/kframework/kore/convertors/KILtoKORE.java @@ -2,7 +2,15 @@ package org.kframework.kore.convertors; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Sets; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.attributes.Att; import org.kframework.attributes.Location; import org.kframework.attributes.Source; @@ -25,318 +33,382 @@ import org.kframework.utils.errorsystem.KEMException; import scala.collection.Seq; -import java.util.*; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - public class KILtoKORE extends KILTransformation { - private final org.kframework.kil.loader.Context context; - private final boolean syntactic; - private String moduleName; - private final boolean bisonLists; - - public KILtoKORE(org.kframework.kil.loader.Context context, boolean syntactic, boolean bisonLists) { - this.context = context; - this.syntactic = syntactic; - this.bisonLists = bisonLists; - } - - public FlatModule toFlatModule(Module m) { - CheckListDecl.check(m); - CheckBracket.check(m); - moduleName = m.getName(); - - Set items = m.getItems().stream() - .filter(j -> !(j instanceof org.kframework.kil.Import)) - .flatMap(j -> apply(j).stream()).collect(Collectors.toSet()); - - // temporarily declare cell sorts used in the RHS of productions until we - // can parse the configuration so Module checks don't fail - Set tempCellSorts = items.stream().filter(p -> p instanceof org.kframework.definition.Production) - .map(p -> (org.kframework.definition.Production) p) - .flatMap(p -> stream(p.items()).filter(itm -> itm instanceof org.kframework.definition.NonTerminal) - .map(i -> (org.kframework.definition.NonTerminal) i) - .flatMap(nt -> nt.sort().name().endsWith("Cell") || nt.sort().name().endsWith("CellFragment") ? - Stream.of(SyntaxSort.apply(Seq(), nt.sort(), Att.empty().add(Att.TEMPORARY_CELL_SORT_DECL()))) : Stream.of()) - ).collect(Collectors.toSet()); - items.addAll(tempCellSorts); - - Set importedModuleNames = m.getItems().stream() - .filter(imp -> imp instanceof Import) - .map(imp -> apply((Import)imp)) - .collect(Collectors.toSet()); - - Att att = convertAttributes(m); - att = att.add(Att.DIGEST(), m.digest()); - - return new FlatModule(moduleName, immutable(importedModuleNames), immutable(items), att); - } - - public org.kframework.definition.FlatImport apply(Import imp) { - return org.kframework.definition.FlatImport.apply(imp.getName(), imp.isPublic(), convertAttributes(imp)); + private final org.kframework.kil.loader.Context context; + private final boolean syntactic; + private String moduleName; + private final boolean bisonLists; + + public KILtoKORE( + org.kframework.kil.loader.Context context, boolean syntactic, boolean bisonLists) { + this.context = context; + this.syntactic = syntactic; + this.bisonLists = bisonLists; + } + + public FlatModule toFlatModule(Module m) { + CheckListDecl.check(m); + CheckBracket.check(m); + moduleName = m.getName(); + + Set items = + m.getItems().stream() + .filter(j -> !(j instanceof org.kframework.kil.Import)) + .flatMap(j -> apply(j).stream()) + .collect(Collectors.toSet()); + + // temporarily declare cell sorts used in the RHS of productions until we + // can parse the configuration so Module checks don't fail + Set tempCellSorts = + items.stream() + .filter(p -> p instanceof org.kframework.definition.Production) + .map(p -> (org.kframework.definition.Production) p) + .flatMap( + p -> + stream(p.items()) + .filter(itm -> itm instanceof org.kframework.definition.NonTerminal) + .map(i -> (org.kframework.definition.NonTerminal) i) + .flatMap( + nt -> + nt.sort().name().endsWith("Cell") + || nt.sort().name().endsWith("CellFragment") + ? Stream.of( + SyntaxSort.apply( + Seq(), + nt.sort(), + Att.empty().add(Att.TEMPORARY_CELL_SORT_DECL()))) + : Stream.of())) + .collect(Collectors.toSet()); + items.addAll(tempCellSorts); + + Set importedModuleNames = + m.getItems().stream() + .filter(imp -> imp instanceof Import) + .map(imp -> apply((Import) imp)) + .collect(Collectors.toSet()); + + Att att = convertAttributes(m); + att = att.add(Att.DIGEST(), m.digest()); + + return new FlatModule(moduleName, immutable(importedModuleNames), immutable(items), att); + } + + public org.kframework.definition.FlatImport apply(Import imp) { + return org.kframework.definition.FlatImport.apply( + imp.getName(), imp.isPublic(), convertAttributes(imp)); + } + + public org.kframework.definition.Definition apply(Definition d) { + Set kilModules = + d.getItems().stream() + .filter(i -> i instanceof Module) + .map(mod -> (Module) mod) + .collect(Collectors.toSet()); + + List flatModules = + kilModules.stream() + .map(this::toFlatModule) + .sorted(Comparator.comparing(FlatModule::name)) + .collect(Collectors.toList()); + scala.collection.Set koreModules = + FlatModule.toModules(immutable(flatModules), Set()); + + return Definition( + koreModules + .find(x -> x.name().equals(d.getMainModule())) + .getOrElse( + () -> { + throw new AssertionError( + "Could not find main module name: " + + d.getMainModule() + + " when loading from front-end classes."); + }), + koreModules, + Att()); + } + + @SuppressWarnings("unchecked") + public Set apply(ModuleItem i) { + if (i instanceof Syntax || i instanceof PriorityExtended) { + return (Set) apply((ASTNode) i); + } else { + return Sets.newHashSet((org.kframework.definition.Sentence) apply((ASTNode) i)); } + } - public org.kframework.definition.Definition apply(Definition d) { - Set kilModules = d.getItems().stream().filter(i -> i instanceof Module) - .map(mod -> (Module) mod).collect(Collectors.toSet()); + public org.kframework.definition.Sentence apply(SortSynonym synonym) { + return new org.kframework.definition.SortSynonym( + synonym.newSort, synonym.oldSort, convertAttributes(synonym)); + } - List flatModules = kilModules.stream().map(this::toFlatModule).sorted(Comparator.comparing(FlatModule::name)).collect(Collectors.toList()); - scala.collection.Set koreModules = FlatModule.toModules(immutable(flatModules), Set()); + public org.kframework.definition.Sentence apply(SyntaxLexical lexical) { + return new org.kframework.definition.SyntaxLexical( + lexical.name, lexical.regex, convertAttributes(lexical)); + } - return Definition( - koreModules.find(x -> x.name().equals(d.getMainModule())) - .getOrElse(() -> { throw new AssertionError("Could not find main module name: " + d.getMainModule() + " when loading from front-end classes."); }), - koreModules, Att()); - } - - @SuppressWarnings("unchecked") - public Set apply(ModuleItem i) { - if (i instanceof Syntax || i instanceof PriorityExtended) { - return (Set) apply((ASTNode) i); - } else { - return Sets.newHashSet((org.kframework.definition.Sentence) apply((ASTNode) i)); - } - } - - public org.kframework.definition.Sentence apply(SortSynonym synonym) { - return new org.kframework.definition.SortSynonym(synonym.newSort, synonym.oldSort, convertAttributes(synonym)); - } - - public org.kframework.definition.Sentence apply(SyntaxLexical lexical) { - return new org.kframework.definition.SyntaxLexical(lexical.name, lexical.regex, convertAttributes(lexical)); - } - - - public org.kframework.definition.Bubble apply(StringSentence sentence) { - org.kframework.attributes.Att attrs = - convertAttributes(sentence) + public org.kframework.definition.Bubble apply(StringSentence sentence) { + org.kframework.attributes.Att attrs = + convertAttributes(sentence) .add(Att.CONTENT_START_LINE(), sentence.getContentStartLine()) .add(Att.CONTENT_START_COLUMN(), sentence.getContentStartColumn()); - String label = sentence.getLabel(); - if (!label.isEmpty()) { - attrs = attrs.add(Att.LABEL(), sentence.getType().equals(Att.ALIAS().key()) ? label : moduleName + "." + label); - } - - return Bubble(sentence.getType(), sentence.getContent(), attrs); - } - - public org.kframework.definition.SyntaxAssociativity apply(PriorityExtendedAssoc ii) { - scala.collection.Set tags = toTags(ii.getTags(), ii); - String assocOrig = ii.getAssoc(); - Associativity assoc = applyAssoc(assocOrig); - return SyntaxAssociativity(assoc, tags, convertAttributes(ii)); - } - - public Associativity applyAssoc(String assocOrig) { - // "left", "right", "non-assoc" - return switch (assocOrig) { - case "left" -> Associativity.Left; - case "right" -> Associativity.Right; - case "non-assoc" -> Associativity.NonAssoc; - default -> throw new AssertionError("Incorrect assoc string: " + assocOrig); - }; + String label = sentence.getLabel(); + if (!label.isEmpty()) { + attrs = + attrs.add( + Att.LABEL(), + sentence.getType().equals(Att.ALIAS().key()) ? label : moduleName + "." + label); } - public Set apply(PriorityExtended pe) { - Seq> seqOfSetOfTags = immutable(pe.getPriorityBlocks() - .stream().map(block -> toTags(block.getProductions(), pe)) + return Bubble(sentence.getType(), sentence.getContent(), attrs); + } + + public org.kframework.definition.SyntaxAssociativity apply(PriorityExtendedAssoc ii) { + scala.collection.Set tags = toTags(ii.getTags(), ii); + String assocOrig = ii.getAssoc(); + Associativity assoc = applyAssoc(assocOrig); + return SyntaxAssociativity(assoc, tags, convertAttributes(ii)); + } + + public Associativity applyAssoc(String assocOrig) { + // "left", "right", "non-assoc" + return switch (assocOrig) { + case "left" -> Associativity.Left; + case "right" -> Associativity.Right; + case "non-assoc" -> Associativity.NonAssoc; + default -> throw new AssertionError("Incorrect assoc string: " + assocOrig); + }; + } + + public Set apply(PriorityExtended pe) { + Seq> seqOfSetOfTags = + immutable( + pe.getPriorityBlocks().stream() + .map(block -> toTags(block.getProductions(), pe)) .collect(Collectors.toList())); - return Sets.newHashSet(SyntaxPriority(seqOfSetOfTags)); + return Sets.newHashSet(SyntaxPriority(seqOfSetOfTags)); + } + + public scala.collection.Set toTags(List labels, ASTNode loc) { + return immutable( + labels.stream() + .flatMap( + l -> { + java.util.Set productions = context.tags.get(l.name()); + if (productions.isEmpty()) + throw KEMException.outerParserError( + "Could not find any productions for tag: " + l.name(), + loc.getSource(), + loc.getLocation()); + return productions.stream() + .map( + p -> { + String label = p.getKLabel(true); + if (label == null && p.getAttributes().contains(Att.BRACKET())) { + label = p.getBracketLabel(true); + } + return Tag(label); + }); + }) + .collect(Collectors.toSet())); + } + + public Set apply(Syntax s) { + Set res = new HashSet<>(); + + org.kframework.kore.Sort sort = s.getDeclaredSort().getSort(); + + // just a sort declaration + if (s.getPriorityBlocks().size() == 0) { + res.add(SyntaxSort(immutable(s.getParams()), sort, convertAttributes(s))); + return res; } - public scala.collection.Set toTags(List labels, ASTNode loc) { - return immutable(labels.stream().flatMap(l -> { - java.util.Set productions = context.tags.get(l.name()); - if (productions.isEmpty()) - throw KEMException.outerParserError("Could not find any productions for tag: " + l.name(), loc.getSource(), loc.getLocation()); - return productions.stream().map(p -> { - String label = p.getKLabel(true); - if (label == null && p.getAttributes().contains(Att.BRACKET())) { - label = p.getBracketLabel(true); - } - return Tag(label); - }); - }).collect(Collectors.toSet())); + Function> applyToTags = + (PriorityBlock b) -> + immutable( + Stream.concat( + b.getProductions().stream() + .filter(p -> p.getKLabel(true) != null) + .map(p -> Tag(p.getKLabel(true))), + b.getProductions().stream() + .filter(p -> p.containsAttribute(Att.BRACKET())) + .map(p -> Tag(p.getBracketLabel(true)))) + .collect(Collectors.toSet())); + + if (s.getPriorityBlocks().size() > 1) { + res.add( + SyntaxPriority( + immutable( + s.getPriorityBlocks().stream().map(applyToTags).collect(Collectors.toList())))); } - public Set apply(Syntax s) { - Set res = new HashSet<>(); - - org.kframework.kore.Sort sort = s.getDeclaredSort().getSort(); - - // just a sort declaration - if (s.getPriorityBlocks().size() == 0) { - res.add(SyntaxSort(immutable(s.getParams()), sort, convertAttributes(s))); - return res; - } - - Function> applyToTags = (PriorityBlock b) -> immutable(Stream.concat(b - .getProductions().stream().filter(p -> p.getKLabel(true) != null).map(p -> Tag(p.getKLabel(true))), - b.getProductions().stream().filter(p -> p.containsAttribute(Att.BRACKET())).map(p -> Tag(p.getBracketLabel(true)))) - .collect(Collectors.toSet())); - - if (s.getPriorityBlocks().size() > 1) { - res.add(SyntaxPriority(immutable(s.getPriorityBlocks().stream().map(applyToTags) - .collect(Collectors.toList())))); - } - - // there are some productions - for (PriorityBlock b : s.getPriorityBlocks()) { - if (!b.getAssoc().equals("")) { - Associativity assoc = applyAssoc(b.getAssoc()); - res.add(SyntaxAssociativity(assoc, applyToTags.apply(b))); - } - - for (Production p : b.getProductions()) { - if (p.containsAttribute(Att.REJECT())) // skip productions of the old reject type - continue; - // Handle a special case first: List productions have only - // one item. - if (p.getItems().size() == 1 && p.getItems().get(0) instanceof UserList) { - applyUserList(res, sort, p, (UserList) p.getItems().get(0)); - } else { - List items = new ArrayList<>(); - for (org.kframework.kil.ProductionItem it : p.getItems()) { - if (it instanceof NonTerminal nt) { - items.add(NonTerminal(nt.getSort(), nt.getName())); - } else if (it instanceof UserList) { - throw new AssertionError("Lists should have applied before."); - } else if (it instanceof Lexical) { - String regex; - if (p.containsAttribute(Att.REGEX())) - regex = p.getAttribute(Att.REGEX()); - else - regex = ((Lexical) it).getLexicalRule(); - RegexTerminal regexTerminal = getRegexTerminal(regex); - - items.add(regexTerminal); - } else if (it instanceof Terminal) { - items.add(Terminal(((Terminal) it).getTerminal())); - } else { - throw new AssertionError("Unhandled case"); - } - } - - org.kframework.attributes.Att attrs = convertAttributes(p); - if (attrs.contains(Att.BRACKET())) { - attrs = attrs.add(Att.BRACKET_LABEL(), KLabel.class, KLabel(p.getBracketLabel(true), immutable(p.getParams()))); - } - - org.kframework.definition.Production prod; - if (p.getKLabel(true) == null) - prod = Production( - immutable(p.getParams()), - sort, - immutable(items), - attrs); - else - prod = Production( - KLabel(p.getKLabel(true), immutable(p.getParams())), - sort, - immutable(items), - attrs); - - res.add(prod); - // handle associativity for the production - if (p.containsAttribute(Att.LEFT())) - res.add(SyntaxAssociativity(applyAssoc("left"), Set(Tag(p.getKLabel(true))))); - else if (p.containsAttribute(Att.RIGHT())) - res.add(SyntaxAssociativity(applyAssoc("right"), Set(Tag(p.getKLabel(true))))); - else if (p.containsAttribute(Att.NON_ASSOC())) - res.add(SyntaxAssociativity(applyAssoc("non-assoc"), Set(Tag(p.getKLabel(true))))); - } + // there are some productions + for (PriorityBlock b : s.getPriorityBlocks()) { + if (!b.getAssoc().equals("")) { + Associativity assoc = applyAssoc(b.getAssoc()); + res.add(SyntaxAssociativity(assoc, applyToTags.apply(b))); + } + + for (Production p : b.getProductions()) { + if (p.containsAttribute(Att.REJECT())) // skip productions of the old reject type + continue; + // Handle a special case first: List productions have only + // one item. + if (p.getItems().size() == 1 && p.getItems().get(0) instanceof UserList) { + applyUserList(res, sort, p, (UserList) p.getItems().get(0)); + } else { + List items = new ArrayList<>(); + for (org.kframework.kil.ProductionItem it : p.getItems()) { + if (it instanceof NonTerminal nt) { + items.add(NonTerminal(nt.getSort(), nt.getName())); + } else if (it instanceof UserList) { + throw new AssertionError("Lists should have applied before."); + } else if (it instanceof Lexical) { + String regex; + if (p.containsAttribute(Att.REGEX())) regex = p.getAttribute(Att.REGEX()); + else regex = ((Lexical) it).getLexicalRule(); + RegexTerminal regexTerminal = getRegexTerminal(regex); + + items.add(regexTerminal); + } else if (it instanceof Terminal) { + items.add(Terminal(((Terminal) it).getTerminal())); + } else { + throw new AssertionError("Unhandled case"); } + } + + org.kframework.attributes.Att attrs = convertAttributes(p); + if (attrs.contains(Att.BRACKET())) { + attrs = + attrs.add( + Att.BRACKET_LABEL(), + KLabel.class, + KLabel(p.getBracketLabel(true), immutable(p.getParams()))); + } + + org.kframework.definition.Production prod; + if (p.getKLabel(true) == null) + prod = Production(immutable(p.getParams()), sort, immutable(items), attrs); + else + prod = + Production( + KLabel(p.getKLabel(true), immutable(p.getParams())), + sort, + immutable(items), + attrs); + + res.add(prod); + // handle associativity for the production + if (p.containsAttribute(Att.LEFT())) + res.add(SyntaxAssociativity(applyAssoc("left"), Set(Tag(p.getKLabel(true))))); + else if (p.containsAttribute(Att.RIGHT())) + res.add(SyntaxAssociativity(applyAssoc("right"), Set(Tag(p.getKLabel(true))))); + else if (p.containsAttribute(Att.NON_ASSOC())) + res.add(SyntaxAssociativity(applyAssoc("non-assoc"), Set(Tag(p.getKLabel(true))))); } - return res; + } } - - public static RegexTerminal getRegexTerminal(String regex) { - String precede = "#"; - if (regex.startsWith("(? 0 && regex.charAt(followIndex - 1) == '\\')) { - follow = regex.substring(followIndex + "(?!".length(), regex.length() - 1); - regex = regex.substring(0, followIndex); - } + if (regex.charAt(i) == '(') depth++; + if (regex.charAt(i) == ')') depth--; + if (depth == 0) { + precede = regex.substring("(? res, - org.kframework.kore.Sort sort, Production p, UserList userList) { - - // Transform list declarations of the form Es ::= List{E, ","} into something representable in kore - org.kframework.kore.Sort elementSort = userList.getSort(); - - org.kframework.attributes.Att attrs = convertAttributes(p).add(Att.USER_LIST(), userList.getListType()); - String kilProductionId = "" + System.identityHashCode(p); - org.kframework.definition.Production prod1, prod3; - - - if (bisonLists) { - // Es ::= Es "," E - prod1 = Production(KLabel(p.getKLabel(true), immutable(p.getParams())), sort, - Seq(NonTerminal(sort), Terminal(userList.getSeparator()), NonTerminal(elementSort)), attrs); - } else { - // Es ::= E "," Es - prod1 = Production(KLabel(p.getKLabel(true), immutable(p.getParams())), sort, - Seq(NonTerminal(elementSort), Terminal(userList.getSeparator()), NonTerminal(sort)), attrs); - } - - - // Es ::= ".Es" - prod3 = Production(KLabel(p.getTerminatorKLabel(true), immutable(p.getParams())), sort, Seq(Terminal("." + sort.toString())), - attrs.remove(Att.FORMAT()).remove(Att.STRICT()).add(Att.KLABEL(), p.getTerminatorKLabel(false))); - - res.add(prod1); - res.add(prod3); - } - - public static org.kframework.attributes.Att convertAttributes(ASTNode t) { - Att attributes = ProcessGroupAttributes.getProcessedAtt(t.getAttributes(), t); - - return attributes - .addAll(attributesFromLocation(t.getLocation())) - .addAll(attributesFromSource(t.getSource())); + String follow = "#"; + int followIndex = regex.lastIndexOf("(?!"); + if (followIndex != -1 && regex.endsWith(")")) { // find the follow pattern at the end: (?!X) + if (!(followIndex > 0 && regex.charAt(followIndex - 1) == '\\')) { + follow = regex.substring(followIndex + "(?!".length(), regex.length() - 1); + regex = regex.substring(0, followIndex); + } } - - private static Att attributesFromSource(Source source) { - if (source != null) { - return Att().add(Source.class, source); - } - return Att(); + return RegexTerminal(precede, regex, follow); + } + + public void applyUserList( + Set res, + org.kframework.kore.Sort sort, + Production p, + UserList userList) { + + // Transform list declarations of the form Es ::= List{E, ","} into something representable in + // kore + org.kframework.kore.Sort elementSort = userList.getSort(); + + org.kframework.attributes.Att attrs = + convertAttributes(p).add(Att.USER_LIST(), userList.getListType()); + String kilProductionId = "" + System.identityHashCode(p); + org.kframework.definition.Production prod1, prod3; + + if (bisonLists) { + // Es ::= Es "," E + prod1 = + Production( + KLabel(p.getKLabel(true), immutable(p.getParams())), + sort, + Seq(NonTerminal(sort), Terminal(userList.getSeparator()), NonTerminal(elementSort)), + attrs); + } else { + // Es ::= E "," Es + prod1 = + Production( + KLabel(p.getKLabel(true), immutable(p.getParams())), + sort, + Seq(NonTerminal(elementSort), Terminal(userList.getSeparator()), NonTerminal(sort)), + attrs); } - private static org.kframework.attributes.Att attributesFromLocation(Location location) { - if (location != null) { - return Att().add(Location.class, location); - } else - return Att(); + // Es ::= ".Es" + prod3 = + Production( + KLabel(p.getTerminatorKLabel(true), immutable(p.getParams())), + sort, + Seq(Terminal("." + sort.toString())), + attrs + .remove(Att.FORMAT()) + .remove(Att.STRICT()) + .add(Att.KLABEL(), p.getTerminatorKLabel(false))); + + res.add(prod1); + res.add(prod3); + } + + public static org.kframework.attributes.Att convertAttributes(ASTNode t) { + Att attributes = ProcessGroupAttributes.getProcessedAtt(t.getAttributes(), t); + + return attributes + .addAll(attributesFromLocation(t.getLocation())) + .addAll(attributesFromSource(t.getSource())); + } + + private static Att attributesFromSource(Source source) { + if (source != null) { + return Att().add(Source.class, source); } - + return Att(); + } + + private static org.kframework.attributes.Att attributesFromLocation(Location location) { + if (location != null) { + return Att().add(Location.class, location); + } else return Att(); + } } diff --git a/kernel/src/main/java/org/kframework/kprove/KProve.java b/kernel/src/main/java/org/kframework/kprove/KProve.java index 528b4ef23cb..20cc944a84b 100644 --- a/kernel/src/main/java/org/kframework/kprove/KProve.java +++ b/kernel/src/main/java/org/kframework/kprove/KProve.java @@ -1,7 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kprove; +import static org.kframework.Collections.*; + import com.google.inject.Inject; +import java.nio.charset.StandardCharsets; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; import org.kframework.RewriterResult; import org.kframework.definition.Definition; import org.kframework.definition.Module; @@ -9,7 +15,6 @@ import org.kframework.rewriter.Rewriter; import org.kframework.unparser.KPrint; import org.kframework.unparser.ToJson; -import org.kframework.utils.BinaryLoader; import org.kframework.utils.Stopwatch; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KException; @@ -17,72 +22,82 @@ import org.kframework.utils.file.FileUtil; import scala.Tuple2; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.util.Set; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; - public record KProve( - KExceptionManager kem, - FileUtil files, - KPrint kprint, - KProveOptions kproveOptions, - CompiledDefinition compiledDefinition, - ProofDefinitionBuilder proofDefinitionBuilder, - Function rewriterGenerator, - Stopwatch sw -) { - private static final int KPROVE_SUCCESS_EXIT_CODE = 0; - private static final int KPROVE_MISMATCH_CONFIG_CODE = 1; - - @Inject - public KProve {} + KExceptionManager kem, + FileUtil files, + KPrint kprint, + KProveOptions kproveOptions, + CompiledDefinition compiledDefinition, + ProofDefinitionBuilder proofDefinitionBuilder, + Function rewriterGenerator, + Stopwatch sw) { + private static final int KPROVE_SUCCESS_EXIT_CODE = 0; + private static final int KPROVE_MISMATCH_CONFIG_CODE = 1; - public int run() { - if (!kproveOptions.specFile(files).exists()) { - throw KEMException.criticalError("Definition file doesn't exist: " + - kproveOptions.specFile(files).getAbsolutePath()); - } + @Inject + public KProve {} - Tuple2 compiled = proofDefinitionBuilder - .build(kproveOptions.specFile(files), kproveOptions.specModule, compiledDefinition.kompileOptions.readOnlyKompiledDirectory); + public int run() { + if (!kproveOptions.specFile(files).exists()) { + throw KEMException.criticalError( + "Definition file doesn't exist: " + kproveOptions.specFile(files).getAbsolutePath()); + } - Rewriter rewriter = rewriterGenerator.apply(compiled._1()); - Module specModule = compiled._2(); + Tuple2 compiled = + proofDefinitionBuilder.build( + kproveOptions.specFile(files), + kproveOptions.specModule, + compiledDefinition.kompileOptions.readOnlyKompiledDirectory); - if (kproveOptions.emitJson) { - files.saveToKompiled("prove-definition.json", new String(ToJson.apply(compiled._1()), StandardCharsets.UTF_8)); - } + Rewriter rewriter = rewriterGenerator.apply(compiled._1()); + Module specModule = compiled._2(); - if (kproveOptions.emitJsonSpec != null) { - Set names = stream(compiled._1().modules()).map(Module::name).collect(Collectors.toSet()); - Set specMods = stream(specModule.importedModules()).filter(m -> !names.contains(m.name())).collect(Collectors.toSet()); - specMods.add(specModule); - files.saveToWorkingDirectory(kproveOptions.emitJsonSpec, ToJson.apply(specMods, specModule.name())); - } + if (kproveOptions.emitJson) { + files.saveToKompiled( + "prove-definition.json", new String(ToJson.apply(compiled._1()), StandardCharsets.UTF_8)); + } - RewriterResult results = rewriter.prove(specModule, true); - sw.printIntermediate("Backend"); - kprint.prettyPrint(compiled._1(), compiled._1().getModule("LANGUAGE-PARSING").get(), kprint::outputFile, - results.k()); - sw.printTotal("Total"); + if (kproveOptions.emitJsonSpec != null) { + Set names = + stream(compiled._1().modules()).map(Module::name).collect(Collectors.toSet()); + Set specMods = + stream(specModule.importedModules()) + .filter(m -> !names.contains(m.name())) + .collect(Collectors.toSet()); + specMods.add(specModule); + files.saveToWorkingDirectory( + kproveOptions.emitJsonSpec, ToJson.apply(specMods, specModule.name())); + } - int errCode = results.exitCode().orElse(0); - switch (errCode) { - case KPROVE_SUCCESS_EXIT_CODE -> {} - case KPROVE_MISMATCH_CONFIG_CODE -> { - kem.addKException(new KException(KException.ExceptionType.ERROR, KException.KExceptionGroup.PROVER, - "backend terminated because the configuration cannot be rewritten further. See output for more details.")); - } - default -> { - kem.addKException(new KException(KException.ExceptionType.ERROR, KException.KExceptionGroup.PROVER, - "backend crashed with exit code " + errCode)); - } - } + RewriterResult results = rewriter.prove(specModule, true); + sw.printIntermediate("Backend"); + kprint.prettyPrint( + compiled._1(), + compiled._1().getModule("LANGUAGE-PARSING").get(), + kprint::outputFile, + results.k()); + sw.printTotal("Total"); - return results.exitCode().orElse(KEMException.TERMINATED_WITH_ERRORS_EXIT_CODE); + int errCode = results.exitCode().orElse(0); + switch (errCode) { + case KPROVE_SUCCESS_EXIT_CODE -> {} + case KPROVE_MISMATCH_CONFIG_CODE -> { + kem.addKException( + new KException( + KException.ExceptionType.ERROR, + KException.KExceptionGroup.PROVER, + "backend terminated because the configuration cannot be rewritten further. See" + + " output for more details.")); + } + default -> { + kem.addKException( + new KException( + KException.ExceptionType.ERROR, + KException.KExceptionGroup.PROVER, + "backend crashed with exit code " + errCode)); + } } + + return results.exitCode().orElse(KEMException.TERMINATED_WITH_ERRORS_EXIT_CODE); + } } diff --git a/kernel/src/main/java/org/kframework/kprove/KProveFrontEnd.java b/kernel/src/main/java/org/kframework/kprove/KProveFrontEnd.java index 7b9c291bfe3..4350d6f78c1 100644 --- a/kernel/src/main/java/org/kframework/kprove/KProveFrontEnd.java +++ b/kernel/src/main/java/org/kframework/kprove/KProveFrontEnd.java @@ -5,6 +5,8 @@ import com.google.inject.Inject; import com.google.inject.Module; import com.google.inject.Provider; +import java.io.File; +import java.util.List; import org.kframework.main.FrontEnd; import org.kframework.main.GlobalOptions; import org.kframework.utils.errorsystem.KExceptionManager; @@ -16,48 +18,43 @@ import org.kframework.utils.inject.DefinitionScope; import org.kframework.utils.inject.JCommanderModule; -import java.io.File; -import java.util.List; - public class KProveFrontEnd extends FrontEnd { - - public static List getModules() { - return ImmutableList.of( - new KProveModule(), - new CommonModule(), - new JCommanderModule(), - new DefinitionLoadingModule()); - } - - - private final DefinitionScope scope; - private final Provider kompiledDir; - private final Provider kprove; - - @Inject - KProveFrontEnd( - GlobalOptions options, - @JCommanderModule.Usage String usage, - JarInfo jarInfo, - DefinitionScope scope, - @KompiledDir Provider kompiledDir, - KExceptionManager kem, - Provider files, - Provider kprove) { - super(kem, options, usage, jarInfo, files); - this.scope = scope; - this.kompiledDir = kompiledDir; - this.kprove = kprove; - } - - @Override - protected int run() { - scope.enter(kompiledDir.get()); - try { - return kprove.get().run(); - } finally { - scope.exit(); - } + public static List getModules() { + return ImmutableList.of( + new KProveModule(), + new CommonModule(), + new JCommanderModule(), + new DefinitionLoadingModule()); + } + + private final DefinitionScope scope; + private final Provider kompiledDir; + private final Provider kprove; + + @Inject + KProveFrontEnd( + GlobalOptions options, + @JCommanderModule.Usage String usage, + JarInfo jarInfo, + DefinitionScope scope, + @KompiledDir Provider kompiledDir, + KExceptionManager kem, + Provider files, + Provider kprove) { + super(kem, options, usage, jarInfo, files); + this.scope = scope; + this.kompiledDir = kompiledDir; + this.kprove = kprove; + } + + @Override + protected int run() { + scope.enter(kompiledDir.get()); + try { + return kprove.get().run(); + } finally { + scope.exit(); } + } } diff --git a/kernel/src/main/java/org/kframework/kprove/KProveModule.java b/kernel/src/main/java/org/kframework/kprove/KProveModule.java index ca375b76ad7..487f9b8ccb1 100644 --- a/kernel/src/main/java/org/kframework/kprove/KProveModule.java +++ b/kernel/src/main/java/org/kframework/kprove/KProveModule.java @@ -18,47 +18,56 @@ import org.kframework.utils.options.SMTOptions; public class KProveModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(FrontEnd.class).to(KProveFrontEnd.class); - bind(Tool.class).toInstance(Tool.KPROVE); + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(FrontEnd.class).to(KProveFrontEnd.class); + bind(Tool.class).toInstance(Tool.KPROVE); - install(new BackendModule()); - install(new RewriterModule()); + install(new BackendModule()); + install(new RewriterModule()); - Multibinder optionsBinder = Multibinder.newSetBinder(binder(), Object.class, Options.class); - optionsBinder.addBinding().to(KProveOptions.class); - } + Multibinder optionsBinder = + Multibinder.newSetBinder(binder(), Object.class, Options.class); + optionsBinder.addBinding().to(KProveOptions.class); + } - @Provides @RequestScoped - GlobalOptions globalOptions(KProveOptions options) { - return options.getGlobalOptions_useOnlyInGuiceProvider(); - } + @Provides + @RequestScoped + GlobalOptions globalOptions(KProveOptions options) { + return options.getGlobalOptions_useOnlyInGuiceProvider(); + } - @Provides @RequestScoped - OuterParsingOptions outerParsingOptions(KProveOptions options) { return options.outerParsing; } + @Provides + @RequestScoped + OuterParsingOptions outerParsingOptions(KProveOptions options) { + return options.outerParsing; + } - @Provides @RequestScoped - InnerParsingOptions InnerParsingOptions(KProveOptions options) { return options.innerParsing; } + @Provides + @RequestScoped + InnerParsingOptions InnerParsingOptions(KProveOptions options) { + return options.innerParsing; + } - @Provides @RequestScoped - PrintOptions printOptions(KProveOptions options) { - return options.print; - } + @Provides + @RequestScoped + PrintOptions printOptions(KProveOptions options) { + return options.print; + } - @Provides - DefinitionLoadingOptions loadingOptions(KProveOptions options) { - return options.definitionLoading; - } + @Provides + DefinitionLoadingOptions loadingOptions(KProveOptions options) { + return options.definitionLoading; + } - @Provides - BackendOptions backendOptions(KProveOptions options) { - return options.backend; - } + @Provides + BackendOptions backendOptions(KProveOptions options) { + return options.backend; + } - @Provides - SMTOptions smtOptions(KProveOptions options) { - return options.smt; - } + @Provides + SMTOptions smtOptions(KProveOptions options) { + return options.smt; + } } diff --git a/kernel/src/main/java/org/kframework/kprove/KProveOptions.java b/kernel/src/main/java/org/kframework/kprove/KProveOptions.java index d25a5b6b6c3..57921f54583 100644 --- a/kernel/src/main/java/org/kframework/kprove/KProveOptions.java +++ b/kernel/src/main/java/org/kframework/kprove/KProveOptions.java @@ -5,8 +5,10 @@ import com.beust.jcommander.Parameter; import com.beust.jcommander.ParametersDelegate; import com.google.inject.Inject; -import org.kframework.unparser.PrintOptions; +import java.io.File; +import java.util.List; import org.kframework.main.GlobalOptions; +import org.kframework.unparser.PrintOptions; import org.kframework.utils.file.FileUtil; import org.kframework.utils.inject.RequestScoped; import org.kframework.utils.options.BackendOptions; @@ -15,83 +17,96 @@ import org.kframework.utils.options.OuterParsingOptions; import org.kframework.utils.options.SMTOptions; -import java.io.File; -import java.util.Collections; -import java.util.List; - @RequestScoped public class KProveOptions { - @Inject - public KProveOptions() {} - - @ParametersDelegate - private final transient GlobalOptions global = new GlobalOptions(); - - /** - * Use only in the Guice Provider method, so it can replace the GlobalOptions from kompile. - */ - public GlobalOptions getGlobalOptions_useOnlyInGuiceProvider() { - return global; - } - - @ParametersDelegate - public DefinitionLoadingOptions definitionLoading = new DefinitionLoadingOptions(); - - @ParametersDelegate - public OuterParsingOptions outerParsing = new OuterParsingOptions(); - - @ParametersDelegate - public InnerParsingOptions innerParsing = new InnerParsingOptions(); - - private File specFile; - - public synchronized File specFile(FileUtil files) { - return outerParsing.mainDefinitionFile(files); - } - - @ParametersDelegate - public BackendOptions backend = new BackendOptions(); - - @ParametersDelegate - public SMTOptions smt = new SMTOptions(); - - @ParametersDelegate - public PrintOptions print = new PrintOptions(); - - @Parameter(names="--branching-allowed", descriptionKey = "number", arity = 1, - description="Number of branching events allowed before a forcible stop.") - public int branchingAllowed = Integer.MAX_VALUE; - - @Parameter(names={"--spec-module", "-sm"}, descriptionKey = "name", - description="Name of module containing specification to prove") - public String specModule; - - @Parameter(names="--depth", descriptionKey = "number", - description="The maximum number of computational steps to prove") - public Integer depth; - - @Parameter(names="--trusted", descriptionKey = "labels", - description="Mark this comma separated list of claims as [trusted]") - public List trusted = null; - - @Parameter(names="--exclude", descriptionKey = "labels", description="Exclude this comma separated list of claims") - public List exclude = null; - - @Parameter(names="--claims", descriptionKey = "labels", description="Only keep this comma separated list of claims") - public List claims = null; - - @Parameter(names="--debugger", - description="Launch proof in an interactive debugger. Currently only supported by the Haskell backend.") - public boolean debugger; - - @Parameter(names="--debug-script", descriptionKey = "file", - description="Run script passed in specified file when the debugger starts. Used with --debugger.") - public String debugScript; - - @Parameter(names="--emit-json", description="Emit JSON serialized main definition for proving.") - public boolean emitJson = false; - - @Parameter(names="--emit-json-spec", descriptionKey = "file", - description="If set, emit the JSON serialization of the spec module to the specified file.") - public String emitJsonSpec = null; + @Inject + public KProveOptions() {} + + @ParametersDelegate private final transient GlobalOptions global = new GlobalOptions(); + + /** Use only in the Guice Provider method, so it can replace the GlobalOptions from kompile. */ + public GlobalOptions getGlobalOptions_useOnlyInGuiceProvider() { + return global; + } + + @ParametersDelegate + public DefinitionLoadingOptions definitionLoading = new DefinitionLoadingOptions(); + + @ParametersDelegate public OuterParsingOptions outerParsing = new OuterParsingOptions(); + + @ParametersDelegate public InnerParsingOptions innerParsing = new InnerParsingOptions(); + + private File specFile; + + public synchronized File specFile(FileUtil files) { + return outerParsing.mainDefinitionFile(files); + } + + @ParametersDelegate public BackendOptions backend = new BackendOptions(); + + @ParametersDelegate public SMTOptions smt = new SMTOptions(); + + @ParametersDelegate public PrintOptions print = new PrintOptions(); + + @Parameter( + names = "--branching-allowed", + descriptionKey = "number", + arity = 1, + description = "Number of branching events allowed before a forcible stop.") + public int branchingAllowed = Integer.MAX_VALUE; + + @Parameter( + names = {"--spec-module", "-sm"}, + descriptionKey = "name", + description = "Name of module containing specification to prove") + public String specModule; + + @Parameter( + names = "--depth", + descriptionKey = "number", + description = "The maximum number of computational steps to prove") + public Integer depth; + + @Parameter( + names = "--trusted", + descriptionKey = "labels", + description = "Mark this comma separated list of claims as [trusted]") + public List trusted = null; + + @Parameter( + names = "--exclude", + descriptionKey = "labels", + description = "Exclude this comma separated list of claims") + public List exclude = null; + + @Parameter( + names = "--claims", + descriptionKey = "labels", + description = "Only keep this comma separated list of claims") + public List claims = null; + + @Parameter( + names = "--debugger", + description = + "Launch proof in an interactive debugger. Currently only supported by the Haskell" + + " backend.") + public boolean debugger; + + @Parameter( + names = "--debug-script", + descriptionKey = "file", + description = + "Run script passed in specified file when the debugger starts. Used with --debugger.") + public String debugScript; + + @Parameter( + names = "--emit-json", + description = "Emit JSON serialized main definition for proving.") + public boolean emitJson = false; + + @Parameter( + names = "--emit-json-spec", + descriptionKey = "file", + description = "If set, emit the JSON serialization of the spec module to the specified file.") + public String emitJsonSpec = null; } diff --git a/kernel/src/main/java/org/kframework/kprove/ProofDefinitionBuilder.java b/kernel/src/main/java/org/kframework/kprove/ProofDefinitionBuilder.java index 2ff777a4a25..7c6461849db 100644 --- a/kernel/src/main/java/org/kframework/kprove/ProofDefinitionBuilder.java +++ b/kernel/src/main/java/org/kframework/kprove/ProofDefinitionBuilder.java @@ -1,8 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kprove; +import static org.kframework.Collections.*; + import com.google.common.collect.Sets; import com.google.inject.Inject; +import java.io.File; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.io.FilenameUtils; import org.kframework.attributes.Att; import org.kframework.compile.Backend; @@ -16,95 +24,118 @@ import scala.Option; import scala.Tuple2; -import java.io.File; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; +public record ProofDefinitionBuilder( + CompiledDefinition compiledDefinition, + Backend backend, + Kompile kompile, + KProveOptions proveOptions, + FileUtil files, + Stopwatch sw) { -import static org.kframework.Collections.*; + @Inject + public ProofDefinitionBuilder {} -public record ProofDefinitionBuilder(CompiledDefinition compiledDefinition, - Backend backend, Kompile kompile, - KProveOptions proveOptions, - FileUtil files, Stopwatch sw) { + /** + * @param specFile File containing specification rules to prove. Not part of definition. + * @param specModuleName Module containing specifications to prove + */ + public Tuple2 build( + File specFile, String specModuleName, boolean readOnlyCache) { + String defModuleNameUpdated = compiledDefinition.kompiledDefinition.mainModule().name(); + String specModuleNameUpdated = + specModuleName == null + ? FilenameUtils.getBaseName(specFile.getName()).toUpperCase() + : specModuleName; + File absSpecFile = files.resolveWorkingDirectory(specFile).getAbsoluteFile(); - @Inject - public ProofDefinitionBuilder { - } - - /** - * @param specFile File containing specification rules to prove. Not part of definition. - * @param specModuleName Module containing specifications to prove - */ - public Tuple2 build(File specFile, String specModuleName, boolean readOnlyCache) { - String defModuleNameUpdated = compiledDefinition.kompiledDefinition.mainModule().name(); - String specModuleNameUpdated = - specModuleName == null ? FilenameUtils.getBaseName(specFile.getName()).toUpperCase() : specModuleName; - File absSpecFile = files.resolveWorkingDirectory(specFile).getAbsoluteFile(); - - Set modules = kompile.parseModules(compiledDefinition, defModuleNameUpdated, specModuleNameUpdated, absSpecFile, - backend.excludedModuleTags(), true, true); - Map modulesMap = modules.stream().collect(Collectors.toMap(Module::name, m -> m)); - Definition parsedDefinition = compiledDefinition.getParsedDefinition(); - Module specModule = getModule(specModuleNameUpdated, modulesMap, parsedDefinition); - specModule = filter(specModule); - kompile.proverChecksX(specModule, modulesMap.get(defModuleNameUpdated)); - kompile.structuralChecks(immutable(modules), specModule, Option.empty(), backend.excludedModuleTags()); - specModule = backend.specificationSteps(compiledDefinition.kompiledDefinition).apply(specModule); - sw.printIntermediate("Apply prover steps"); - return Tuple2.apply(compiledDefinition.kompiledDefinition, specModule); - } + Set modules = + kompile.parseModules( + compiledDefinition, + defModuleNameUpdated, + specModuleNameUpdated, + absSpecFile, + backend.excludedModuleTags(), + true, + true); + Map modulesMap = + modules.stream().collect(Collectors.toMap(Module::name, m -> m)); + Definition parsedDefinition = compiledDefinition.getParsedDefinition(); + Module specModule = getModule(specModuleNameUpdated, modulesMap, parsedDefinition); + specModule = filter(specModule); + kompile.proverChecksX(specModule, modulesMap.get(defModuleNameUpdated)); + kompile.structuralChecks( + immutable(modules), specModule, Option.empty(), backend.excludedModuleTags()); + specModule = + backend.specificationSteps(compiledDefinition.kompiledDefinition).apply(specModule); + sw.printIntermediate("Apply prover steps"); + return Tuple2.apply(compiledDefinition.kompiledDefinition, specModule); + } - private static Module getModule(String defModule, Map modules, Definition parsedDefinition) { - if (modules.containsKey(defModule)) - return modules.get(defModule); - Option mod = parsedDefinition.getModule(defModule); - if (mod.isDefined()) { - return mod.get(); - } - throw KEMException.criticalError("Module " + defModule + " does not exist."); + private static Module getModule( + String defModule, Map modules, Definition parsedDefinition) { + if (modules.containsKey(defModule)) return modules.get(defModule); + Option mod = parsedDefinition.getModule(defModule); + if (mod.isDefined()) { + return mod.get(); } + throw KEMException.criticalError("Module " + defModule + " does not exist."); + } - // filter claims according the command line options - private Module filter(Module specModule) { - if (proveOptions.trusted != null || proveOptions.exclude != null || proveOptions.claims != null) { - Set unused = new HashSet<>(); - if (proveOptions.trusted != null) unused.addAll(proveOptions.trusted); - if (proveOptions.exclude != null) unused.addAll(proveOptions.exclude); - if (proveOptions.claims != null) unused.addAll(proveOptions.claims); - if (proveOptions.exclude != null && proveOptions.claims != null) { - Sets.SetView intersection = Sets.intersection(new HashSet<>(proveOptions.exclude), new HashSet<>(proveOptions.claims)); - if (intersection.size() != 0) - throw KEMException.criticalError("Labels used for both --exclude and --claims: " + intersection); - } - specModule = new ModuleTransformer((m -> { - Set filtered = stream(m.localSentences()).flatMap(s -> { - if (s instanceof Claim c && s.att().getOptional(Att.LABEL()).isPresent()) { - String label = s.att().getOptional(Att.LABEL()).get(); - if (proveOptions.trusted != null && proveOptions.trusted.contains(label)) { - s = c.newInstance(c.body(), c.requires(), c.ensures(), c.att().add(Att.TRUSTED())); - unused.remove(label); - } - if (proveOptions.exclude != null && proveOptions.exclude.contains(label)) { - unused.remove(label); - return Stream.empty(); - } - if (proveOptions.claims != null) - if (proveOptions.claims.contains(label)) - unused.remove(label); - else - return Stream.empty(); - } - return Stream.of(s); - }).collect(Collectors.toSet()); + // filter claims according the command line options + private Module filter(Module specModule) { + if (proveOptions.trusted != null + || proveOptions.exclude != null + || proveOptions.claims != null) { + Set unused = new HashSet<>(); + if (proveOptions.trusted != null) unused.addAll(proveOptions.trusted); + if (proveOptions.exclude != null) unused.addAll(proveOptions.exclude); + if (proveOptions.claims != null) unused.addAll(proveOptions.claims); + if (proveOptions.exclude != null && proveOptions.claims != null) { + Sets.SetView intersection = + Sets.intersection( + new HashSet<>(proveOptions.exclude), new HashSet<>(proveOptions.claims)); + if (intersection.size() != 0) + throw KEMException.criticalError( + "Labels used for both --exclude and --claims: " + intersection); + } + specModule = + new ModuleTransformer( + (m -> { + Set filtered = + stream(m.localSentences()) + .flatMap( + s -> { + if (s instanceof Claim c + && s.att().getOptional(Att.LABEL()).isPresent()) { + String label = s.att().getOptional(Att.LABEL()).get(); + if (proveOptions.trusted != null + && proveOptions.trusted.contains(label)) { + s = + c.newInstance( + c.body(), + c.requires(), + c.ensures(), + c.att().add(Att.TRUSTED())); + unused.remove(label); + } + if (proveOptions.exclude != null + && proveOptions.exclude.contains(label)) { + unused.remove(label); + return Stream.empty(); + } + if (proveOptions.claims != null) + if (proveOptions.claims.contains(label)) unused.remove(label); + else return Stream.empty(); + } + return Stream.of(s); + }) + .collect(Collectors.toSet()); return Module.apply(m.name(), m.imports(), immutable(filtered), m.att()); - }), "Filter claims") { - }.apply(specModule); - if (unused.size() != 0) - throw KEMException.criticalError("Unused filtering labels: " + unused); - } - return specModule; + }), + "Filter claims") {}.apply(specModule); + if (unused.size() != 0) + throw KEMException.criticalError("Unused filtering labels: " + unused); } + return specModule; + } } diff --git a/kernel/src/main/java/org/kframework/kprove/RewriterModule.java b/kernel/src/main/java/org/kframework/kprove/RewriterModule.java index 90ea42f76b8..b962834f9d6 100644 --- a/kernel/src/main/java/org/kframework/kprove/RewriterModule.java +++ b/kernel/src/main/java/org/kframework/kprove/RewriterModule.java @@ -4,6 +4,8 @@ import com.google.inject.AbstractModule; import com.google.inject.Provider; import com.google.inject.Provides; +import java.util.Map; +import java.util.function.Function; import org.kframework.definition.Definition; import org.kframework.kompile.KompileOptions; import org.kframework.rewriter.Rewriter; @@ -11,23 +13,26 @@ import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; -import java.util.Map; -import java.util.function.Function; - public class RewriterModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(FileUtil.class); - } + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(FileUtil.class); + } - @Provides - Function getRewriter(KompileOptions options, Map>> map, KExceptionManager kem) { - Provider> provider = map.get(options.backend); - if (provider == null) { - throw KEMException.criticalError("Backend " + options.backend + " does not support execution. Supported backends are: " - + map.keySet()); - } - return provider.get(); + @Provides + Function getRewriter( + KompileOptions options, + Map>> map, + KExceptionManager kem) { + Provider> provider = map.get(options.backend); + if (provider == null) { + throw KEMException.criticalError( + "Backend " + + options.backend + + " does not support execution. Supported backends are: " + + map.keySet()); } + return provider.get(); + } } diff --git a/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternFrontEnd.java b/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternFrontEnd.java index ed495154d8c..e74bea8597c 100644 --- a/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternFrontEnd.java +++ b/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternFrontEnd.java @@ -1,9 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.ksearchpattern; -import com.google.inject.Provider; import com.google.inject.Inject; import com.google.inject.Module; +import com.google.inject.Provider; +import java.io.File; +import java.util.ArrayList; +import java.util.List; import org.kframework.attributes.Source; import org.kframework.backend.kore.ModuleToKORE; import org.kframework.builtin.BooleanUtils; @@ -25,93 +28,91 @@ import org.kframework.utils.inject.JCommanderModule; import org.kframework.utils.inject.JCommanderModule.Usage; -import java.io.File; -import java.util.ArrayList; -import java.util.List; - /** * Frontend for k-compiled-search-pattern tool. - *

- * k-compile-search-patterrn is used by the new krun frontend in order to - * convert a search pattern written as a rule bubble into a KORE search pattern - * for the Haskell backend. + * + *

k-compile-search-patterrn is used by the new krun frontend in order to convert a search + * pattern written as a rule bubble into a KORE search pattern for the Haskell backend. */ public class KSearchPatternFrontEnd extends FrontEnd { - private final KSearchPatternOptions options; - private final Provider kompileOptions; - private final KExceptionManager kem; - private final Provider files; - private final GlobalOptions globalOptions; - private final DefinitionScope scope; - private final Provider kompiledDir; - private final Provider compiledDef; + private final KSearchPatternOptions options; + private final Provider kompileOptions; + private final KExceptionManager kem; + private final Provider files; + private final GlobalOptions globalOptions; + private final DefinitionScope scope; + private final Provider kompiledDir; + private final Provider compiledDef; - @Inject - public KSearchPatternFrontEnd( - KSearchPatternOptions options, - KExceptionManager kem, - Provider kompileOptions, - GlobalOptions globalOptions, - @Usage String usage, - JarInfo jarInfo, - Provider files, - @KompiledDir Provider kompiledDir, - Provider compiledDef, - DefinitionScope scope) { - super(kem, globalOptions, usage, jarInfo, files); - this.options = options; - this.kompileOptions = kompileOptions; - this.globalOptions = globalOptions; - this.kem = kem; - this.files = files; - this.scope = scope; - this.kompiledDir = kompiledDir; - this.compiledDef = compiledDef; - } + @Inject + public KSearchPatternFrontEnd( + KSearchPatternOptions options, + KExceptionManager kem, + Provider kompileOptions, + GlobalOptions globalOptions, + @Usage String usage, + JarInfo jarInfo, + Provider files, + @KompiledDir Provider kompiledDir, + Provider compiledDef, + DefinitionScope scope) { + super(kem, globalOptions, usage, jarInfo, files); + this.options = options; + this.kompileOptions = kompileOptions; + this.globalOptions = globalOptions; + this.kem = kem; + this.files = files; + this.scope = scope; + this.kompiledDir = kompiledDir; + this.compiledDef = compiledDef; + } - public static List getModules() { - List modules = new ArrayList<>(); - modules.add(new KSearchPatternModule()); - modules.add(new JCommanderModule()); - modules.add(new CommonModule()); - return modules; - } + public static List getModules() { + List modules = new ArrayList<>(); + modules.add(new KSearchPatternModule()); + modules.add(new JCommanderModule()); + modules.add(new CommonModule()); + return modules; + } - @Override - protected int run() { - scope.enter(kompiledDir.get()); - try { - FileUtil files = this.files.get(); - CompiledDefinition compiledDef = this.compiledDef.get(); - KompileOptions kompileOptions = this.kompileOptions.get(); - Rule pattern = compiledDef.compilePatternIfAbsent(files, kem, options.pattern(), Source.apply("")); - K patternTerm = RewriteToTop.toLeft(pattern.body()); - K patternCondition = pattern.requires(); - org.kframework.definition.Module mod = compiledDef.executionModule(); - AddSortInjections addSortInjections = new AddSortInjections(mod); - ModuleToKORE converter = new ModuleToKORE(mod, compiledDef.topCellInitializer, kompileOptions); - StringBuilder sb = new StringBuilder(); - ExpandMacros macroExpander = ExpandMacros.forNonSentences(mod, files, kompileOptions, false); - K withMacros = macroExpander.expand(patternTerm); - K kWithInjections = addSortInjections.addInjections(withMacros); - sb.append("\\and{SortGeneratedTopCell{}}("); - converter.convert(kWithInjections, sb); - sb.append(", "); - if (patternCondition.equals(BooleanUtils.TRUE)) { - sb.append("\\top{SortGeneratedTopCell{}}()"); - } else { - sb.append("\\equals{SortBool{},SortGeneratedTopCell{}}("); - withMacros = macroExpander.expand(patternCondition); - kWithInjections = addSortInjections.addInjections(withMacros); - converter.convert(kWithInjections, sb); - sb.append(", \\dv{SortBool{}}(\"true\"))"); - } - sb.append(")"); - System.out.println(sb); - return 0; - } finally { - scope.exit(); - } + @Override + protected int run() { + scope.enter(kompiledDir.get()); + try { + FileUtil files = this.files.get(); + CompiledDefinition compiledDef = this.compiledDef.get(); + KompileOptions kompileOptions = this.kompileOptions.get(); + Rule pattern = + compiledDef.compilePatternIfAbsent( + files, kem, options.pattern(), Source.apply("")); + K patternTerm = RewriteToTop.toLeft(pattern.body()); + K patternCondition = pattern.requires(); + org.kframework.definition.Module mod = compiledDef.executionModule(); + AddSortInjections addSortInjections = new AddSortInjections(mod); + ModuleToKORE converter = + new ModuleToKORE(mod, compiledDef.topCellInitializer, kompileOptions); + StringBuilder sb = new StringBuilder(); + ExpandMacros macroExpander = ExpandMacros.forNonSentences(mod, files, kompileOptions, false); + K withMacros = macroExpander.expand(patternTerm); + K kWithInjections = addSortInjections.addInjections(withMacros); + sb.append("\\and{SortGeneratedTopCell{}}("); + converter.convert(kWithInjections, sb); + sb.append(", "); + if (patternCondition.equals(BooleanUtils.TRUE)) { + sb.append("\\top{SortGeneratedTopCell{}}()"); + } else { + sb.append("\\equals{SortBool{},SortGeneratedTopCell{}}("); + withMacros = macroExpander.expand(patternCondition); + kWithInjections = addSortInjections.addInjections(withMacros); + converter.convert(kWithInjections, sb); + sb.append(", \\dv{SortBool{}}(\"true\"))"); + } + sb.append(")"); + System.out.println(sb); + return 0; + } finally { + scope.exit(); } + } } diff --git a/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternModule.java b/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternModule.java index 93328edf004..6a2437bb6b1 100644 --- a/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternModule.java +++ b/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternModule.java @@ -3,42 +3,43 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; -import com.google.inject.TypeLiteral; import com.google.inject.multibindings.Multibinder; import org.kframework.main.FrontEnd; import org.kframework.main.GlobalOptions; import org.kframework.main.Tool; -import org.kframework.utils.inject.Options; import org.kframework.utils.inject.DefinitionLoadingModule; +import org.kframework.utils.inject.Options; import org.kframework.utils.inject.RequestScoped; import org.kframework.utils.options.DefinitionLoadingOptions; /** * Guice module for k-compile-search-pattern tool. * - * Binds the information needed to compute the kompiled directory as well as the options - * and frontend. + *

Binds the information needed to compute the kompiled directory as well as the options and + * frontend. */ public class KSearchPatternModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(FrontEnd.class).to(KSearchPatternFrontEnd.class); - bind(Tool.class).toInstance(Tool.KSEARCHPATTERN); + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(FrontEnd.class).to(KSearchPatternFrontEnd.class); + bind(Tool.class).toInstance(Tool.KSEARCHPATTERN); - install(new DefinitionLoadingModule()); + install(new DefinitionLoadingModule()); - Multibinder optionsBinder = Multibinder.newSetBinder(binder(), Object.class, Options.class); - optionsBinder.addBinding().to(KSearchPatternOptions.class); - } + Multibinder optionsBinder = + Multibinder.newSetBinder(binder(), Object.class, Options.class); + optionsBinder.addBinding().to(KSearchPatternOptions.class); + } - @Provides @RequestScoped - GlobalOptions globalOptions(KSearchPatternOptions options) { - return options.global; - } + @Provides + @RequestScoped + GlobalOptions globalOptions(KSearchPatternOptions options) { + return options.global; + } - @Provides - DefinitionLoadingOptions defLoadingOptions(KSearchPatternOptions options) { - return options.definitionLoading; - } + @Provides + DefinitionLoadingOptions defLoadingOptions(KSearchPatternOptions options) { + return options.definitionLoading; + } } diff --git a/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternOptions.java b/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternOptions.java index 9fcc1baec84..dd3ec39d0e2 100644 --- a/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternOptions.java +++ b/kernel/src/main/java/org/kframework/ksearchpattern/KSearchPatternOptions.java @@ -4,32 +4,27 @@ import com.beust.jcommander.Parameter; import com.beust.jcommander.ParametersDelegate; import com.google.inject.Inject; +import java.util.List; import org.kframework.main.GlobalOptions; import org.kframework.utils.inject.RequestScoped; import org.kframework.utils.options.DefinitionLoadingOptions; -import java.util.List; - -/** - * JCommander options for k-compile-search-pattern. - */ - +/** JCommander options for k-compile-search-pattern. */ @RequestScoped public class KSearchPatternOptions { - @Inject - public KSearchPatternOptions() {} + @Inject + public KSearchPatternOptions() {} - @ParametersDelegate - public transient GlobalOptions global = new GlobalOptions(); + @ParametersDelegate public transient GlobalOptions global = new GlobalOptions(); - @ParametersDelegate - public DefinitionLoadingOptions definitionLoading = new DefinitionLoadingOptions(); + @ParametersDelegate + public DefinitionLoadingOptions definitionLoading = new DefinitionLoadingOptions(); - @Parameter(description="") - private List parameters; + @Parameter(description = "") + private List parameters; - public String pattern() { - return parameters.get(0); - } + public String pattern() { + return parameters.get(0); + } } diff --git a/kernel/src/main/java/org/kframework/kserver/KServerFrontEnd.java b/kernel/src/main/java/org/kframework/kserver/KServerFrontEnd.java index b1ea8a48939..4d69b9ad1c1 100644 --- a/kernel/src/main/java/org/kframework/kserver/KServerFrontEnd.java +++ b/kernel/src/main/java/org/kframework/kserver/KServerFrontEnd.java @@ -1,5 +1,6 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kserver; + import com.google.common.collect.ImmutableList; import com.google.inject.Inject; import com.google.inject.Injector; @@ -9,6 +10,15 @@ import com.martiansoftware.nailgun.NGListeningAddress; import com.martiansoftware.nailgun.NGServer; import com.martiansoftware.nailgun.ThreadLocalPrintStream; +import java.io.File; +import java.io.PrintStream; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.kframework.main.FrontEnd; import org.kframework.main.Main; import org.kframework.utils.OS; @@ -21,171 +31,164 @@ import org.kframework.utils.inject.JCommanderModule.Usage; import org.kframework.utils.inject.SimpleScope; -import java.io.File; -import java.io.PrintStream; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - - public class KServerFrontEnd extends FrontEnd { - public static List getModules() { - List modules = new ArrayList<>(); - modules.add(new KServerModule()); - modules.add(new JCommanderModule()); - modules.add(new CommonModule()); - return modules; + public static List getModules() { + List modules = new ArrayList<>(); + modules.add(new KServerModule()); + modules.add(new JCommanderModule()); + modules.add(new CommonModule()); + return modules; + } + + @Inject + public KServerFrontEnd( + KExceptionManager kem, + KServerOptions options, + @Usage String usage, + JarInfo jarInfo, + Provider files) { + super(kem, options.global, usage, jarInfo, files); + this.options = options; + } + + private static KServerFrontEnd instance; + private static Thread threadInstance; + private static final ImmutableList tools = + ImmutableList.of( + "-kompile", "-kast", "-kdep", "-kprove", "-kserver", "-k-compile-search-pattern"); + + private final KServerOptions options; + private final Map injectors = new HashMap<>(); + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + + @Override + protected int run() { + for (String tool : tools) { + injectors.put(tool, Main.getInjector(tool)); } - - @Inject - public KServerFrontEnd( - KExceptionManager kem, - KServerOptions options, - @Usage String usage, - JarInfo jarInfo, - Provider files) { - super(kem, options.global, usage, jarInfo, files); - this.options = options; + NGServer server; + File dir = null; + if (isLocal()) { + // can use more secure unix domain sockets + // we use HOME variable to get home on linux because user.home does not match HOME variable + // when run with sudo + // unless run with sudo -H, and we want to ensure that the installer works correctly. + String dirpath = options.socket; + if (dirpath == null) { + String home = + OS.current() == OS.LINUX ? System.getenv("HOME") : System.getProperty("user.home"); + dirpath = home + File.separatorChar + ".kserver"; + } + dir = new File(dirpath); + dir.mkdirs(); + dir.setReadable(false, false); + dir.setReadable(true, true); + dir.setWritable(false, false); + dir.setWritable(true, true); + dir.setExecutable(false, false); + dir.setExecutable(true, true); + File socket = new File(dir, "socket"); + socket.deleteOnExit(); + if (socket.exists()) { + System.out.println("Warning: K server already started."); + socket.delete(); + } + server = new NGServer(new NGListeningAddress(socket.getAbsolutePath()), 10, 10000); + } else { + server = new NGServer(InetAddress.getLoopbackAddress(), options.port); } - - private static KServerFrontEnd instance; - private static Thread threadInstance; - private static final ImmutableList tools = ImmutableList.of("-kompile", "-kast", - "-kdep", "-kprove", "-kserver", "-k-compile-search-pattern"); - - private final KServerOptions options; - private final Map injectors = new HashMap<>(); - private final ReadWriteLock lock = new ReentrantReadWriteLock(); - - @Override - protected int run() { - for (String tool : tools) { - injectors.put(tool, Main.getInjector(tool)); - } - NGServer server; - File dir = null; - if (isLocal()) { - // can use more secure unix domain sockets - // we use HOME variable to get home on linux because user.home does not match HOME variable when run with sudo - // unless run with sudo -H, and we want to ensure that the installer works correctly. - String dirpath = options.socket; - if (dirpath == null) { - String home = OS.current() == OS.LINUX ? System.getenv("HOME") : System.getProperty("user.home"); - dirpath = home + File.separatorChar + ".kserver"; - } - dir = new File(dirpath); - dir.mkdirs(); - dir.setReadable(false, false); - dir.setReadable(true, true); - dir.setWritable(false, false); - dir.setWritable(true, true); - dir.setExecutable(false, false); - dir.setExecutable(true, true); - File socket = new File(dir, "socket"); - socket.deleteOnExit(); - if (socket.exists()) { - System.out.println("Warning: K server already started."); - socket.delete(); - } - server = new NGServer(new NGListeningAddress(socket.getAbsolutePath()), 10, 10000); - } else { - server = new NGServer(InetAddress.getLoopbackAddress(), options.port); - } - Thread t = new Thread(server); - instance = this; - threadInstance = t; - t.start(); - - if (isLocal()) { - System.out.println("K server started using IPC at " + dir.getAbsolutePath()); - } else { - int runningPort = server.getPort(); - while (runningPort == 0) { - try { - Thread.sleep(50L); - } catch (InterruptedException e) { - } - runningPort = server.getPort(); - } - System.out.println("K server started on 127.0.0.1:" + options.port); - } - + Thread t = new Thread(server); + instance = this; + threadInstance = t; + t.start(); + + if (isLocal()) { + System.out.println("K server started using IPC at " + dir.getAbsolutePath()); + } else { + int runningPort = server.getPort(); + while (runningPort == 0) { try { - t.join(); - return 0; + Thread.sleep(50L); } catch (InterruptedException e) { - //application is about to die - return 0; } + runningPort = server.getPort(); + } + System.out.println("K server started on 127.0.0.1:" + options.port); } - public static KServerFrontEnd instance() { - return instance; + try { + t.join(); + return 0; + } catch (InterruptedException e) { + // application is about to die + return 0; } + } - public int run(String tool, String[] args, File workingDir, Map env, long startTime) { - ThreadLocalPrintStream system_out = (ThreadLocalPrintStream) System.out; - ThreadLocalPrintStream system_err = (ThreadLocalPrintStream) System.err; + public static KServerFrontEnd instance() { + return instance; + } - Injector injector; + public int run( + String tool, String[] args, File workingDir, Map env, long startTime) { + ThreadLocalPrintStream system_out = (ThreadLocalPrintStream) System.out; + ThreadLocalPrintStream system_err = (ThreadLocalPrintStream) System.err; - lock.readLock().lock(); - try { - injector = injectors.get(tool); - } finally { - lock.readLock().unlock(); - } + Injector injector; - Main launcher = injector.getInstance(Main.class); - SimpleScope requestScope = launcher.getRequestScope(); - try { - requestScope.enter(); - Main.seedInjector(requestScope, tool, args, workingDir, env, startTime); - TTYInfo tty = injector.getInstance(TTYInfo.class); - if (!tty.stdout()) { - system_out.init(new PrintStream(system_out.getPrintStream())); - } - if (!tty.stderr()) { - system_err.init(new PrintStream(system_err.getPrintStream())); - } - - int result = launcher.runApplication(); - System.out.flush(); - System.err.flush(); - return result; - } finally { - requestScope.exit(); - } + lock.readLock().lock(); + try { + injector = injectors.get(tool); + } finally { + lock.readLock().unlock(); } - public static void nailMain(NGContext context) { - KServerFrontEnd kserver = KServerFrontEnd.instance(); - if (!kserver.isLocal()) { - context.assertLoopbackClient(); - } - if (context.getArgs()[0].equals("shutdown")) { - System.setSecurityManager(null); - context.getNGServer().shutdown(true); - } else if (context.getArgs()[0].equals("reset")) { - kserver.lock.writeLock().lock(); - try { - kserver.injectors.clear(); - for (String tool : tools) { - kserver.injectors.put(tool, Main.getInjector(tool)); - } - } finally { - kserver.lock.writeLock().unlock(); - } - System.gc(); - } + Main launcher = injector.getInstance(Main.class); + SimpleScope requestScope = launcher.getRequestScope(); + try { + requestScope.enter(); + Main.seedInjector(requestScope, tool, args, workingDir, env, startTime); + TTYInfo tty = injector.getInstance(TTYInfo.class); + if (!tty.stdout()) { + system_out.init(new PrintStream(system_out.getPrintStream())); + } + if (!tty.stderr()) { + system_err.init(new PrintStream(system_err.getPrintStream())); + } + + int result = launcher.runApplication(); + System.out.flush(); + System.err.flush(); + return result; + } finally { + requestScope.exit(); } + } - public boolean isLocal() { - return (OS.current() != OS.WINDOWS) || (options.socket != null); + public static void nailMain(NGContext context) { + KServerFrontEnd kserver = KServerFrontEnd.instance(); + if (!kserver.isLocal()) { + context.assertLoopbackClient(); } + if (context.getArgs()[0].equals("shutdown")) { + System.setSecurityManager(null); + context.getNGServer().shutdown(true); + } else if (context.getArgs()[0].equals("reset")) { + kserver.lock.writeLock().lock(); + try { + kserver.injectors.clear(); + for (String tool : tools) { + kserver.injectors.put(tool, Main.getInjector(tool)); + } + } finally { + kserver.lock.writeLock().unlock(); + } + System.gc(); + } + } + + public boolean isLocal() { + return (OS.current() != OS.WINDOWS) || (options.socket != null); + } } diff --git a/kernel/src/main/java/org/kframework/kserver/KServerModule.java b/kernel/src/main/java/org/kframework/kserver/KServerModule.java index 865cdfc76f4..36c1ed017ff 100644 --- a/kernel/src/main/java/org/kframework/kserver/KServerModule.java +++ b/kernel/src/main/java/org/kframework/kserver/KServerModule.java @@ -1,40 +1,40 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kserver; -import java.io.File; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.util.Providers; +import java.io.File; import org.kframework.main.FrontEnd; import org.kframework.main.GlobalOptions; import org.kframework.main.Tool; import org.kframework.utils.file.DefinitionDir; import org.kframework.utils.file.KompiledDir; import org.kframework.utils.inject.Options; - -import com.google.inject.AbstractModule; -import com.google.inject.Provides; -import com.google.inject.TypeLiteral; -import com.google.inject.multibindings.Multibinder; -import com.google.inject.util.Providers; import org.kframework.utils.inject.RequestScoped; public class KServerModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(Tool.class).toInstance(Tool.KSERVER); - bind(FrontEnd.class).to(KServerFrontEnd.class); - - Multibinder optionsBinder = Multibinder.newSetBinder(binder(), Object.class, Options.class); - optionsBinder.addBinding().to(KServerOptions.class); - Multibinder.newSetBinder(binder(), new TypeLiteral>() {}, Options.class); - - bind(File.class).annotatedWith(DefinitionDir.class).toProvider(Providers.of(null)); - bind(File.class).annotatedWith(KompiledDir.class).toProvider(Providers.of(null)); - } - - @Provides @RequestScoped - GlobalOptions globalOptions(KServerOptions options) { - return options.global; - } - + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(Tool.class).toInstance(Tool.KSERVER); + bind(FrontEnd.class).to(KServerFrontEnd.class); + + Multibinder optionsBinder = + Multibinder.newSetBinder(binder(), Object.class, Options.class); + optionsBinder.addBinding().to(KServerOptions.class); + Multibinder.newSetBinder(binder(), new TypeLiteral>() {}, Options.class); + + bind(File.class).annotatedWith(DefinitionDir.class).toProvider(Providers.of(null)); + bind(File.class).annotatedWith(KompiledDir.class).toProvider(Providers.of(null)); + } + + @Provides + @RequestScoped + GlobalOptions globalOptions(KServerOptions options) { + return options.global; + } } diff --git a/kernel/src/main/java/org/kframework/kserver/KServerOptions.java b/kernel/src/main/java/org/kframework/kserver/KServerOptions.java index b09695b0ac3..668d0a46ca3 100644 --- a/kernel/src/main/java/org/kframework/kserver/KServerOptions.java +++ b/kernel/src/main/java/org/kframework/kserver/KServerOptions.java @@ -1,26 +1,27 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kserver; +import com.beust.jcommander.Parameter; +import com.beust.jcommander.ParametersDelegate; import com.google.inject.Inject; import org.kframework.main.GlobalOptions; import org.kframework.utils.inject.RequestScoped; -import com.beust.jcommander.Parameter; -import com.beust.jcommander.ParametersDelegate; - @RequestScoped public class KServerOptions { - @Inject - public KServerOptions() {} - - @ParametersDelegate - public transient GlobalOptions global = new GlobalOptions(); + @Inject + public KServerOptions() {} - @Parameter(names={"--port", "-p"}, description="The port to start the server on.") - public int port = 2113; + @ParametersDelegate public transient GlobalOptions global = new GlobalOptions(); - @Parameter(names={"--socket"}, description="The directory to put the unix domain socket in.") - public String socket = null; + @Parameter( + names = {"--port", "-p"}, + description = "The port to start the server on.") + public int port = 2113; + @Parameter( + names = {"--socket"}, + description = "The directory to put the unix domain socket in.") + public String socket = null; } diff --git a/kernel/src/main/java/org/kframework/lsp/CompletionHelper.java b/kernel/src/main/java/org/kframework/lsp/CompletionHelper.java index 3d85328a9d5..0e35074a344 100644 --- a/kernel/src/main/java/org/kframework/lsp/CompletionHelper.java +++ b/kernel/src/main/java/org/kframework/lsp/CompletionHelper.java @@ -1,210 +1,249 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; +import static org.kframework.Collections.immutable; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.InsertTextFormat; import org.jetbrains.annotations.NotNull; import org.kframework.attributes.Att; -import org.kframework.kil.Module; import org.kframework.kil.*; +import org.kframework.kil.Module; import org.kframework.kore.Sort; import scala.Tuple2; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - -import static org.kframework.Collections.immutable; - -/** - * Helper methods for building CompletionItems - */ +/** Helper methods for building CompletionItems */ public class CompletionHelper { - static Pattern ptrn = Pattern.compile("[a-zA-Z0-9#]+"); - - // create the list of CompletionItems for every piece of syntax - // for now we filter by alphanumeric but can be improved greatly. - public static List getRuleCompletion(List dis) { - List lci = new ArrayList<>(); - // Traverse all the modules and all the syntax declarations to find the Terminals in productions - // For each Terminal that follows the above, create a CompletionItem with some documentation - // Tree structure: Definition -> Module -> Syntax -> PriorityBlock -> Production -> Terminal - dis.stream().filter(i -> i instanceof Module) - .map(m -> ((Module) m)) - .forEach(m -> m.getItems().stream() - .filter(mi -> mi instanceof Syntax) - .map(s -> ((Syntax) s)) - .forEach(s -> s.getPriorityBlocks() - .forEach((pb -> pb.getProductions() - .forEach(p -> { - if (p.getItems().get(0) instanceof Terminal && ptrn.matcher(((Terminal)p.getItems().get(0)).getTerminal()).matches()) { - CompletionItem completionItem = buildRuleCompletionItem(m, s, p); - lci.add(completionItem); - } else - p.getItems().stream() - .filter(pi -> pi instanceof Terminal) - .map(t -> (Terminal) t) - .forEach(t -> { - if (ptrn.matcher(t.getTerminal()).matches()) { - CompletionItem completionItem = buildRuleCompletionItem(m, s, p, t); - lci.add(completionItem); - } - }); - } - ))))); - - return lci; - } - - // for productions that start with a valid terminal - // build a code snippet with tabstops - @NotNull - public static CompletionItem buildRuleCompletionItem(Module m, Syntax s, Production p) { - CompletionItem completionItem = new CompletionItem(); - Terminal t = (Terminal) p.getItems().get(0); - completionItem.setLabel(t.getTerminal()); - StringBuilder snip = new StringBuilder(); - int codeSnip = 1; - String prevToken = "("; - for (int i = 0; i < p.getItems().size(); i++) { - ProductionItem pi = p.getItems().get(i); - if (pi instanceof Terminal) { - String trm = ((Terminal) pi).getTerminal(); - // don't insert whitespaces around ( ) parentheses - if (!(prevToken.equals("(") || prevToken.equals(")")) && !"(".equals(trm) && !")".equals(trm) && !",".equals(trm)) - snip.append(" "); - prevToken = trm; - snip.append(trm); - } else if (pi instanceof NonTerminal) { - if (!(prevToken.equals("(") || prevToken.equals(")"))) - snip.append(" "); - prevToken = ""; - snip.append("${"); - snip.append(codeSnip++); - snip.append(":_:"); - snip.append(((NonTerminal) pi).getSort()); - snip.append("}"); - } - } - - completionItem.setInsertText(snip.toString()); - completionItem.setDetail("module " + m.getName()); - String doc = "syntax "; - doc += !s.getParams().isEmpty() ? - "{" + s.getParams().stream().map(Sort::toString).collect(Collectors.joining(", ")) + "} " : ""; - doc += s.getDeclaredSort() + " ::= "; - doc += p.toString(); - completionItem.setDocumentation(doc); - completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - completionItem.setKind(CompletionItemKind.Function); - return completionItem; - } - - @NotNull - private static CompletionItem buildRuleCompletionItem(Module m, Syntax s, Production p, Terminal t) { - CompletionItem completionItem = new CompletionItem(); - completionItem.setLabel(t.getTerminal()); - completionItem.setInsertText(t.getTerminal()); - completionItem.setDetail("module " + m.getName()); - String doc = "syntax "; - doc += !s.getParams().isEmpty() ? - "{" + s.getParams().stream().map(Sort::toString).collect(Collectors.joining(", ")) + "} " : ""; - doc += s.getDeclaredSort() + " ::= "; - doc += p.toString(); - completionItem.setDocumentation(doc); - completionItem.setInsertTextFormat(InsertTextFormat.PlainText); - completionItem.setKind(CompletionItemKind.Operator); - return completionItem; - } - - public static CompletionItem getNewRequiresCompletion() { - CompletionItem completionItem = new CompletionItem(); - completionItem.setLabel("requires"); - completionItem.setInsertText("requires \"${1:file}\""); - completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - completionItem.setKind(CompletionItemKind.Keyword); - return completionItem; + static Pattern ptrn = Pattern.compile("[a-zA-Z0-9#]+"); + + // create the list of CompletionItems for every piece of syntax + // for now we filter by alphanumeric but can be improved greatly. + public static List getRuleCompletion(List dis) { + List lci = new ArrayList<>(); + // Traverse all the modules and all the syntax declarations to find the Terminals in productions + // For each Terminal that follows the above, create a CompletionItem with some + // documentation + // Tree structure: Definition -> Module -> Syntax -> PriorityBlock -> Production -> Terminal + dis.stream() + .filter(i -> i instanceof Module) + .map(m -> ((Module) m)) + .forEach( + m -> + m.getItems().stream() + .filter(mi -> mi instanceof Syntax) + .map(s -> ((Syntax) s)) + .forEach( + s -> + s.getPriorityBlocks() + .forEach( + (pb -> + pb.getProductions() + .forEach( + p -> { + if (p.getItems().get(0) instanceof Terminal + && ptrn.matcher( + ((Terminal) p.getItems().get(0)) + .getTerminal()) + .matches()) { + CompletionItem completionItem = + buildRuleCompletionItem(m, s, p); + lci.add(completionItem); + } else + p.getItems().stream() + .filter(pi -> pi instanceof Terminal) + .map(t -> (Terminal) t) + .forEach( + t -> { + if (ptrn.matcher(t.getTerminal()) + .matches()) { + CompletionItem completionItem = + buildRuleCompletionItem( + m, s, p, t); + lci.add(completionItem); + } + }); + }))))); + + return lci; + } + + // for productions that start with a valid terminal + // build a code snippet with tabstops + @NotNull + public static CompletionItem buildRuleCompletionItem(Module m, Syntax s, Production p) { + CompletionItem completionItem = new CompletionItem(); + Terminal t = (Terminal) p.getItems().get(0); + completionItem.setLabel(t.getTerminal()); + StringBuilder snip = new StringBuilder(); + int codeSnip = 1; + String prevToken = "("; + for (int i = 0; i < p.getItems().size(); i++) { + ProductionItem pi = p.getItems().get(i); + if (pi instanceof Terminal) { + String trm = ((Terminal) pi).getTerminal(); + // don't insert whitespaces around ( ) parentheses + if (!(prevToken.equals("(") || prevToken.equals(")")) + && !"(".equals(trm) + && !")".equals(trm) + && !",".equals(trm)) snip.append(" "); + prevToken = trm; + snip.append(trm); + } else if (pi instanceof NonTerminal) { + if (!(prevToken.equals("(") || prevToken.equals(")"))) snip.append(" "); + prevToken = ""; + snip.append("${"); + snip.append(codeSnip++); + snip.append(":_:"); + snip.append(((NonTerminal) pi).getSort()); + snip.append("}"); + } } - public static CompletionItem getNewModuleCompletion() { - CompletionItem completionItem = new CompletionItem(); - completionItem.setLabel("module"); - completionItem.setInsertText("module ${0:NAME}\nendmodule"); - completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - completionItem.setKind(CompletionItemKind.Keyword); - return completionItem; - } - - public static List getNewSentenceCompletion() { - CompletionItem completionItem = new CompletionItem(); - completionItem.setLabel("syntax"); - completionItem.setInsertText("syntax ${1:SORT} ::= $0"); - completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - completionItem.setKind(CompletionItemKind.Keyword); - - return List.of(completionItem, - new CompletionItem("rule"), - new CompletionItem("configuration"), - new CompletionItem("context"), - new CompletionItem("claim")); - } - - public static CompletionItem getNewImportCompletion() { - CompletionItem completionItem = new CompletionItem(); - completionItem.setLabel("imports"); - completionItem.setInsertText("imports ${0:NAME}"); - completionItem.setInsertTextFormat(InsertTextFormat.Snippet); - completionItem.setKind(CompletionItemKind.Keyword); - return completionItem; - } - - public static List getImportCompletion(List allDi) { - return allDi.stream() - .filter(mi2 -> mi2 instanceof Module) - .map(m2 -> ((Module) m2)) - .map(m2 -> { - CompletionItem ci = new CompletionItem(); - ci.setLabel(m2.getName()); - ci.setInsertText(m2.getName()); - ci.setDetail(Path.of(m2.getSource().source()).getFileName().toString()); - ci.setKind(CompletionItemKind.Module); - return ci; - }).collect(Collectors.toList()); - } - - // create a list of all the visible declared sorts - public static List getSyntaxCompletion(List allDi) { - Map> allSorts = allDi.stream().filter(i -> i instanceof Module) - .map(m3 -> ((Module) m3)) - .flatMap(m3 -> m3.getItems().stream() + completionItem.setInsertText(snip.toString()); + completionItem.setDetail("module " + m.getName()); + String doc = "syntax "; + doc += + !s.getParams().isEmpty() + ? "{" + + s.getParams().stream().map(Sort::toString).collect(Collectors.joining(", ")) + + "} " + : ""; + doc += s.getDeclaredSort() + " ::= "; + doc += p.toString(); + completionItem.setDocumentation(doc); + completionItem.setInsertTextFormat(InsertTextFormat.Snippet); + completionItem.setKind(CompletionItemKind.Function); + return completionItem; + } + + @NotNull + private static CompletionItem buildRuleCompletionItem( + Module m, Syntax s, Production p, Terminal t) { + CompletionItem completionItem = new CompletionItem(); + completionItem.setLabel(t.getTerminal()); + completionItem.setInsertText(t.getTerminal()); + completionItem.setDetail("module " + m.getName()); + String doc = "syntax "; + doc += + !s.getParams().isEmpty() + ? "{" + + s.getParams().stream().map(Sort::toString).collect(Collectors.joining(", ")) + + "} " + : ""; + doc += s.getDeclaredSort() + " ::= "; + doc += p.toString(); + completionItem.setDocumentation(doc); + completionItem.setInsertTextFormat(InsertTextFormat.PlainText); + completionItem.setKind(CompletionItemKind.Operator); + return completionItem; + } + + public static CompletionItem getNewRequiresCompletion() { + CompletionItem completionItem = new CompletionItem(); + completionItem.setLabel("requires"); + completionItem.setInsertText("requires \"${1:file}\""); + completionItem.setInsertTextFormat(InsertTextFormat.Snippet); + completionItem.setKind(CompletionItemKind.Keyword); + return completionItem; + } + + public static CompletionItem getNewModuleCompletion() { + CompletionItem completionItem = new CompletionItem(); + completionItem.setLabel("module"); + completionItem.setInsertText("module ${0:NAME}\nendmodule"); + completionItem.setInsertTextFormat(InsertTextFormat.Snippet); + completionItem.setKind(CompletionItemKind.Keyword); + return completionItem; + } + + public static List getNewSentenceCompletion() { + CompletionItem completionItem = new CompletionItem(); + completionItem.setLabel("syntax"); + completionItem.setInsertText("syntax ${1:SORT} ::= $0"); + completionItem.setInsertTextFormat(InsertTextFormat.Snippet); + completionItem.setKind(CompletionItemKind.Keyword); + + return List.of( + completionItem, + new CompletionItem("rule"), + new CompletionItem("configuration"), + new CompletionItem("context"), + new CompletionItem("claim")); + } + + public static CompletionItem getNewImportCompletion() { + CompletionItem completionItem = new CompletionItem(); + completionItem.setLabel("imports"); + completionItem.setInsertText("imports ${0:NAME}"); + completionItem.setInsertTextFormat(InsertTextFormat.Snippet); + completionItem.setKind(CompletionItemKind.Keyword); + return completionItem; + } + + public static List getImportCompletion(List allDi) { + return allDi.stream() + .filter(mi2 -> mi2 instanceof Module) + .map(m2 -> ((Module) m2)) + .map( + m2 -> { + CompletionItem ci = new CompletionItem(); + ci.setLabel(m2.getName()); + ci.setInsertText(m2.getName()); + ci.setDetail(Path.of(m2.getSource().source()).getFileName().toString()); + ci.setKind(CompletionItemKind.Module); + return ci; + }) + .collect(Collectors.toList()); + } + + // create a list of all the visible declared sorts + public static List getSyntaxCompletion(List allDi) { + Map> allSorts = + allDi.stream() + .filter(i -> i instanceof Module) + .map(m3 -> ((Module) m3)) + .flatMap( + m3 -> + m3.getItems().stream() .filter(mi3 -> mi3 instanceof Syntax) .map(s -> ((Syntax) s)) .filter(s -> !s.getParams().contains(s.getDeclaredSort().getRealSort())) - .map(s -> Tuple2.apply(s.getDeclaredSort().getRealSort().name(), s.getAttributes()))) - .collect(Collectors.groupingBy(Tuple2::_1, Collectors.mapping(Tuple2::_2, Collectors.toSet()))); - Map allSorts2 = allSorts.entrySet().stream() - .map(e -> Tuple2.apply(e.getKey(), Att.mergeAttributes(immutable(e.getValue())))) - .collect(Collectors.toMap(Tuple2::_1, Tuple2::_2)); - return allSorts2.entrySet().stream().map(e -> { - CompletionItem ci = new CompletionItem(); - ci.setLabel(e.getKey()); - ci.setInsertText(e.getKey()); - // TODO: to calculate properly we need to recurse through the inclusion tree - // and find the first module to declare the sort. This should be easy to get - // when we connect to the kompile pipeline. - //ci.setDetail("module " + m.getName()); - String documentation = "syntax " + e.getKey() + " "; - documentation += e.getValue().toString(); - ci.setDocumentation(documentation); - ci.setKind(CompletionItemKind.TypeParameter); - return ci; - }).collect(Collectors.toList()); - } + .map( + s -> + Tuple2.apply( + s.getDeclaredSort().getRealSort().name(), s.getAttributes()))) + .collect( + Collectors.groupingBy( + Tuple2::_1, Collectors.mapping(Tuple2::_2, Collectors.toSet()))); + Map allSorts2 = + allSorts.entrySet().stream() + .map(e -> Tuple2.apply(e.getKey(), Att.mergeAttributes(immutable(e.getValue())))) + .collect(Collectors.toMap(Tuple2::_1, Tuple2::_2)); + return allSorts2.entrySet().stream() + .map( + e -> { + CompletionItem ci = new CompletionItem(); + ci.setLabel(e.getKey()); + ci.setInsertText(e.getKey()); + // TODO: to calculate properly we need to recurse through the inclusion tree + // and find the first module to declare the sort. This should be easy to get + // when we connect to the kompile pipeline. + // ci.setDetail("module " + m.getName()); + String documentation = "syntax " + e.getKey() + " "; + documentation += e.getValue().toString(); + ci.setDocumentation(documentation); + ci.setKind(CompletionItemKind.TypeParameter); + return ci; + }) + .collect(Collectors.toList()); + } } diff --git a/kernel/src/main/java/org/kframework/lsp/KLanguageServer.java b/kernel/src/main/java/org/kframework/lsp/KLanguageServer.java index 8487a314c18..5d6d0c6614e 100644 --- a/kernel/src/main/java/org/kframework/lsp/KLanguageServer.java +++ b/kernel/src/main/java/org/kframework/lsp/KLanguageServer.java @@ -1,7 +1,14 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; +import static org.kframework.kompile.Kompile.CACHE_FILE_NAME; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.eclipse.lsp4j.services.LanguageClient; @@ -11,121 +18,126 @@ import org.eclipse.lsp4j.services.WorkspaceService; import org.kframework.main.Main; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -import static org.kframework.kompile.Kompile.CACHE_FILE_NAME; - -/** - * Language Server implementation for the K framework. - */ +/** Language Server implementation for the K framework. */ public class KLanguageServer implements LanguageServer, LanguageClientAware { - private final TextDocumentService textDocumentService; - private final WorkspaceService workspaceService; - private ClientCapabilities clientCapabilities; - LanguageClient languageClient; - List workspaceFolders; - private int shutdown = 1; - - public KLanguageServer() { - try { - this.textDocumentService = new KTextDocumentService(this); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - this.workspaceService = new KWorkspaceService(this); + private final TextDocumentService textDocumentService; + private final WorkspaceService workspaceService; + private ClientCapabilities clientCapabilities; + LanguageClient languageClient; + List workspaceFolders; + private int shutdown = 1; + + public KLanguageServer() { + try { + this.textDocumentService = new KTextDocumentService(this); + } catch (URISyntaxException e) { + throw new RuntimeException(e); } - - @Override - public CompletableFuture initialize(InitializeParams initializeParams) { - workspaceFolders = initializeParams.getWorkspaceFolders(); - LSClientLogger.getInstance().logMessage("initWorkspaceFolders: " + initializeParams.getWorkspaceFolders()); - - final InitializeResult response = new InitializeResult(new ServerCapabilities()); - //Set the document synchronization capabilities to full. - response.getCapabilities().setTextDocumentSync(TextDocumentSyncKind.Full); - this.clientCapabilities = initializeParams.getCapabilities(); - - /* Check if dynamic registration of completion capability is allowed by the client. If so we don't register the capability. - Else, we register the completion capability. - */ - // TODO: check if this needs to be guarded - response.getCapabilities().setReferencesProvider(true); - response.getCapabilities().setDefinitionProvider(true); - response.getCapabilities().setSelectionRangeProvider(true); - - if (!isDynamicCompletionRegistration()) - response.getCapabilities().setCompletionProvider(new CompletionOptions()); - if (!isDiagnosticRegistration()) - response.getCapabilities().setDiagnosticProvider(new DiagnosticRegistrationOptions(false, false)); - return CompletableFuture.supplyAsync(() -> response); - } - - @Override - public void initialized(InitializedParams params) { - //Check if dynamic completion support is allowed, if so register. - if (isDynamicCompletionRegistration()) { - CompletionRegistrationOptions completionRegistrationOptions = new CompletionRegistrationOptions(); - Registration completionRegistration = new Registration(UUID.randomUUID().toString(), - "textDocument/completion", completionRegistrationOptions); - languageClient.registerCapability(new RegistrationParams(List.of(completionRegistration))); - } - if (isDiagnosticRegistration()) { - DiagnosticRegistrationOptions diagnosticRegistrationOptions = new DiagnosticRegistrationOptions(false, false); - Registration diagnosticRegistration = new Registration(UUID.randomUUID().toString(), - "textDocument/diagnostic", diagnosticRegistrationOptions); - languageClient.registerCapability(new RegistrationParams(List.of(diagnosticRegistration))); - } - // Register file watchers - List watchers = new ArrayList<>(); - watchers.add(new FileSystemWatcher(Either.forLeft("/**/" + CACHE_FILE_NAME), - WatchKind.Create + WatchKind.Delete + WatchKind.Change)); - DidChangeWatchedFilesRegistrationOptions opts = new DidChangeWatchedFilesRegistrationOptions(watchers); - Registration registration = new Registration(UUID.randomUUID().toString(), - "workspace/didChangeWatchedFiles", opts); - languageClient.registerCapability(new RegistrationParams(Collections.singletonList(registration))); - } - - @Override - public CompletableFuture shutdown() { - shutdown = 0; - return CompletableFuture.supplyAsync(Object::new); - } - - @Override - public void exit() { - Main.exit(shutdown); - } - - @Override - public TextDocumentService getTextDocumentService() { - return this.textDocumentService; - } - - @Override - public WorkspaceService getWorkspaceService() { - return this.workspaceService; - } - - @Override - public void connect(LanguageClient languageClient) { - this.languageClient = languageClient; - LSClientLogger.getInstance().initialize(this.languageClient); - } - - private boolean isDynamicCompletionRegistration() { - TextDocumentClientCapabilities textDocumentCapabilities = clientCapabilities.getTextDocument(); - return textDocumentCapabilities != null && textDocumentCapabilities.getCompletion() != null - && Boolean.FALSE.equals(textDocumentCapabilities.getCompletion().getDynamicRegistration()); + this.workspaceService = new KWorkspaceService(this); + } + + @Override + public CompletableFuture initialize(InitializeParams initializeParams) { + workspaceFolders = initializeParams.getWorkspaceFolders(); + LSClientLogger.getInstance() + .logMessage("initWorkspaceFolders: " + initializeParams.getWorkspaceFolders()); + + final InitializeResult response = new InitializeResult(new ServerCapabilities()); + // Set the document synchronization capabilities to full. + response.getCapabilities().setTextDocumentSync(TextDocumentSyncKind.Full); + this.clientCapabilities = initializeParams.getCapabilities(); + + /* Check if dynamic registration of completion capability is allowed by the client. If so we don't register the capability. + Else, we register the completion capability. + */ + // TODO: check if this needs to be guarded + response.getCapabilities().setReferencesProvider(true); + response.getCapabilities().setDefinitionProvider(true); + response.getCapabilities().setSelectionRangeProvider(true); + + if (!isDynamicCompletionRegistration()) + response.getCapabilities().setCompletionProvider(new CompletionOptions()); + if (!isDiagnosticRegistration()) + response + .getCapabilities() + .setDiagnosticProvider(new DiagnosticRegistrationOptions(false, false)); + return CompletableFuture.supplyAsync(() -> response); + } + + @Override + public void initialized(InitializedParams params) { + // Check if dynamic completion support is allowed, if so register. + if (isDynamicCompletionRegistration()) { + CompletionRegistrationOptions completionRegistrationOptions = + new CompletionRegistrationOptions(); + Registration completionRegistration = + new Registration( + UUID.randomUUID().toString(), + "textDocument/completion", + completionRegistrationOptions); + languageClient.registerCapability(new RegistrationParams(List.of(completionRegistration))); } - - private boolean isDiagnosticRegistration() { - TextDocumentClientCapabilities textDocumentCapabilities = clientCapabilities.getTextDocument(); - return textDocumentCapabilities != null && textDocumentCapabilities.getDiagnostic() != null; + if (isDiagnosticRegistration()) { + DiagnosticRegistrationOptions diagnosticRegistrationOptions = + new DiagnosticRegistrationOptions(false, false); + Registration diagnosticRegistration = + new Registration( + UUID.randomUUID().toString(), + "textDocument/diagnostic", + diagnosticRegistrationOptions); + languageClient.registerCapability(new RegistrationParams(List.of(diagnosticRegistration))); } + // Register file watchers + List watchers = new ArrayList<>(); + watchers.add( + new FileSystemWatcher( + Either.forLeft("/**/" + CACHE_FILE_NAME), + WatchKind.Create + WatchKind.Delete + WatchKind.Change)); + DidChangeWatchedFilesRegistrationOptions opts = + new DidChangeWatchedFilesRegistrationOptions(watchers); + Registration registration = + new Registration(UUID.randomUUID().toString(), "workspace/didChangeWatchedFiles", opts); + languageClient.registerCapability( + new RegistrationParams(Collections.singletonList(registration))); + } + + @Override + public CompletableFuture shutdown() { + shutdown = 0; + return CompletableFuture.supplyAsync(Object::new); + } + + @Override + public void exit() { + Main.exit(shutdown); + } + + @Override + public TextDocumentService getTextDocumentService() { + return this.textDocumentService; + } + + @Override + public WorkspaceService getWorkspaceService() { + return this.workspaceService; + } + + @Override + public void connect(LanguageClient languageClient) { + this.languageClient = languageClient; + LSClientLogger.getInstance().initialize(this.languageClient); + } + + private boolean isDynamicCompletionRegistration() { + TextDocumentClientCapabilities textDocumentCapabilities = clientCapabilities.getTextDocument(); + return textDocumentCapabilities != null + && textDocumentCapabilities.getCompletion() != null + && Boolean.FALSE.equals(textDocumentCapabilities.getCompletion().getDynamicRegistration()); + } + + private boolean isDiagnosticRegistration() { + TextDocumentClientCapabilities textDocumentCapabilities = clientCapabilities.getTextDocument(); + return textDocumentCapabilities != null && textDocumentCapabilities.getDiagnostic() != null; + } } diff --git a/kernel/src/main/java/org/kframework/lsp/KLanguageServerLauncher.java b/kernel/src/main/java/org/kframework/lsp/KLanguageServerLauncher.java index 96bce81e480..775dead12ff 100644 --- a/kernel/src/main/java/org/kframework/lsp/KLanguageServerLauncher.java +++ b/kernel/src/main/java/org/kframework/lsp/KLanguageServerLauncher.java @@ -1,37 +1,36 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; -import org.eclipse.lsp4j.jsonrpc.Launcher; -import org.eclipse.lsp4j.services.LanguageClient; - import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import org.eclipse.lsp4j.jsonrpc.Launcher; +import org.eclipse.lsp4j.services.LanguageClient; -/** - * Standard IO Launcher for K Language Server. - */ +/** Standard IO Launcher for K Language Server. */ public class KLanguageServerLauncher { - public static void main(String[] args) throws InterruptedException, ExecutionException { - startServer(System.in, System.out); - } + public static void main(String[] args) throws InterruptedException, ExecutionException { + startServer(System.in, System.out); + } - /** - * Starts the language server given the input and output streams to read and write messages. - * - * @param in input stream. - * @param out output stream. - * @throws InterruptedException - * @throws ExecutionException - */ - public static void startServer(InputStream in, OutputStream out) throws InterruptedException, ExecutionException { - KLanguageServer server = new KLanguageServer(); - Launcher launcher = Launcher.createLauncher(server, LanguageClient.class, in, out); - LanguageClient client = launcher.getRemoteProxy(); - server.connect(client); - Future startListening = launcher.startListening(); - startListening.get(); - } + /** + * Starts the language server given the input and output streams to read and write messages. + * + * @param in input stream. + * @param out output stream. + * @throws InterruptedException + * @throws ExecutionException + */ + public static void startServer(InputStream in, OutputStream out) + throws InterruptedException, ExecutionException { + KLanguageServer server = new KLanguageServer(); + Launcher launcher = + Launcher.createLauncher(server, LanguageClient.class, in, out); + LanguageClient client = launcher.getRemoteProxy(); + server.connect(client); + Future startListening = launcher.startListening(); + startListening.get(); + } } diff --git a/kernel/src/main/java/org/kframework/lsp/KPos.java b/kernel/src/main/java/org/kframework/lsp/KPos.java index 19561a547d9..942414f8bf6 100644 --- a/kernel/src/main/java/org/kframework/lsp/KPos.java +++ b/kernel/src/main/java/org/kframework/lsp/KPos.java @@ -1,79 +1,71 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; -import org.eclipse.lsp4j.Position; - import java.util.Objects; +import org.eclipse.lsp4j.Position; /** - * KPos a position in a file starting from one. - * Use this class when converting positions to aviod off by one errors. + * KPos a position in a file starting from one. Use this class when converting positions to aviod + * off by one errors. */ public class KPos { - /** - * Line position in a document (one-based). - */ - private int line; - - /** - * Character offset on a line in a document (one-based). - */ - private int character; - - public KPos() { - line = 0; - character = 0; - } - - public KPos(int line, int character) { - this.line = line; - this.character = character; - } - - public KPos(Position pos) { - this.line = pos.getLine() + 1; - this.character = pos.getCharacter() + 1; - } - - public Position toPosition() { - return new Position(line - 1, character - 1); - } - - public int getLine() { - return line; - } - - public void setLine(int line) { - this.line = line; - } - - public int getCharacter() { - return character; - } - - public void setCharacter(int character) { - this.character = character; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - KPos kPos = (KPos) o; - return line == kPos.line && character == kPos.character; - } - - @Override - public int hashCode() { - return Objects.hash(line, character); - } - - @Override - public String toString() { - return "KPos{" + - "l:" + line + - ", c:" + character + - '}'; - } + /** Line position in a document (one-based). */ + private int line; + + /** Character offset on a line in a document (one-based). */ + private int character; + + public KPos() { + line = 0; + character = 0; + } + + public KPos(int line, int character) { + this.line = line; + this.character = character; + } + + public KPos(Position pos) { + this.line = pos.getLine() + 1; + this.character = pos.getCharacter() + 1; + } + + public Position toPosition() { + return new Position(line - 1, character - 1); + } + + public int getLine() { + return line; + } + + public void setLine(int line) { + this.line = line; + } + + public int getCharacter() { + return character; + } + + public void setCharacter(int character) { + this.character = character; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KPos kPos = (KPos) o; + return line == kPos.line && character == kPos.character; + } + + @Override + public int hashCode() { + return Objects.hash(line, character); + } + + @Override + public String toString() { + return "KPos{" + "l:" + line + ", c:" + character + '}'; + } } diff --git a/kernel/src/main/java/org/kframework/lsp/KTextDocument.java b/kernel/src/main/java/org/kframework/lsp/KTextDocument.java index f287b1f80e8..d0163b91176 100644 --- a/kernel/src/main/java/org/kframework/lsp/KTextDocument.java +++ b/kernel/src/main/java/org/kframework/lsp/KTextDocument.java @@ -1,7 +1,10 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; - +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.eclipse.lsp4j.Diagnostic; import org.eclipse.lsp4j.DiagnosticSeverity; import org.eclipse.lsp4j.Range; @@ -12,82 +15,78 @@ import org.kframework.parser.outer.Outer; import org.kframework.utils.errorsystem.KEMException; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Store information about each file. - */ +/** Store information about each file. */ public class KTextDocument { - public String content = ""; - public String uri = ""; - public int[] lines; - public int[] columns; - public boolean linesOutdated = true; - public boolean parsingOutdated = true; - public List problems = new ArrayList<>(); - // definition items provided by outer parsing - public List dis = new ArrayList<>(); - public static final ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(null, "k"); + public String content = ""; + public String uri = ""; + public int[] lines; + public int[] columns; + public boolean linesOutdated = true; + public boolean parsingOutdated = true; + public List problems = new ArrayList<>(); + // definition items provided by outer parsing + public List dis = new ArrayList<>(); + public static final ExtractFencedKCodeFromMarkdown mdExtractor = + new ExtractFencedKCodeFromMarkdown(null, "k"); - public void updateText(String input) { - parsingOutdated = true; - linesOutdated = true; - content = input; - problems.clear(); - } + public void updateText(String input) { + parsingOutdated = true; + linesOutdated = true; + content = input; + problems.clear(); + } - private static final Pattern p = Pattern.compile("(module|endmodule|syntax|context|configuration|rule|claim|import[s]?)"); + private static final Pattern p = + Pattern.compile("(module|endmodule|syntax|context|configuration|rule|claim|import[s]?)"); - // get the last keyword at KPos in order to provide contextual completion - public String getContextAt(KPos pos) { - if (linesOutdated) { - linesOutdated = false; - lines = new int[content.length() + 1]; - columns = new int[content.length() + 1]; - int l = 1; - int c = 1; - for (int offset = 0; offset < content.length(); offset++) { - lines[offset] = l; - columns[offset] = c; - if (content.codePointAt(offset) == '\n') { - l++; - c = 0; - } - c++; - } - lines[content.length()] = l; - columns[content.length()] = c; + // get the last keyword at KPos in order to provide contextual completion + public String getContextAt(KPos pos) { + if (linesOutdated) { + linesOutdated = false; + lines = new int[content.length() + 1]; + columns = new int[content.length() + 1]; + int l = 1; + int c = 1; + for (int offset = 0; offset < content.length(); offset++) { + lines[offset] = l; + columns[offset] = c; + if (content.codePointAt(offset) == '\n') { + l++; + c = 0; } - Matcher m = p.matcher(content); - String context = ""; - while (m.find()) { - if (lines[m.end()] > pos.getLine() || lines[m.end()] == pos.getLine() && columns[m.end()] > pos.getCharacter()) - break; - context = m.group(); - } - return context; + c++; + } + lines[content.length()] = l; + columns[content.length()] = c; + } + Matcher m = p.matcher(content); + String context = ""; + while (m.find()) { + if (lines[m.end()] > pos.getLine() + || lines[m.end()] == pos.getLine() && columns[m.end()] > pos.getCharacter()) break; + context = m.group(); } + return context; + } - public void outerParse() { - if (parsingOutdated) { - parsingOutdated = false; - problems.clear(); - try { - String contents = this.content; - if (uri.endsWith(".md")) - contents = mdExtractor.extract(contents, Source.apply(uri)); - dis = Outer.parse(Source.apply(uri), contents, null); - } catch (KEMException e) { - Location loc = e.exception.getLocation(); - if (loc == null) loc = new Location(1, 1, 1, 2); - Range range = TextDocumentSyncHandler.loc2range(loc); - Diagnostic d = new Diagnostic(range, e.exception.getMessage(), DiagnosticSeverity.Error, "Outer Parser"); - problems.add(d); - } - } + public void outerParse() { + if (parsingOutdated) { + parsingOutdated = false; + problems.clear(); + try { + String contents = this.content; + if (uri.endsWith(".md")) contents = mdExtractor.extract(contents, Source.apply(uri)); + dis = Outer.parse(Source.apply(uri), contents, null); + } catch (KEMException e) { + Location loc = e.exception.getLocation(); + if (loc == null) loc = new Location(1, 1, 1, 2); + Range range = TextDocumentSyncHandler.loc2range(loc); + Diagnostic d = + new Diagnostic( + range, e.exception.getMessage(), DiagnosticSeverity.Error, "Outer Parser"); + problems.add(d); + } } + } } diff --git a/kernel/src/main/java/org/kframework/lsp/KTextDocumentService.java b/kernel/src/main/java/org/kframework/lsp/KTextDocumentService.java index 4d005a8ec27..dca4abad70d 100644 --- a/kernel/src/main/java/org/kframework/lsp/KTextDocumentService.java +++ b/kernel/src/main/java/org/kframework/lsp/KTextDocumentService.java @@ -1,11 +1,6 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; -import org.eclipse.lsp4j.*; -import org.eclipse.lsp4j.jsonrpc.messages.Either; -import org.eclipse.lsp4j.services.TextDocumentService; -import org.kframework.kompile.Kompile; - import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -13,92 +8,119 @@ import java.nio.file.Path; import java.util.List; import java.util.concurrent.CompletableFuture; +import org.eclipse.lsp4j.*; +import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.kframework.kompile.Kompile; -/** - * TextDocumentService implementation for K. - */ +/** TextDocumentService implementation for K. */ public class KTextDocumentService implements TextDocumentService { - private final KLanguageServer languageServer; - private final LSClientLogger clientLogger; - - public final TextDocumentSyncHandler memo; - public static final URI domains; - public static final URI kast; - // time delay after which to start doing completion calculation - public static long DELAY_EXECUTION_MS = 1000; - - static { - try { - domains = Path.of(Kompile.BUILTIN_DIRECTORY.toString(), "domains.md").toRealPath(LinkOption.NOFOLLOW_LINKS).toUri(); - kast = Path.of(Kompile.BUILTIN_DIRECTORY.toString(), "kast.md").toRealPath(LinkOption.NOFOLLOW_LINKS).toUri(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - - public KTextDocumentService(KLanguageServer languageServer) throws URISyntaxException { - this.languageServer = languageServer; - this.clientLogger = LSClientLogger.getInstance(); - memo = new TextDocumentSyncHandler(clientLogger, languageServer); - memo.add(domains.toString()); - memo.add(kast.toString()); - this.clientLogger.logMessage("Operation '" + "text/workspaceFolders " + languageServer.workspaceFolders); - } - - @Override - public void didOpen(DidOpenTextDocumentParams didOpenTextDocumentParams) { - this.clientLogger.logMessage("Operation '" + "text/didOpen" + - "' {fileUri: '" + didOpenTextDocumentParams.getTextDocument().getUri() + "'} opened"); - memo.didOpen(didOpenTextDocumentParams); - } - - @Override - public void didChange(DidChangeTextDocumentParams didChangeTextDocumentParams) { - this.clientLogger.logMessage("Operation '" + "text/didChange" + - "' {fileUri: '" + didChangeTextDocumentParams.getTextDocument().getUri() + "'} Changed"); - memo.didChange(didChangeTextDocumentParams); - } - - @Override - public void didClose(DidCloseTextDocumentParams didCloseTextDocumentParams) { - this.clientLogger.logMessage("Operation '" + "text/didClose" + - "' {fileUri: '" + didCloseTextDocumentParams.getTextDocument().getUri() + "'} Closed"); - if (!(didCloseTextDocumentParams.getTextDocument().getUri().equals(domains.toString()) - || didCloseTextDocumentParams.getTextDocument().getUri().equals(kast.toString()))) - memo.didClose(didCloseTextDocumentParams); - } - - @Override - public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) { - this.clientLogger.logMessage("Operation '" + "text/didSave" + - "' {fileUri: '" + didSaveTextDocumentParams.getTextDocument().getUri() + "'} Saved"); - memo.didSave(didSaveTextDocumentParams); - } - - @Override - public CompletableFuture, CompletionList>> completion(CompletionParams position) { - return memo.completion(position); - } - - @Override - public CompletableFuture diagnostic(DocumentDiagnosticParams params) { - return memo.diagnostic(params); - } - - @Override - public CompletableFuture, List>> definition(DefinitionParams params) { - return memo.definition(params); - } - - @Override - public CompletableFuture> references(ReferenceParams params) { - return memo.references(params); - } - - @Override - public CompletableFuture> selectionRange(SelectionRangeParams params) { - return memo.selectionRange(params); + private final KLanguageServer languageServer; + private final LSClientLogger clientLogger; + + public final TextDocumentSyncHandler memo; + public static final URI domains; + public static final URI kast; + // time delay after which to start doing completion calculation + public static long DELAY_EXECUTION_MS = 1000; + + static { + try { + domains = + Path.of(Kompile.BUILTIN_DIRECTORY.toString(), "domains.md") + .toRealPath(LinkOption.NOFOLLOW_LINKS) + .toUri(); + kast = + Path.of(Kompile.BUILTIN_DIRECTORY.toString(), "kast.md") + .toRealPath(LinkOption.NOFOLLOW_LINKS) + .toUri(); + } catch (IOException e) { + throw new RuntimeException(e); } + } + + public KTextDocumentService(KLanguageServer languageServer) throws URISyntaxException { + this.languageServer = languageServer; + this.clientLogger = LSClientLogger.getInstance(); + memo = new TextDocumentSyncHandler(clientLogger, languageServer); + memo.add(domains.toString()); + memo.add(kast.toString()); + this.clientLogger.logMessage( + "Operation '" + "text/workspaceFolders " + languageServer.workspaceFolders); + } + + @Override + public void didOpen(DidOpenTextDocumentParams didOpenTextDocumentParams) { + this.clientLogger.logMessage( + "Operation '" + + "text/didOpen" + + "' {fileUri: '" + + didOpenTextDocumentParams.getTextDocument().getUri() + + "'} opened"); + memo.didOpen(didOpenTextDocumentParams); + } + + @Override + public void didChange(DidChangeTextDocumentParams didChangeTextDocumentParams) { + this.clientLogger.logMessage( + "Operation '" + + "text/didChange" + + "' {fileUri: '" + + didChangeTextDocumentParams.getTextDocument().getUri() + + "'} Changed"); + memo.didChange(didChangeTextDocumentParams); + } + + @Override + public void didClose(DidCloseTextDocumentParams didCloseTextDocumentParams) { + this.clientLogger.logMessage( + "Operation '" + + "text/didClose" + + "' {fileUri: '" + + didCloseTextDocumentParams.getTextDocument().getUri() + + "'} Closed"); + if (!(didCloseTextDocumentParams.getTextDocument().getUri().equals(domains.toString()) + || didCloseTextDocumentParams.getTextDocument().getUri().equals(kast.toString()))) + memo.didClose(didCloseTextDocumentParams); + } + + @Override + public void didSave(DidSaveTextDocumentParams didSaveTextDocumentParams) { + this.clientLogger.logMessage( + "Operation '" + + "text/didSave" + + "' {fileUri: '" + + didSaveTextDocumentParams.getTextDocument().getUri() + + "'} Saved"); + memo.didSave(didSaveTextDocumentParams); + } + + @Override + public CompletableFuture, CompletionList>> completion( + CompletionParams position) { + return memo.completion(position); + } + + @Override + public CompletableFuture diagnostic(DocumentDiagnosticParams params) { + return memo.diagnostic(params); + } + + @Override + public CompletableFuture< + Either, List>> + definition(DefinitionParams params) { + return memo.definition(params); + } + + @Override + public CompletableFuture> references(ReferenceParams params) { + return memo.references(params); + } + + @Override + public CompletableFuture> selectionRange(SelectionRangeParams params) { + return memo.selectionRange(params); + } } diff --git a/kernel/src/main/java/org/kframework/lsp/KWorkspaceService.java b/kernel/src/main/java/org/kframework/lsp/KWorkspaceService.java index 7e0852a1362..93e05d10ca6 100644 --- a/kernel/src/main/java/org/kframework/lsp/KWorkspaceService.java +++ b/kernel/src/main/java/org/kframework/lsp/KWorkspaceService.java @@ -6,34 +6,32 @@ import org.eclipse.lsp4j.RenameFilesParams; import org.eclipse.lsp4j.services.WorkspaceService; -/** - * WorkspaceService implementation for K. - */ +/** WorkspaceService implementation for K. */ public class KWorkspaceService implements WorkspaceService { - private final KLanguageServer languageServer; - LSClientLogger clientLogger; + private final KLanguageServer languageServer; + LSClientLogger clientLogger; - public KWorkspaceService(KLanguageServer languageServer) { - this.languageServer = languageServer; - this.clientLogger = LSClientLogger.getInstance(); - } + public KWorkspaceService(KLanguageServer languageServer) { + this.languageServer = languageServer; + this.clientLogger = LSClientLogger.getInstance(); + } - @Override - public void didChangeConfiguration(DidChangeConfigurationParams didChangeConfigurationParams) { - this.clientLogger.logMessage("Operation 'workspace/didChangeConfiguration' Ack"); - } + @Override + public void didChangeConfiguration(DidChangeConfigurationParams didChangeConfigurationParams) { + this.clientLogger.logMessage("Operation 'workspace/didChangeConfiguration' Ack"); + } - @Override - public void didChangeWatchedFiles(DidChangeWatchedFilesParams didChangeWatchedFilesParams) { - this.clientLogger.logMessage("Operation 'workspace/didChangeWatchedFiles' Ack"); - KTextDocumentService ktxt = (KTextDocumentService) languageServer.getTextDocumentService(); - ktxt.memo.loadCaches(); - languageServer.languageClient.refreshDiagnostics(); - } + @Override + public void didChangeWatchedFiles(DidChangeWatchedFilesParams didChangeWatchedFilesParams) { + this.clientLogger.logMessage("Operation 'workspace/didChangeWatchedFiles' Ack"); + KTextDocumentService ktxt = (KTextDocumentService) languageServer.getTextDocumentService(); + ktxt.memo.loadCaches(); + languageServer.languageClient.refreshDiagnostics(); + } - @Override - public void didRenameFiles(RenameFilesParams params) { - this.clientLogger.logMessage("Operation 'workspace/didRenameFiles' Ack"); - } + @Override + public void didRenameFiles(RenameFilesParams params) { + this.clientLogger.logMessage("Operation 'workspace/didRenameFiles' Ack"); + } } diff --git a/kernel/src/main/java/org/kframework/lsp/LSClientLogger.java b/kernel/src/main/java/org/kframework/lsp/LSClientLogger.java index 41f3377541d..9f6f06d2847 100644 --- a/kernel/src/main/java/org/kframework/lsp/LSClientLogger.java +++ b/kernel/src/main/java/org/kframework/lsp/LSClientLogger.java @@ -5,36 +5,33 @@ import org.eclipse.lsp4j.MessageType; import org.eclipse.lsp4j.services.LanguageClient; -/** - * Use this class to send log messages to the client. - */ +/** Use this class to send log messages to the client. */ public class LSClientLogger { - private static LSClientLogger INSTANCE; - private LanguageClient client; - private boolean isInitialized; + private static LSClientLogger INSTANCE; + private LanguageClient client; + private boolean isInitialized; - private LSClientLogger() { - } + private LSClientLogger() {} - public void initialize(LanguageClient languageClient) { - if (!Boolean.TRUE.equals(isInitialized)) { - this.client = languageClient; - } - isInitialized = true; + public void initialize(LanguageClient languageClient) { + if (!Boolean.TRUE.equals(isInitialized)) { + this.client = languageClient; } + isInitialized = true; + } - public static LSClientLogger getInstance() { - if (INSTANCE == null) { - INSTANCE = new LSClientLogger(); - } - return INSTANCE; + public static LSClientLogger getInstance() { + if (INSTANCE == null) { + INSTANCE = new LSClientLogger(); } + return INSTANCE; + } - public void logMessage(String message) { - if (!isInitialized) { - return; - } - client.logMessage(new MessageParams(MessageType.Info, message)); + public void logMessage(String message) { + if (!isInitialized) { + return; } + client.logMessage(new MessageParams(MessageType.Info, message)); + } } diff --git a/kernel/src/main/java/org/kframework/lsp/TextDocumentSyncHandler.java b/kernel/src/main/java/org/kframework/lsp/TextDocumentSyncHandler.java index d204107e46a..92788117e1a 100644 --- a/kernel/src/main/java/org/kframework/lsp/TextDocumentSyncHandler.java +++ b/kernel/src/main/java/org/kframework/lsp/TextDocumentSyncHandler.java @@ -1,15 +1,30 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; +import static org.kframework.kompile.Kompile.CACHE_FILE_NAME; +import static org.kframework.lsp.CompletionHelper.*; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.kframework.attributes.Att; import org.kframework.attributes.Source; import org.kframework.definition.Bubble; import org.kframework.definition.KViz; -import org.kframework.kil.Module; import org.kframework.kil.*; +import org.kframework.kil.Module; import org.kframework.kompile.DefinitionParsing; import org.kframework.kore.K; import org.kframework.main.GlobalOptions; @@ -19,501 +34,770 @@ import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.Path; -import java.util.*; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import static org.kframework.kompile.Kompile.CACHE_FILE_NAME; -import static org.kframework.lsp.CompletionHelper.*; - -/** - * Handle the caches of all the files of interest. - */ +/** Handle the caches of all the files of interest. */ public class TextDocumentSyncHandler { - public Map files = new HashMap<>(); - public Map caches = new HashMap<>(); - private final LSClientLogger clientLogger; - private final KLanguageServer kls; - private WorkspaceFolder workspaceFolder; - private Optional cacheFile = Optional.empty(); - - private static final BinaryLoader loader = new BinaryLoader(new KExceptionManager(new GlobalOptions())); - - - public TextDocumentSyncHandler(LSClientLogger clientLogger, KLanguageServer kls) { - this.clientLogger = clientLogger; - this.kls = kls; - } - - public void findCacheFile() { - if (workspaceFolder != null || kls.workspaceFolders == null) - return; - try { - workspaceFolder = kls.workspaceFolders.get(0); - // TODO: find a better way to get the kompiled directory - maybe with the toml file from KBuild - cacheFile = Files.walk(Path.of(URI.create(workspaceFolder.getUri()))) - .filter(p -> p.endsWith(CACHE_FILE_NAME)).findFirst(); - loadCaches(); - } catch (IOException e) { - clientLogger.logMessage("findCachesException: " + e); - } + public Map files = new HashMap<>(); + public Map caches = new HashMap<>(); + private final LSClientLogger clientLogger; + private final KLanguageServer kls; + private WorkspaceFolder workspaceFolder; + private Optional cacheFile = Optional.empty(); + + private static final BinaryLoader loader = + new BinaryLoader(new KExceptionManager(new GlobalOptions())); + + public TextDocumentSyncHandler(LSClientLogger clientLogger, KLanguageServer kls) { + this.clientLogger = clientLogger; + this.kls = kls; + } + + public void findCacheFile() { + if (workspaceFolder != null || kls.workspaceFolders == null) return; + try { + workspaceFolder = kls.workspaceFolders.get(0); + // TODO: find a better way to get the kompiled directory - maybe with the toml file from + // KBuild + cacheFile = + Files.walk(Path.of(URI.create(workspaceFolder.getUri()))) + .filter(p -> p.endsWith(CACHE_FILE_NAME)) + .findFirst(); + loadCaches(); + } catch (IOException e) { + clientLogger.logMessage("findCachesException: " + e); } - - public void loadCaches() { - cacheFile.ifPresent(path -> caches = loader.loadCache(java.util.Map.class, path.toFile())); - if (caches == null) - caches = new HashMap<>(); - caches.forEach((key, val) -> { - String uri = Path.of(val.module().att().get(org.kframework.attributes.Source.class).source()).toUri().toString(); - // load into LSP all the files found in the caches, even if they are not open in the IDE. - // this way we can find all the updated locations when finding references - if (!files.containsKey(uri)) - add(uri); + } + + public void loadCaches() { + cacheFile.ifPresent(path -> caches = loader.loadCache(java.util.Map.class, path.toFile())); + if (caches == null) caches = new HashMap<>(); + caches.forEach( + (key, val) -> { + String uri = + Path.of(val.module().att().get(org.kframework.attributes.Source.class).source()) + .toUri() + .toString(); + // load into LSP all the files found in the caches, even if they are not open in the IDE. + // this way we can find all the updated locations when finding references + if (!files.containsKey(uri)) add(uri); }); - clientLogger.logMessage("loaded cached modules: " + caches.size()); - } - - public void add(String uri) { - try { - KTextDocument doc = new KTextDocument(); - files.put(uri, doc); - doc.uri = uri; - doc.updateText(FileUtil.load(new File(new URI(uri)))); - doc.outerParse(); - } catch (URISyntaxException e) { - clientLogger.logMessage(TextDocumentSyncHandler.class + ".addUri failed: " + uri); - } - } - - public void didOpen(DidOpenTextDocumentParams params) { - String uri = params.getTextDocument().getUri(); - KTextDocument doc; - if (files.containsKey(uri)) - doc = files.get(uri); - else { - doc = new KTextDocument(); - doc.uri = uri; - files.put(uri, doc); - } - doc.updateText(params.getTextDocument().getText()); - } - - public void didChange(DidChangeTextDocumentParams params) { - files.get(params.getTextDocument().getUri()).updateText(params.getContentChanges().get(0).getText()); - } - - public void didSave(DidSaveTextDocumentParams params) { - KTextDocument doc = files.get(params.getTextDocument().getUri()); - doc.outerParse(); + clientLogger.logMessage("loaded cached modules: " + caches.size()); + } + + public void add(String uri) { + try { + KTextDocument doc = new KTextDocument(); + files.put(uri, doc); + doc.uri = uri; + doc.updateText(FileUtil.load(new File(new URI(uri)))); + doc.outerParse(); + } catch (URISyntaxException e) { + clientLogger.logMessage(TextDocumentSyncHandler.class + ".addUri failed: " + uri); } - - public void didClose(DidCloseTextDocumentParams params) { - // do not remove files from memory - //files.remove(params.getTextDocument().getUri()); + } + + public void didOpen(DidOpenTextDocumentParams params) { + String uri = params.getTextDocument().getUri(); + KTextDocument doc; + if (files.containsKey(uri)) doc = files.get(uri); + else { + doc = new KTextDocument(); + doc.uri = uri; + files.put(uri, doc); } - - // recurse through all the required files and return the list of DefinitionItems - public List slurp(String uri) { - Set visited = new HashSet<>(); - visited.add(KTextDocumentService.domains.toString()); - visited.add(KTextDocumentService.kast.toString()); - slurp2(uri, visited); - List dis = files.entrySet().stream() - .filter(e -> visited.contains(e.getKey())) - .flatMap(e -> e.getValue().dis.stream()) - .collect(Collectors.toList()); - return dis; + doc.updateText(params.getTextDocument().getText()); + } + + public void didChange(DidChangeTextDocumentParams params) { + files + .get(params.getTextDocument().getUri()) + .updateText(params.getContentChanges().get(0).getText()); + } + + public void didSave(DidSaveTextDocumentParams params) { + KTextDocument doc = files.get(params.getTextDocument().getUri()); + doc.outerParse(); + } + + public void didClose(DidCloseTextDocumentParams params) { + // do not remove files from memory + // files.remove(params.getTextDocument().getUri()); + } + + // recurse through all the required files and return the list of DefinitionItems + public List slurp(String uri) { + Set visited = new HashSet<>(); + visited.add(KTextDocumentService.domains.toString()); + visited.add(KTextDocumentService.kast.toString()); + slurp2(uri, visited); + List dis = + files.entrySet().stream() + .filter(e -> visited.contains(e.getKey())) + .flatMap(e -> e.getValue().dis.stream()) + .collect(Collectors.toList()); + return dis; + } + + private void slurp2(String uri, Set visited) { + if (!files.containsKey(uri)) { + try { + if (new File(new URI(uri)).exists()) add(uri); + } catch (URISyntaxException e) { + clientLogger.logMessage( + TextDocumentSyncHandler.class + ".slurp failed1: " + uri + "\n" + e.getMessage()); + } } - - private void slurp2(String uri, Set visited) { - if (!files.containsKey(uri)) { - try { - if (new File(new URI(uri)).exists()) - add(uri); - } catch (URISyntaxException e) { - clientLogger.logMessage(TextDocumentSyncHandler.class + ".slurp failed1: " + uri + "\n" + e.getMessage()); - } - } - KTextDocument current = files.get(uri); - if (current.parsingOutdated) - current.outerParse(); - if (!visited.contains(uri) && files.containsKey(uri)) { - visited.add(uri); - files.get(uri).dis.forEach(r -> { + KTextDocument current = files.get(uri); + if (current.parsingOutdated) current.outerParse(); + if (!visited.contains(uri) && files.containsKey(uri)) { + visited.add(uri); + files + .get(uri) + .dis + .forEach( + r -> { if (r instanceof Require) { - try { - Require req = (Require) r; - URI targetURI = Path.of(new File(new URI(uri)).getParent(), req.getValue()).toRealPath(LinkOption.NOFOLLOW_LINKS).toUri(); - slurp2(targetURI.toString(), visited); - } catch (IOException | URISyntaxException e) { - clientLogger.logMessage(TextDocumentSyncHandler.class + ".slurp failed2: " + uri + "\n" + e); - } + try { + Require req = (Require) r; + URI targetURI = + Path.of(new File(new URI(uri)).getParent(), req.getValue()) + .toRealPath(LinkOption.NOFOLLOW_LINKS) + .toUri(); + slurp2(targetURI.toString(), visited); + } catch (IOException | URISyntaxException e) { + clientLogger.logMessage( + TextDocumentSyncHandler.class + ".slurp failed2: " + uri + "\n" + e); + } } - }); - } + }); } - - // Create a list of CompletionItems depending on the context. - // A work in progress file may not parse, but we still want to have completion working, therefore we use a regex - // to find the closest keyword, and approximate the context. - public CompletableFuture, CompletionList>> completion(CompletionParams position) { - return CompletableFuture.supplyAsync(() -> { - KPos pos = new KPos(position.getPosition()); - List lci = new ArrayList<>(); - KTextDocument doc = files.get(position.getTextDocument().getUri()); - String context = doc.getContextAt(pos); - List allDi = slurp(position.getTextDocument().getUri()); - switch (context) { + } + + // Create a list of CompletionItems depending on the context. + // A work in progress file may not parse, but we still want to have completion working, therefore + // we use a regex + // to find the closest keyword, and approximate the context. + public CompletableFuture, CompletionList>> completion( + CompletionParams position) { + return CompletableFuture.supplyAsync( + () -> { + KPos pos = new KPos(position.getPosition()); + List lci = new ArrayList<>(); + KTextDocument doc = files.get(position.getTextDocument().getUri()); + String context = doc.getContextAt(pos); + List allDi = slurp(position.getTextDocument().getUri()); + switch (context) { case "" -> { - lci.add(getNewRequiresCompletion()); - lci.add(getNewModuleCompletion()); + lci.add(getNewRequiresCompletion()); + lci.add(getNewModuleCompletion()); } case "endmodule" -> lci.add(getNewModuleCompletion()); case "module" -> { - lci.add(getNewImportCompletion()); - lci.addAll(getNewSentenceCompletion()); + lci.add(getNewImportCompletion()); + lci.addAll(getNewSentenceCompletion()); } case "import", "imports" -> { - lci.add(getNewImportCompletion()); - lci.addAll(getNewSentenceCompletion()); - lci.addAll(getImportCompletion(allDi)); + lci.add(getNewImportCompletion()); + lci.addAll(getNewSentenceCompletion()); + lci.addAll(getImportCompletion(allDi)); } case "syntax" -> { - lci.addAll(getNewSentenceCompletion()); - lci.addAll(getSyntaxCompletion(allDi)); + lci.addAll(getNewSentenceCompletion()); + lci.addAll(getSyntaxCompletion(allDi)); } case "context", "rule", "configuration", "claim" -> { - lci.addAll(getNewSentenceCompletion()); - lci.addAll(getRuleCompletion(allDi)); + lci.addAll(getNewSentenceCompletion()); + lci.addAll(getRuleCompletion(allDi)); } - } - this.clientLogger.logMessage("Operation '" + "text/completion: " + position.getTextDocument().getUri() + " #pos: " - + pos.getLine() + " " + pos.getCharacter() + " context: " + context + " #: " + lci.size()); - - // TODO: add completion for attributes - return Either.forLeft(lci); + } + this.clientLogger.logMessage( + "Operation '" + + "text/completion: " + + position.getTextDocument().getUri() + + " #pos: " + + pos.getLine() + + " " + + pos.getCharacter() + + " context: " + + context + + " #: " + + lci.size()); + + // TODO: add completion for attributes + return Either.forLeft(lci); }); - } - - // ctrl+click - goto definition for requires, imports terms inside rules - public CompletableFuture, List>> definition(DefinitionParams params) { - findCacheFile(); - KPos pos = new KPos(params.getPosition()); - return CompletableFuture.supplyAsync(() -> { - this.clientLogger.logMessage("Operation '" + "text/definition: " + params.getTextDocument().getUri() + " #pos: " + pos.getLine() + " " + pos.getCharacter()); - List lls = new ArrayList<>(); - try { - List dis = files.get(params.getTextDocument().getUri()).dis; - for (DefinitionItem di : dis) { - if (di instanceof Require) { // goto required file - org.kframework.attributes.Location loc = getSafeLoc(di); - if (isPositionOverLocation(pos, loc)) { - Require req = (Require) di; - File f = new File(new URI(params.getTextDocument().getUri())); - URI targetURI = Path.of(f.getParent(), req.getValue()).toRealPath(LinkOption.NOFOLLOW_LINKS).toUri(); - lls.add(new LocationLink(targetURI.toString(), - new Range(new Position(0, 0), new Position(10, 0)), - new Range(new Position(0, 0), new Position(0, 0)), - loc2range(loc))); - break; - } - } else if (di instanceof Module m) { - for (ModuleItem mi : m.getItems()) { - org.kframework.attributes.Location loc = getSafeLoc(mi); - if (isPositionOverLocation(pos, loc)) { - if (mi instanceof Import imp) { // goto module definition - List allDi = slurp(params.getTextDocument().getUri()); - allDi.stream().filter(ddi -> ddi instanceof Module) - .map(ddi -> ((Module) ddi)) - .filter(m2 -> m2.getName().equals(imp.getName())) - .forEach(m3 -> lls.add(new LocationLink(URI.create(m3.getSource().source()).toString(), - loc2range(getSafeLoc(m3)), - loc2range(getSafeLoc(m3)), - loc2range(getSafeLoc(imp))))); - } else if (mi instanceof StringSentence ss) { // goto syntax of term inside rule - String suffix = ss.getType().equals(DefinitionParsing.configuration) ? "-" + RuleGrammarGenerator.CONFIG_CELLS : "-" + RuleGrammarGenerator.RULE_CELLS; - Optional> ch = caches.entrySet().stream().filter(elm -> elm.getKey().startsWith(m.getName() + suffix)).findFirst(); - if (ch.isPresent()) { - Map parsedSent = ch.get().getValue().cache(); - if (parsedSent.containsKey(ss.getContent())) { - Bubble b = new Bubble(ss.getType(), ss.getContent(), ss.getAttributes() - .add(org.kframework.attributes.Location.class, ss.getLocation()).add(Source.class, ss.getSource()) - .add(Att.CONTENT_START_LINE(), ss.getContentStartLine()).add(Att.CONTENT_START_COLUMN(), ss.getContentStartColumn())); - ParseCache.ParsedSentence parse = DefinitionParsing.updateLocation(parsedSent.get(ss.getContent()), b); - AtomicReference x = new AtomicReference<>(); - KViz.from(t -> { - if (isPositionOverLocation(pos, t.location().get())) - x.set(t); // find the deepest term that contains this position - return t; - }, "Find def in rule").apply(parse.parse()); - if (x.get() != null && x.get().att().get(org.kframework.definition.Production.class).source().isPresent()) { - org.kframework.definition.Production prd = x.get().att().get(org.kframework.definition.Production.class); - if (prd.source().isPresent()) // exclude generated productions like casts - lls.add(new LocationLink(URI.create(prd.source().get().source()).toString(), - loc2range(prd.location().get()), - loc2range(prd.location().get()), - loc2range(x.get().att().get(org.kframework.attributes.Location.class)))); - } else - clientLogger.logMessage("definition failed no origin for prod: " + (x.get() != null ? x.get().att().get(org.kframework.definition.Production.class) : null)); - - } - } else { - kls.languageClient.showMessage(new MessageParams(MessageType.Error, "No caches found for this sentence. 'Go to definition' inside rules is only available in workspace mode and requires a kompiled definition.")); - } - } - break; - } + } + + // ctrl+click - goto definition for requires, imports terms inside rules + public CompletableFuture< + Either, List>> + definition(DefinitionParams params) { + findCacheFile(); + KPos pos = new KPos(params.getPosition()); + return CompletableFuture.supplyAsync( + () -> { + this.clientLogger.logMessage( + "Operation '" + + "text/definition: " + + params.getTextDocument().getUri() + + " #pos: " + + pos.getLine() + + " " + + pos.getCharacter()); + List lls = new ArrayList<>(); + try { + List dis = files.get(params.getTextDocument().getUri()).dis; + for (DefinitionItem di : dis) { + if (di instanceof Require) { // goto required file + org.kframework.attributes.Location loc = getSafeLoc(di); + if (isPositionOverLocation(pos, loc)) { + Require req = (Require) di; + File f = new File(new URI(params.getTextDocument().getUri())); + URI targetURI = + Path.of(f.getParent(), req.getValue()) + .toRealPath(LinkOption.NOFOLLOW_LINKS) + .toUri(); + lls.add( + new LocationLink( + targetURI.toString(), + new Range(new Position(0, 0), new Position(10, 0)), + new Range(new Position(0, 0), new Position(0, 0)), + loc2range(loc))); + break; + } + } else if (di instanceof Module m) { + for (ModuleItem mi : m.getItems()) { + org.kframework.attributes.Location loc = getSafeLoc(mi); + if (isPositionOverLocation(pos, loc)) { + if (mi instanceof Import imp) { // goto module definition + List allDi = slurp(params.getTextDocument().getUri()); + allDi.stream() + .filter(ddi -> ddi instanceof Module) + .map(ddi -> ((Module) ddi)) + .filter(m2 -> m2.getName().equals(imp.getName())) + .forEach( + m3 -> + lls.add( + new LocationLink( + URI.create(m3.getSource().source()).toString(), + loc2range(getSafeLoc(m3)), + loc2range(getSafeLoc(m3)), + loc2range(getSafeLoc(imp))))); + } else if (mi instanceof StringSentence ss) { // goto syntax of term inside rule + String suffix = + ss.getType().equals(DefinitionParsing.configuration) + ? "-" + RuleGrammarGenerator.CONFIG_CELLS + : "-" + RuleGrammarGenerator.RULE_CELLS; + Optional> ch = + caches.entrySet().stream() + .filter(elm -> elm.getKey().startsWith(m.getName() + suffix)) + .findFirst(); + if (ch.isPresent()) { + Map parsedSent = + ch.get().getValue().cache(); + if (parsedSent.containsKey(ss.getContent())) { + Bubble b = + new Bubble( + ss.getType(), + ss.getContent(), + ss.getAttributes() + .add( + org.kframework.attributes.Location.class, + ss.getLocation()) + .add(Source.class, ss.getSource()) + .add(Att.CONTENT_START_LINE(), ss.getContentStartLine()) + .add(Att.CONTENT_START_COLUMN(), ss.getContentStartColumn())); + ParseCache.ParsedSentence parse = + DefinitionParsing.updateLocation(parsedSent.get(ss.getContent()), b); + AtomicReference x = new AtomicReference<>(); + KViz.from( + t -> { + if (isPositionOverLocation(pos, t.location().get())) + x.set(t); // find the deepest term that contains this position + return t; + }, + "Find def in rule") + .apply(parse.parse()); + if (x.get() != null + && x.get() + .att() + .get(org.kframework.definition.Production.class) + .source() + .isPresent()) { + org.kframework.definition.Production prd = + x.get().att().get(org.kframework.definition.Production.class); + if (prd.source() + .isPresent()) // exclude generated productions like casts + lls.add( + new LocationLink( + URI.create(prd.source().get().source()).toString(), + loc2range(prd.location().get()), + loc2range(prd.location().get()), + loc2range( + x.get() + .att() + .get(org.kframework.attributes.Location.class)))); + } else + clientLogger.logMessage( + "definition failed no origin for prod: " + + (x.get() != null + ? x.get() + .att() + .get(org.kframework.definition.Production.class) + : null)); } + } else { + kls.languageClient.showMessage( + new MessageParams( + MessageType.Error, + "No caches found for this sentence. 'Go to definition' inside rules" + + " is only available in workspace mode and requires a kompiled" + + " definition.")); + } } + break; + } } - } catch (URISyntaxException | IOException e) { - clientLogger.logMessage("definition failed: " + params.getTextDocument().getUri() + e); + } } + } catch (URISyntaxException | IOException e) { + clientLogger.logMessage("definition failed: " + params.getTextDocument().getUri() + e); + } - return Either.forRight(lls); + return Either.forRight(lls); }); - } - - // in case a node doesn't have a location information, return Location(0,0,0,0) - public static org.kframework.attributes.Location getSafeLoc(ASTNode node) { - return node.location().orElse(new org.kframework.attributes.Location(0,0,0,0)); - } - - // true if Position(l,c) is over Location(startL, startC, endL, endC). Expects Position to start from 1, just as Location - public static boolean isPositionOverLocation(KPos pos, org.kframework.attributes.Location loc) { - return (loc.startLine() < pos.getLine() || (loc.startLine() == pos.getLine() && loc.startColumn() <= pos.getCharacter())) && - (pos.getLine() < loc.endLine() || (pos.getLine() == loc.endLine() && pos.getCharacter() <= loc.endColumn())); - } - - // K starts counting lines and columns from 1 and LSP starts counting from 0 - public static Range loc2range(org.kframework.attributes.Location loc) { - return new Range(new Position(loc.startLine() - 1 , loc.startColumn() - 1), new Position(loc.endLine() - 1, loc.endColumn() - 1)); - } - - // previous diagnostics task. If it's still active, cancel it and run a newer, updated one - private final Map> latestDiagnosticScheduled = new HashMap<>(); - - public CompletableFuture diagnostic(DocumentDiagnosticParams params) { - findCacheFile(); - String uri = params.getTextDocument().getUri(); - if (latestDiagnosticScheduled.containsKey(uri) && !latestDiagnosticScheduled.get(uri).isDone()) - latestDiagnosticScheduled.get(uri).completeExceptionally(new Throwable("Cancelled diagnostic publisher")); - - Executor delayedExecutor = CompletableFuture.delayedExecutor(KTextDocumentService.DELAY_EXECUTION_MS, TimeUnit.MILLISECONDS); - CompletableFuture scheduledFuture = CompletableFuture.supplyAsync(() -> { - // make sure the out syntax is up to date - files.get(params.getTextDocument().getUri()).outerParse(); - List problems = files.get(params.getTextDocument().getUri()).problems; - // for each bubble in the current file - // search for a cached parsed version and collect reported errors - files.get(params.getTextDocument().getUri()).dis.stream().filter(di -> di instanceof Module).map(di -> (Module) di) - .forEach(m -> m.getItems().stream().filter(mi -> mi instanceof StringSentence).map(mi -> (StringSentence) mi) - .forEach(ss -> { - String suffix = ss.getType().equals(DefinitionParsing.configuration) ? "-" + RuleGrammarGenerator.CONFIG_CELLS : "-" + RuleGrammarGenerator.RULE_CELLS; - Optional> ch = caches.entrySet().stream().filter(elm -> elm.getKey().startsWith(m.getName() + suffix)).findFirst(); - if (ch.isPresent()) { - ParseCache parseCache = ch.get().getValue(); - Map parsedSent = parseCache.cache(); - if (parsedSent.containsKey(ss.getContent())) { - Bubble b = new Bubble(ss.getType(), ss.getContent(), ss.getAttributes() - .add(org.kframework.attributes.Location.class, ss.getLocation()).add(Source.class, ss.getSource()) - .add(Att.CONTENT_START_LINE(), ss.getContentStartLine()).add(Att.CONTENT_START_COLUMN(), ss.getContentStartColumn())); - ParseCache.ParsedSentence parse = DefinitionParsing.updateLocation(parsedSent.get(b.contents()), b); - parse.errors().forEach(err -> { - Diagnostic d = new Diagnostic(loc2range(err.exception.getLocation()), err.exception.getMessage(), DiagnosticSeverity.Error, "Inner Parser"); - problems.add(d); - }); - parse.warnings().forEach(err -> { - Diagnostic d = new Diagnostic(loc2range(err.exception.getLocation()), err.exception.getMessage(), DiagnosticSeverity.Warning, "Inner Parser"); - problems.add(d); - }); + } + + // in case a node doesn't have a location information, return Location(0,0,0,0) + public static org.kframework.attributes.Location getSafeLoc(ASTNode node) { + return node.location().orElse(new org.kframework.attributes.Location(0, 0, 0, 0)); + } + + // true if Position(l,c) is over Location(startL, startC, endL, endC). Expects Position to start + // from 1, just as Location + public static boolean isPositionOverLocation(KPos pos, org.kframework.attributes.Location loc) { + return (loc.startLine() < pos.getLine() + || (loc.startLine() == pos.getLine() && loc.startColumn() <= pos.getCharacter())) + && (pos.getLine() < loc.endLine() + || (pos.getLine() == loc.endLine() && pos.getCharacter() <= loc.endColumn())); + } + + // K starts counting lines and columns from 1 and LSP starts counting from 0 + public static Range loc2range(org.kframework.attributes.Location loc) { + return new Range( + new Position(loc.startLine() - 1, loc.startColumn() - 1), + new Position(loc.endLine() - 1, loc.endColumn() - 1)); + } + + // previous diagnostics task. If it's still active, cancel it and run a newer, updated one + private final Map> latestDiagnosticScheduled = + new HashMap<>(); + + public CompletableFuture diagnostic(DocumentDiagnosticParams params) { + findCacheFile(); + String uri = params.getTextDocument().getUri(); + if (latestDiagnosticScheduled.containsKey(uri) && !latestDiagnosticScheduled.get(uri).isDone()) + latestDiagnosticScheduled + .get(uri) + .completeExceptionally(new Throwable("Cancelled diagnostic publisher")); + + Executor delayedExecutor = + CompletableFuture.delayedExecutor( + KTextDocumentService.DELAY_EXECUTION_MS, TimeUnit.MILLISECONDS); + CompletableFuture scheduledFuture = + CompletableFuture.supplyAsync( + () -> { + // make sure the out syntax is up to date + files.get(params.getTextDocument().getUri()).outerParse(); + List problems = files.get(params.getTextDocument().getUri()).problems; + // for each bubble in the current file + // search for a cached parsed version and collect reported errors + files.get(params.getTextDocument().getUri()).dis.stream() + .filter(di -> di instanceof Module) + .map(di -> (Module) di) + .forEach( + m -> + m.getItems().stream() + .filter(mi -> mi instanceof StringSentence) + .map(mi -> (StringSentence) mi) + .forEach( + ss -> { + String suffix = + ss.getType().equals(DefinitionParsing.configuration) + ? "-" + RuleGrammarGenerator.CONFIG_CELLS + : "-" + RuleGrammarGenerator.RULE_CELLS; + Optional> ch = + caches.entrySet().stream() + .filter( + elm -> + elm.getKey().startsWith(m.getName() + suffix)) + .findFirst(); + if (ch.isPresent()) { + ParseCache parseCache = ch.get().getValue(); + Map parsedSent = + parseCache.cache(); + if (parsedSent.containsKey(ss.getContent())) { + Bubble b = + new Bubble( + ss.getType(), + ss.getContent(), + ss.getAttributes() + .add( + org.kframework.attributes.Location.class, + ss.getLocation()) + .add(Source.class, ss.getSource()) + .add( + Att.CONTENT_START_LINE(), + ss.getContentStartLine()) + .add( + Att.CONTENT_START_COLUMN(), + ss.getContentStartColumn())); + ParseCache.ParsedSentence parse = + DefinitionParsing.updateLocation( + parsedSent.get(b.contents()), b); + parse + .errors() + .forEach( + err -> { + Diagnostic d = + new Diagnostic( + loc2range(err.exception.getLocation()), + err.exception.getMessage(), + DiagnosticSeverity.Error, + "Inner Parser"); + problems.add(d); + }); + parse + .warnings() + .forEach( + err -> { + Diagnostic d = + new Diagnostic( + loc2range(err.exception.getLocation()), + err.exception.getMessage(), + DiagnosticSeverity.Warning, + "Inner Parser"); + problems.add(d); + }); + } } - } - })); - - DocumentDiagnosticReport report = new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(problems)); - this.clientLogger.logMessage("Operation '" + "text/diagnostics: " + params.getTextDocument().getUri() + " #problems: " + problems.size()); - return report; - }, delayedExecutor); - latestDiagnosticScheduled.put(uri, scheduledFuture); - return scheduledFuture; - } - - // find references of modules being used in imports and syntax used in rules - public CompletableFuture> references(ReferenceParams params) { - return CompletableFuture.supplyAsync(() -> { - KPos pos = new KPos(params.getPosition()); - List lloc = new ArrayList<>(); - - // look in the current file and find the term under KPos - List dis = files.get(params.getTextDocument().getUri()).dis; - for (DefinitionItem di : dis) { - org.kframework.attributes.Location loc = getSafeLoc(di); - if (isPositionOverLocation(pos, loc)) { - Module m = (Module) di; - // want to activate when over `module NAME` and nothing else but, - // we don't store the exact position for the module name so try to calculate it - String name = m.getName(); - org.kframework.attributes.Location nameLoc = new org.kframework.attributes.Location( - loc.startLine(), loc.startColumn(), loc.startLine(), loc.startColumn() + "module ".length() + name.length()); - - if (isPositionOverLocation(pos, nameLoc)) { - List allDi = files.values().stream() - .flatMap(doc -> doc.dis.stream()).collect(Collectors.toList()); - allDi.stream().filter(ddi -> ddi instanceof Module) - .map(ddi -> ((Module) ddi)) - .forEach(m3 -> m3.getItems().stream() + })); + + DocumentDiagnosticReport report = + new DocumentDiagnosticReport(new RelatedFullDocumentDiagnosticReport(problems)); + this.clientLogger.logMessage( + "Operation '" + + "text/diagnostics: " + + params.getTextDocument().getUri() + + " #problems: " + + problems.size()); + return report; + }, + delayedExecutor); + latestDiagnosticScheduled.put(uri, scheduledFuture); + return scheduledFuture; + } + + // find references of modules being used in imports and syntax used in rules + public CompletableFuture> references(ReferenceParams params) { + return CompletableFuture.supplyAsync( + () -> { + KPos pos = new KPos(params.getPosition()); + List lloc = new ArrayList<>(); + + // look in the current file and find the term under KPos + List dis = files.get(params.getTextDocument().getUri()).dis; + for (DefinitionItem di : dis) { + org.kframework.attributes.Location loc = getSafeLoc(di); + if (isPositionOverLocation(pos, loc)) { + Module m = (Module) di; + // want to activate when over `module NAME` and nothing else but, + // we don't store the exact position for the module name so try to calculate it + String name = m.getName(); + org.kframework.attributes.Location nameLoc = + new org.kframework.attributes.Location( + loc.startLine(), + loc.startColumn(), + loc.startLine(), + loc.startColumn() + "module ".length() + name.length()); + + if (isPositionOverLocation(pos, nameLoc)) { + List allDi = + files.values().stream() + .flatMap(doc -> doc.dis.stream()) + .collect(Collectors.toList()); + allDi.stream() + .filter(ddi -> ddi instanceof Module) + .map(ddi -> ((Module) ddi)) + .forEach( + m3 -> + m3.getItems().stream() .filter(mi -> mi instanceof Import) .map(mmi -> (Import) mmi) .filter(i -> i.getName().equals(name)) - .forEach(imp -> - lloc.add(new Location(URI.create(m3.getSource().source()).toString(), - loc2range(getSafeLoc(imp)))))); - } else { - // look for syntax references - AtomicReference xprd = new AtomicReference<>(); - m.getItems().stream().filter(a -> a instanceof Syntax) - .map(a -> ((Syntax)a)) - .forEach(b -> b.getPriorityBlocks().forEach(c -> c.getProductions().stream() - .filter(d -> isPositionOverLocation(pos, d.getLocation())).forEach(xprd::set))); - if (xprd.get() != null) { - Production prd = xprd.get(); - String psource = Path.of(URI.create(prd.source().get().source())).toString(); - org.kframework.attributes.Location ploc = prd.location().get(); - - if (caches.isEmpty()) - kls.languageClient.showMessage(new MessageParams(MessageType.Error, "No caches found. 'Find references' for productions is only available in workspace mode and requires a kompiled definition.")); - - // caches remember previous versions for quick access, so we may find more instances than there actually exist in the source file - // 1. for each cached sentence - // 2. find if it still exists in the source file and get its updated location - caches.forEach((mname, parseCache) -> { - String uri = Path.of(parseCache.module().att().get(org.kframework.attributes.Source.class).source()).toUri().toString(); - files.get(uri).dis.stream().filter(di2 -> di2 instanceof Module) - .map(di2 -> (Module) di2) - .filter(mm -> mname.startsWith((mm.getName()))) - .forEach(mm -> mm.getItems().stream().filter(mi -> mi instanceof StringSentence) - .map(mi -> (StringSentence) mi) - .forEach(ss -> { - if (parseCache.cache().containsKey(ss.getContent())) { - ParseCache.ParsedSentence ps = parseCache.cache().get(ss.getContent()); - if (ps.parse() != null) { - Bubble b = new Bubble(ss.getType(), ss.getContent(), ss.getAttributes() - .add(org.kframework.attributes.Location.class, ss.getLocation()).add(Source.class, ss.getSource()) - .add(Att.CONTENT_START_LINE(), ss.getContentStartLine()).add(Att.CONTENT_START_COLUMN(), ss.getContentStartColumn())); - ps = DefinitionParsing.updateLocation(ps, b); - KViz.from(t -> { - // the two production elements are not compatible so compare location information which should match - // if the definition wasn't modified - org.kframework.definition.Production dprd = t.att().get(org.kframework.definition.Production.class); - if (dprd.location().isPresent() && dprd.location().get().equals(ploc) && - dprd.source().isPresent() && dprd.source().get().source().equals(psource)) { - lloc.add(new Location(URI.create(t.source().get().source()).toString(), - loc2range(t.location().get()))); - } - return t; - }, "Find ref in rule").apply(ps.parse()); - } - } - }) - ); - }); - } - } - break; + .forEach( + imp -> + lloc.add( + new Location( + URI.create(m3.getSource().source()).toString(), + loc2range(getSafeLoc(imp)))))); + } else { + // look for syntax references + AtomicReference xprd = new AtomicReference<>(); + m.getItems().stream() + .filter(a -> a instanceof Syntax) + .map(a -> ((Syntax) a)) + .forEach( + b -> + b.getPriorityBlocks() + .forEach( + c -> + c.getProductions().stream() + .filter( + d -> isPositionOverLocation(pos, d.getLocation())) + .forEach(xprd::set))); + if (xprd.get() != null) { + Production prd = xprd.get(); + String psource = Path.of(URI.create(prd.source().get().source())).toString(); + org.kframework.attributes.Location ploc = prd.location().get(); + + if (caches.isEmpty()) + kls.languageClient.showMessage( + new MessageParams( + MessageType.Error, + "No caches found. 'Find references' for productions is only available" + + " in workspace mode and requires a kompiled definition.")); + + // caches remember previous versions for quick access, so we may find more + // instances than there actually exist in the source file + // 1. for each cached sentence + // 2. find if it still exists in the source file and get its updated location + caches.forEach( + (mname, parseCache) -> { + String uri = + Path.of( + parseCache + .module() + .att() + .get(org.kframework.attributes.Source.class) + .source()) + .toUri() + .toString(); + files.get(uri).dis.stream() + .filter(di2 -> di2 instanceof Module) + .map(di2 -> (Module) di2) + .filter(mm -> mname.startsWith((mm.getName()))) + .forEach( + mm -> + mm.getItems().stream() + .filter(mi -> mi instanceof StringSentence) + .map(mi -> (StringSentence) mi) + .forEach( + ss -> { + if (parseCache.cache().containsKey(ss.getContent())) { + ParseCache.ParsedSentence ps = + parseCache.cache().get(ss.getContent()); + if (ps.parse() != null) { + Bubble b = + new Bubble( + ss.getType(), + ss.getContent(), + ss.getAttributes() + .add( + org.kframework.attributes.Location + .class, + ss.getLocation()) + .add(Source.class, ss.getSource()) + .add( + Att.CONTENT_START_LINE(), + ss.getContentStartLine()) + .add( + Att.CONTENT_START_COLUMN(), + ss.getContentStartColumn())); + ps = DefinitionParsing.updateLocation(ps, b); + KViz.from( + t -> { + // the two production elements are not + // compatible so compare location + // information which should match + // if the definition wasn't modified + org.kframework.definition.Production + dprd = + t.att() + .get( + org.kframework + .definition + .Production.class); + if (dprd.location().isPresent() + && dprd.location() + .get() + .equals(ploc) + && dprd.source().isPresent() + && dprd.source() + .get() + .source() + .equals(psource)) { + lloc.add( + new Location( + URI.create( + t.source() + .get() + .source()) + .toString(), + loc2range( + t.location().get()))); + } + return t; + }, + "Find ref in rule") + .apply(ps.parse()); + } + } + })); + }); } + } + break; } - // TODO: check why sometimes this message is duplicated - clientLogger.logMessage("Operation '" + "text/references: " + params.getTextDocument().getUri() + " #pos: " - + pos.getLine() + " " + pos.getCharacter() + " found: " + lloc.size()); - - return lloc; + } + // TODO: check why sometimes this message is duplicated + clientLogger.logMessage( + "Operation '" + + "text/references: " + + params.getTextDocument().getUri() + + " #pos: " + + pos.getLine() + + " " + + pos.getCharacter() + + " found: " + + lloc.size()); + + return lloc; }); - } - - // Return the selection tree for a given position. This follows the AST as much as we have location information. - // The SelectionRange object is a recursive structure where the head is the smallest AST node next to the cursor - // and the deepest element is the entire file, the root of the document. - public CompletableFuture> selectionRange(SelectionRangeParams params) { - return CompletableFuture.supplyAsync(() -> { - List lloc = new ArrayList<>(); - - KTextDocument txtDoc = files.get(params.getTextDocument().getUri()); - List dis = txtDoc.dis; - txtDoc.getContextAt(new KPos(1, 1)); // warmup to avoid NPE - SelectionRange topsr = new SelectionRange(new Range(new Position(0,0), - new Position(txtDoc.lines[txtDoc.content.length()], txtDoc.columns[txtDoc.content.length()])), null); - for (Position ppos : params.getPositions()) { - KPos pos = new KPos(ppos); - for (DefinitionItem di : dis) { - if (isPositionOverLocation(pos, getSafeLoc(di))) { - if (di instanceof Module m) { - SelectionRange msr = new SelectionRange(loc2range(m.getLocation()), topsr); - for (ModuleItem mi : m.getItems()) { - if (isPositionOverLocation(pos, getSafeLoc(mi))) { - SelectionRange sentsr = new SelectionRange(loc2range(getSafeLoc(mi)), msr); - if (mi instanceof Syntax stx) { - for (PriorityBlock pb : stx.getPriorityBlocks()) { - SelectionRange pbsr = new SelectionRange(loc2range(getSafeLoc(pb)), sentsr); - for (Production prd : pb.getProductions()) - if (isPositionOverLocation(pos, getSafeLoc(prd))) - lloc.add(new SelectionRange(loc2range(getSafeLoc(prd)), pbsr)); - } - } else if (mi instanceof StringSentence ss) { // if we have caches, find the deepest term - String suffix = ss.getType().equals(DefinitionParsing.configuration) ? "-" + RuleGrammarGenerator.CONFIG_CELLS : "-" + RuleGrammarGenerator.RULE_CELLS; - Optional> ch = caches.entrySet().stream().filter(elm -> elm.getKey().startsWith(m.getName() + suffix)).findFirst(); - AtomicReference x = new AtomicReference<>(sentsr); - if (ch.isPresent()) { - Map parsedSent = ch.get().getValue().cache(); - if (parsedSent.containsKey(ss.getContent())) { - Bubble b = new Bubble(ss.getType(), ss.getContent(), ss.getAttributes() - .add(org.kframework.attributes.Location.class, ss.getLocation()).add(Source.class, ss.getSource()) - .add(Att.CONTENT_START_LINE(), ss.getContentStartLine()).add(Att.CONTENT_START_COLUMN(), ss.getContentStartColumn())); - ParseCache.ParsedSentence parse = DefinitionParsing.updateLocation(parsedSent.get(ss.getContent()), b); - KViz.from(t -> { - if (isPositionOverLocation(pos, t.location().get())) { - SelectionRange tsr = new SelectionRange(loc2range(t.location().get()), x.get()); - x.set(tsr); // find the deepest term that contains this position - } - return t; - }, "Find selectionRange in rule").apply(parse.parse()); - } - } - lloc.add(x.get()); - } else { // anything else that doesn't have a complex structure: Import, SyntaxPriorities... - lloc.add(new SelectionRange(loc2range(getSafeLoc(mi)), msr)); - } - } - } - } else { - lloc.add(new SelectionRange(loc2range(di.getLocation()), topsr)); + } + + // Return the selection tree for a given position. This follows the AST as much as we have + // location information. + // The SelectionRange object is a recursive structure where the head is the smallest AST node next + // to the cursor + // and the deepest element is the entire file, the root of the document. + public CompletableFuture> selectionRange(SelectionRangeParams params) { + return CompletableFuture.supplyAsync( + () -> { + List lloc = new ArrayList<>(); + + KTextDocument txtDoc = files.get(params.getTextDocument().getUri()); + List dis = txtDoc.dis; + txtDoc.getContextAt(new KPos(1, 1)); // warmup to avoid NPE + SelectionRange topsr = + new SelectionRange( + new Range( + new Position(0, 0), + new Position( + txtDoc.lines[txtDoc.content.length()], + txtDoc.columns[txtDoc.content.length()])), + null); + for (Position ppos : params.getPositions()) { + KPos pos = new KPos(ppos); + for (DefinitionItem di : dis) { + if (isPositionOverLocation(pos, getSafeLoc(di))) { + if (di instanceof Module m) { + SelectionRange msr = new SelectionRange(loc2range(m.getLocation()), topsr); + for (ModuleItem mi : m.getItems()) { + if (isPositionOverLocation(pos, getSafeLoc(mi))) { + SelectionRange sentsr = new SelectionRange(loc2range(getSafeLoc(mi)), msr); + if (mi instanceof Syntax stx) { + for (PriorityBlock pb : stx.getPriorityBlocks()) { + SelectionRange pbsr = + new SelectionRange(loc2range(getSafeLoc(pb)), sentsr); + for (Production prd : pb.getProductions()) + if (isPositionOverLocation(pos, getSafeLoc(prd))) + lloc.add(new SelectionRange(loc2range(getSafeLoc(prd)), pbsr)); + } + } else if (mi + instanceof + StringSentence + ss) { // if we have caches, find the deepest term + String suffix = + ss.getType().equals(DefinitionParsing.configuration) + ? "-" + RuleGrammarGenerator.CONFIG_CELLS + : "-" + RuleGrammarGenerator.RULE_CELLS; + Optional> ch = + caches.entrySet().stream() + .filter(elm -> elm.getKey().startsWith(m.getName() + suffix)) + .findFirst(); + AtomicReference x = new AtomicReference<>(sentsr); + if (ch.isPresent()) { + Map parsedSent = + ch.get().getValue().cache(); + if (parsedSent.containsKey(ss.getContent())) { + Bubble b = + new Bubble( + ss.getType(), + ss.getContent(), + ss.getAttributes() + .add( + org.kframework.attributes.Location.class, + ss.getLocation()) + .add(Source.class, ss.getSource()) + .add(Att.CONTENT_START_LINE(), ss.getContentStartLine()) + .add( + Att.CONTENT_START_COLUMN(), + ss.getContentStartColumn())); + ParseCache.ParsedSentence parse = + DefinitionParsing.updateLocation( + parsedSent.get(ss.getContent()), b); + KViz.from( + t -> { + if (isPositionOverLocation(pos, t.location().get())) { + SelectionRange tsr = + new SelectionRange( + loc2range(t.location().get()), x.get()); + x.set(tsr); // find the deepest term that contains this + // position + } + return t; + }, + "Find selectionRange in rule") + .apply(parse.parse()); + } } + lloc.add(x.get()); + } else { // anything else that doesn't have a complex structure: Import, + // SyntaxPriorities... + lloc.add(new SelectionRange(loc2range(getSafeLoc(mi)), msr)); + } } + } + } else { + lloc.add(new SelectionRange(loc2range(di.getLocation()), topsr)); } + } } - - String poss = params.getPositions().stream().map(pos -> new KPos(pos).toString()).collect(Collectors.joining(" ")); - clientLogger.logMessage("Operation '" + "text/selectionRange: " + params.getTextDocument().getUri() + " #poss: " - + poss + " rezDepth: " + lloc.stream().map(TextDocumentSyncHandler::getSelectionRangeDepth).collect(Collectors.toList())); - - return lloc; + } + + String poss = + params.getPositions().stream() + .map(pos -> new KPos(pos).toString()) + .collect(Collectors.joining(" ")); + clientLogger.logMessage( + "Operation '" + + "text/selectionRange: " + + params.getTextDocument().getUri() + + " #poss: " + + poss + + " rezDepth: " + + lloc.stream() + .map(TextDocumentSyncHandler::getSelectionRangeDepth) + .collect(Collectors.toList())); + + return lloc; }); - } + } - // for debug purposes, return the depth of the selection range - private static int getSelectionRangeDepth(SelectionRange sr) { - if (sr == null) return 0; - return 1 + getSelectionRangeDepth(sr.getParent()); - } + // for debug purposes, return the depth of the selection range + private static int getSelectionRangeDepth(SelectionRange sr) { + if (sr == null) return 0; + return 1 + getSelectionRangeDepth(sr.getParent()); + } } diff --git a/kernel/src/main/java/org/kframework/main/AbstractKModule.java b/kernel/src/main/java/org/kframework/main/AbstractKModule.java index 2a8dd35361b..60721518a0d 100644 --- a/kernel/src/main/java/org/kframework/main/AbstractKModule.java +++ b/kernel/src/main/java/org/kframework/main/AbstractKModule.java @@ -5,97 +5,97 @@ import com.google.inject.AbstractModule; import com.google.inject.Binder; import com.google.inject.Module; -import com.google.inject.TypeLiteral; -import com.google.inject.multibindings.MapBinder; import com.google.inject.multibindings.Multibinder; -import org.apache.commons.lang3.tuple.Pair; -import org.kframework.backend.PosterBackend; -import org.kframework.utils.inject.Builtins; -import org.kframework.utils.inject.Options; - import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.function.Supplier; +import org.apache.commons.lang3.tuple.Pair; +import org.kframework.backend.PosterBackend; +import org.kframework.utils.inject.Options; public abstract class AbstractKModule implements KModule { - public List>> posterTypes() { - return Collections.emptyList(); - } + public List>> posterTypes() { + return Collections.emptyList(); + } - public List, Boolean>> kompileOptions() { - return Collections.emptyList(); - } + public List, Boolean>> kompileOptions() { + return Collections.emptyList(); + } - public List, Boolean>> krunOptions() { - return Collections.emptyList(); - } + public List, Boolean>> krunOptions() { + return Collections.emptyList(); + } - public List, Boolean>> kproveOptions() { - return Collections.emptyList(); - } + public List, Boolean>> kproveOptions() { + return Collections.emptyList(); + } - protected void bindOptions(Supplier, Boolean>>> action, Binder binder) { - binder.requireAtInjectOnConstructors(); - Multibinder optionsBinder = Multibinder.newSetBinder(binder, Object.class, Options.class); - for (Pair, Boolean> option : action.get()) { - optionsBinder.addBinding().to(option.getKey()); - } + protected void bindOptions(Supplier, Boolean>>> action, Binder binder) { + binder.requireAtInjectOnConstructors(); + Multibinder optionsBinder = + Multibinder.newSetBinder(binder, Object.class, Options.class); + for (Pair, Boolean> option : action.get()) { + optionsBinder.addBinding().to(option.getKey()); } + } - @Override - public List getKompileModules() { - return Lists.newArrayList(new AbstractModule() { + @Override + public List getKompileModules() { + return Lists.newArrayList( + new AbstractModule() { - @Override - protected void configure() { - bindOptions(AbstractKModule.this::kompileOptions, binder()); - } + @Override + protected void configure() { + bindOptions(AbstractKModule.this::kompileOptions, binder()); + } }); - } - - @Override - public List getKastModules() { - return Lists.newArrayList(); - } - - @Override - public List getKRunModules() { - return Lists.newArrayList(new AbstractModule() { - - @Override - protected void configure() { - bindOptions(AbstractKModule.this::krunOptions, binder()); - } + } + + @Override + public List getKastModules() { + return Lists.newArrayList(); + } + + @Override + public List getKRunModules() { + return Lists.newArrayList( + new AbstractModule() { + + @Override + protected void configure() { + bindOptions(AbstractKModule.this::krunOptions, binder()); + } }); - } - - @Override - public List getKEqModules(List definitionSpecificModules) { - return Lists.newArrayList(); - } - - @Override - public List getDefinitionSpecificKEqModules() { - return Lists.newArrayList(new AbstractModule() { - - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - //bind backend implementations of tools to their interfaces - } + } + + @Override + public List getKEqModules(List definitionSpecificModules) { + return Lists.newArrayList(); + } + + @Override + public List getDefinitionSpecificKEqModules() { + return Lists.newArrayList( + new AbstractModule() { + + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + // bind backend implementations of tools to their interfaces + } }); - } + } - @Override - public List getKProveModules() { - return Lists.newArrayList(new AbstractModule() { + @Override + public List getKProveModules() { + return Lists.newArrayList( + new AbstractModule() { - @Override - protected void configure() { - bindOptions(AbstractKModule.this::kproveOptions, binder()); - } + @Override + protected void configure() { + bindOptions(AbstractKModule.this::kproveOptions, binder()); + } }); - } + } } diff --git a/kernel/src/main/java/org/kframework/main/AnnotatedByDefinitionModule.java b/kernel/src/main/java/org/kframework/main/AnnotatedByDefinitionModule.java index 2e88d9e5364..48b6800496c 100644 --- a/kernel/src/main/java/org/kframework/main/AnnotatedByDefinitionModule.java +++ b/kernel/src/main/java/org/kframework/main/AnnotatedByDefinitionModule.java @@ -8,30 +8,35 @@ import com.google.inject.spi.DefaultElementVisitor; import com.google.inject.spi.Element; import com.google.inject.spi.Elements; - import java.lang.annotation.Annotation; import java.util.List; import java.util.function.Function; public abstract class AnnotatedByDefinitionModule extends PrivateModule { - public void exposeBindings(List modules, Class cls, Function func) { - for (Element element : Elements.getElements(modules)) { - element.acceptVisitor(new DefaultElementVisitor() { - @Override - public Void visit(Binding binding) { - Key key = binding.getKey(); - if (key.getAnnotation() == null && key.getAnnotationType() == null) { - bind(key.getTypeLiteral()).annotatedWith(cls).to(key.getTypeLiteral()); - expose(key.getTypeLiteral()).annotatedWith(cls); - } else if (key.getAnnotationType() != null && !key.getAnnotationType().getPackage().equals(Package.getPackage("com.google.inject.multibindings"))) { - bind(key.getTypeLiteral()).annotatedWith(func.apply(key.getAnnotationType())).to(key); - expose(key.getTypeLiteral()).annotatedWith(func.apply(key.getAnnotationType())); - } - return null; - } - }); - } - modules.forEach(AnnotatedByDefinitionModule.this::install); + public void exposeBindings(List modules, Class cls, Function func) { + for (Element element : Elements.getElements(modules)) { + element.acceptVisitor( + new DefaultElementVisitor() { + @Override + public Void visit(Binding binding) { + Key key = binding.getKey(); + if (key.getAnnotation() == null && key.getAnnotationType() == null) { + bind(key.getTypeLiteral()).annotatedWith(cls).to(key.getTypeLiteral()); + expose(key.getTypeLiteral()).annotatedWith(cls); + } else if (key.getAnnotationType() != null + && !key.getAnnotationType() + .getPackage() + .equals(Package.getPackage("com.google.inject.multibindings"))) { + bind(key.getTypeLiteral()) + .annotatedWith(func.apply(key.getAnnotationType())) + .to(key); + expose(key.getTypeLiteral()).annotatedWith(func.apply(key.getAnnotationType())); + } + return null; + } + }); } + modules.forEach(AnnotatedByDefinitionModule.this::install); + } } diff --git a/kernel/src/main/java/org/kframework/main/BinaryToText.java b/kernel/src/main/java/org/kframework/main/BinaryToText.java index 3139e8ef914..7d15899491e 100644 --- a/kernel/src/main/java/org/kframework/main/BinaryToText.java +++ b/kernel/src/main/java/org/kframework/main/BinaryToText.java @@ -2,40 +2,38 @@ package org.kframework.main; import com.martiansoftware.nailgun.NGContext; -import org.kframework.kore.K; -import org.kframework.parser.binary.BinaryParser; -import org.kframework.unparser.ToKast; -import org.kframework.utils.file.FileUtil; - import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import org.kframework.kore.K; +import org.kframework.parser.binary.BinaryParser; +import org.kframework.unparser.ToKast; +import org.kframework.utils.file.FileUtil; -/** - * Created by dwightguth on 3/29/16. - */ +/** Created by dwightguth on 3/29/16. */ public class BinaryToText { - // main method used to decipher binary outputs - + // main method used to decipher binary outputs - public static void nailMain(NGContext context) throws IOException { - FileUtil files = new FileUtil(null, new File(context.getWorkingDirectory()),null,null,null); - File f = files.resolveWorkingDirectory(context.getArgs()[0]); - FileChannel channel = FileChannel.open(f.toPath()); - ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); - K result = BinaryParser.parse(buf); - ToKast.apply(result, new PrintStream(new FileOutputStream(files.resolveWorkingDirectory(context.getArgs()[1])))); - } + public static void nailMain(NGContext context) throws IOException { + FileUtil files = new FileUtil(null, new File(context.getWorkingDirectory()), null, null, null); + File f = files.resolveWorkingDirectory(context.getArgs()[0]); + FileChannel channel = FileChannel.open(f.toPath()); + ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + K result = BinaryParser.parse(buf); + ToKast.apply( + result, + new PrintStream(new FileOutputStream(files.resolveWorkingDirectory(context.getArgs()[1])))); + } - public static void main(String[] args) throws IOException { - File f = new File(args[0]); - FileChannel channel = FileChannel.open(f.toPath()); - ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); - K result = BinaryParser.parse(buf); - ToKast.apply(result, new PrintStream(new FileOutputStream(new File(args[1])))); - } + public static void main(String[] args) throws IOException { + File f = new File(args[0]); + FileChannel channel = FileChannel.open(f.toPath()); + ByteBuffer buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + K result = BinaryParser.parse(buf); + ToKast.apply(result, new PrintStream(new FileOutputStream(new File(args[1])))); + } } diff --git a/kernel/src/main/java/org/kframework/main/FrontEnd.java b/kernel/src/main/java/org/kframework/main/FrontEnd.java index 08e015488e0..58c7b6c9f74 100644 --- a/kernel/src/main/java/org/kframework/main/FrontEnd.java +++ b/kernel/src/main/java/org/kframework/main/FrontEnd.java @@ -15,69 +15,72 @@ public abstract class FrontEnd { - protected abstract int run(); + protected abstract int run(); - private final KExceptionManager kem; - protected final GlobalOptions globalOptions; - private final String usage; - private final JarInfo jarInfo; - private final Provider files; + private final KExceptionManager kem; + protected final GlobalOptions globalOptions; + private final String usage; + private final JarInfo jarInfo; + private final Provider files; - @Inject - public FrontEnd( - KExceptionManager kem, - GlobalOptions globalOptions, - String usage, - JarInfo jarInfo, - Provider files) { - this.kem = kem; - this.globalOptions = globalOptions; - this.usage = usage; - this.jarInfo = jarInfo; - this.files = files; - } + @Inject + public FrontEnd( + KExceptionManager kem, + GlobalOptions globalOptions, + String usage, + JarInfo jarInfo, + Provider files) { + this.kem = kem; + this.globalOptions = globalOptions; + this.usage = usage; + this.jarInfo = jarInfo; + this.files = files; + } - public int main() { - int retval; + public int main() { + int retval; + try { + if (globalOptions.help || globalOptions.helpHidden) { + System.out.print(usage); + retval = 0; + } else if (globalOptions.version) { + jarInfo.printVersionMessage(); + retval = 0; + } else { + if (globalOptions.timeout != null) { + new ExitOnTimeoutThread(globalOptions.timeout.toMillis()).start(); + } + if (globalOptions.shutdownWaitTime != null && !Main.isNailgun()) { + // Will interrupt the thread on Ctrl+C and allow the backend to terminate gracefully. + Runtime.getRuntime() + .addShutdownHook( + new Thread( + new InterrupterRunnable( + Thread.currentThread(), globalOptions.shutdownWaitTime.toMillis()))); + } try { - if (globalOptions.help || globalOptions.helpHidden) { - System.out.print(usage); - retval = 0; - } else if (globalOptions.version) { - jarInfo.printVersionMessage(); - retval = 0; - } else { - if (globalOptions.timeout != null) { - new ExitOnTimeoutThread(globalOptions.timeout.toMillis()).start(); - } - if (globalOptions.shutdownWaitTime != null && !Main.isNailgun()) { - //Will interrupt the thread on Ctrl+C and allow the backend to terminate gracefully. - Runtime.getRuntime().addShutdownHook(new Thread(new InterrupterRunnable(Thread.currentThread(), - globalOptions.shutdownWaitTime.toMillis()))); - } - try { - retval = run(); - } catch (ParameterException e) { - throw KEMException.criticalError(e.getMessage(), e); - } finally { - files.get().deleteTempDir(kem); - } - kem.print(); - } - } catch (KEMException e) { - // terminated with errors, so we need to return nonzero error code. - retval = KEMException.TERMINATED_WITH_ERRORS_EXIT_CODE; - if (globalOptions.debug()) { - e.printStackTrace(); - } else { - kem.registerThrown(e); - } - kem.print(); + retval = run(); + } catch (ParameterException e) { + throw KEMException.criticalError(e.getMessage(), e); + } finally { + files.get().deleteTempDir(kem); } - return retval; + kem.print(); + } + } catch (KEMException e) { + // terminated with errors, so we need to return nonzero error code. + retval = KEMException.TERMINATED_WITH_ERRORS_EXIT_CODE; + if (globalOptions.debug()) { + e.printStackTrace(); + } else { + kem.registerThrown(e); + } + kem.print(); } + return retval; + } - public static void printBootError(String message) { - System.err.println(StringUtil.splitLines(KException.criticalError(message).toString())); - } + public static void printBootError(String message) { + System.err.println(StringUtil.splitLines(KException.criticalError(message).toString())); + } } diff --git a/kernel/src/main/java/org/kframework/main/GlobalOptions.java b/kernel/src/main/java/org/kframework/main/GlobalOptions.java index a9558dabf7c..a234971cd55 100644 --- a/kernel/src/main/java/org/kframework/main/GlobalOptions.java +++ b/kernel/src/main/java/org/kframework/main/GlobalOptions.java @@ -2,152 +2,191 @@ package org.kframework.main; import com.beust.jcommander.Parameter; -import com.google.inject.Inject; -import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.errorsystem.KException.ExceptionType; -import org.kframework.utils.options.BaseEnumConverter; -import org.kframework.utils.options.DurationConverter; - import java.time.Duration; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Set; +import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.errorsystem.KException.ExceptionType; +import org.kframework.utils.options.BaseEnumConverter; +import org.kframework.utils.options.DurationConverter; public final class GlobalOptions { - public GlobalOptions() {} + public GlobalOptions() {} - public GlobalOptions(boolean debug, Warnings warnings, boolean verbose) { - this.debug = debug; - this.warnings = warnings; - this.verbose = verbose; - } + public GlobalOptions(boolean debug, Warnings warnings, boolean verbose) { + this.debug = debug; + this.warnings = warnings; + this.verbose = verbose; + } - public GlobalOptions(boolean debug, Warnings warnings, boolean verbose, boolean warnings2errors) { - this.debug = debug; - this.warnings = warnings; - this.verbose = verbose; - this.warnings2errors = warnings2errors; - } + public GlobalOptions(boolean debug, Warnings warnings, boolean verbose, boolean warnings2errors) { + this.debug = debug; + this.warnings = warnings; + this.verbose = verbose; + this.warnings2errors = warnings2errors; + } - public enum Warnings { - /** - * All warnings and errors - */ - ALL(EnumSet.allOf(ExceptionType.class)), + public enum Warnings { + /** All warnings and errors */ + ALL(EnumSet.allOf(ExceptionType.class)), - /** - * All warnings and errors except hidden warnings - */ - NORMAL(EnumSet.range(ExceptionType.ERROR, ExceptionType.FIRST_HIDDEN)), + /** All warnings and errors except hidden warnings */ + NORMAL(EnumSet.range(ExceptionType.ERROR, ExceptionType.FIRST_HIDDEN)), - /** - * No warnings, only errors - */ - NONE(EnumSet.of(ExceptionType.ERROR)); + /** No warnings, only errors */ + NONE(EnumSet.of(ExceptionType.ERROR)); - Warnings(Set types) { - typesIncluded = types; - } - private final Set typesIncluded; - - public Set getTypesIncluded() { return typesIncluded; } + Warnings(Set types) { + typesIncluded = types; } - public static class WarningsConverter extends BaseEnumConverter { - - public WarningsConverter(String optionName) { - super(optionName); - } + private final Set typesIncluded; - @Override - public Class enumClass() { - return Warnings.class; - } + public Set getTypesIncluded() { + return typesIncluded; } + } - public static class ExceptionTypeConverter extends BaseEnumConverter { - - public ExceptionTypeConverter(String optionName) { - super(optionName); - } + public static class WarningsConverter extends BaseEnumConverter { - @Override - public Class enumClass() { - return ExceptionType.class; - } + public WarningsConverter(String optionName) { + super(optionName); } - private Set typesIncluded; - - public boolean includesExceptionType(ExceptionType e) { - Set t = typesIncluded; - if (t == null) { - t = new HashSet<>(warnings.getTypesIncluded()); - t.addAll(enableWarnings); - t.removeAll(disableWarnings); - if (!t.contains(ExceptionType.ERROR)) { - throw KEMException.criticalError("Cannot disable errors with -Wno."); - } - typesIncluded = t; - } - return t.contains(e); + @Override + public Class enumClass() { + return Warnings.class; } + } - @Parameter(names={"--help", "-h"}, description="Print this help message", help = true) - public boolean help = false; + public static class ExceptionTypeConverter extends BaseEnumConverter { - @Parameter(names={"--help-hidden", "-hh"}, description="Print advanced options help message", help = true) - public boolean helpHidden = false; - - @Parameter(names="--version", description="Print version information") - public boolean version = false; - - @Parameter(names={"--verbose", "-v"}, description="Print verbose output messages") - public boolean verbose = false; - - @Parameter(names="--debug", description="Print debugging output messages and error stack traces") - private boolean debug = false; - - @Parameter(names="--debug-warnings", description="Print debugging output messages and error/warning stack traces") - public boolean debugWarnings = false; - - @Parameter(names={"--warnings", "-w"}, converter=WarningsConverter.class, description="Warning level. Values: [all|normal|none]", descriptionKey = "level") - public Warnings warnings = Warnings.NORMAL; - - @Parameter(names="-W", description="Enable specific warning categories. Values: [non-exhaustive-match|undeleted-temp-dir|missing-hook-java|missing-syntax-module|invalid-exit-code|deprecated-backend|invalid-config-var|future-error|unused-var|proof-lint|useless-rule|unresolved-function-symbol|malformed-markdown|invalidated-cache|unused-symbol|removed-anywhere]", descriptionKey = "warning", converter=ExceptionTypeConverter.class) - public List enableWarnings = Collections.emptyList(); - - @Parameter(names="-Wno", description="Disable specific warning categories.", descriptionKey = "warning", converter=ExceptionTypeConverter.class) - public List disableWarnings = Collections.emptyList(); - - @Parameter(names={"--warnings-to-errors", "-w2e"}, description="Convert warnings to errors.") - public boolean warnings2errors = false; - - @Parameter(names = {"--shutdown-wait-time"}, converter = DurationConverter.class, - description = "If option is set, a shutdown hook will be registered " + - "that, once invoked, interrupts the main thread and waits its termination. " + - "The wait time is the argument of this option, in format like 10ms/10s/10m/10h. " + - "Useful if K is interrupted by Ctrl+C, because it allows the backend to detect " + - "interruption and print diagnostics information. Currently interruption detection is implemented " + - "in Java Backend. If K is invoked from KServer (e.g. Nailgun), the option is ignored.", descriptionKey = "time", hidden = true) - public Duration shutdownWaitTime; - - @Parameter(names = {"--timeout"}, converter = DurationConverter.class, - description = "If option is set, timeout for this process, in format like 10ms/10s/10m/10h. " + - "Using this option is preferred compared to bash timeout command, which has known limitations " + - "when invoked from scripts.", descriptionKey = "duration", hidden = true) - public Duration timeout; - - @Parameter(names={"--no-exc-wrap"}, description="Do not wrap exception messages to 80 chars. Keep long lines.", hidden = true) - public boolean noExcWrap = false; - - public boolean debug() { - return debug || debugWarnings; + public ExceptionTypeConverter(String optionName) { + super(optionName); } - @Parameter(names={"--temp-dir"}, description="Put temp files in this location. Default is /tmp/.-xxx", descriptionKey = "path") - public String tempDir = null; + @Override + public Class enumClass() { + return ExceptionType.class; + } + } + + private Set typesIncluded; + + public boolean includesExceptionType(ExceptionType e) { + Set t = typesIncluded; + if (t == null) { + t = new HashSet<>(warnings.getTypesIncluded()); + t.addAll(enableWarnings); + t.removeAll(disableWarnings); + if (!t.contains(ExceptionType.ERROR)) { + throw KEMException.criticalError("Cannot disable errors with -Wno."); + } + typesIncluded = t; + } + return t.contains(e); + } + + @Parameter( + names = {"--help", "-h"}, + description = "Print this help message", + help = true) + public boolean help = false; + + @Parameter( + names = {"--help-hidden", "-hh"}, + description = "Print advanced options help message", + help = true) + public boolean helpHidden = false; + + @Parameter(names = "--version", description = "Print version information") + public boolean version = false; + + @Parameter( + names = {"--verbose", "-v"}, + description = "Print verbose output messages") + public boolean verbose = false; + + @Parameter( + names = "--debug", + description = "Print debugging output messages and error stack traces") + private boolean debug = false; + + @Parameter( + names = "--debug-warnings", + description = "Print debugging output messages and error/warning stack traces") + public boolean debugWarnings = false; + + @Parameter( + names = {"--warnings", "-w"}, + converter = WarningsConverter.class, + description = "Warning level. Values: [all|normal|none]", + descriptionKey = "level") + public Warnings warnings = Warnings.NORMAL; + + @Parameter( + names = "-W", + description = + "Enable specific warning categories. Values:" + + " [non-exhaustive-match|undeleted-temp-dir|missing-hook-java|missing-syntax-module|invalid-exit-code|deprecated-backend|invalid-config-var|future-error|unused-var|proof-lint|useless-rule|unresolved-function-symbol|malformed-markdown|invalidated-cache|unused-symbol|removed-anywhere]", + descriptionKey = "warning", + converter = ExceptionTypeConverter.class) + public List enableWarnings = Collections.emptyList(); + + @Parameter( + names = "-Wno", + description = "Disable specific warning categories.", + descriptionKey = "warning", + converter = ExceptionTypeConverter.class) + public List disableWarnings = Collections.emptyList(); + + @Parameter( + names = {"--warnings-to-errors", "-w2e"}, + description = "Convert warnings to errors.") + public boolean warnings2errors = false; + + @Parameter( + names = {"--shutdown-wait-time"}, + converter = DurationConverter.class, + description = + "If option is set, a shutdown hook will be registered that, once invoked, interrupts the" + + " main thread and waits its termination. The wait time is the argument of this" + + " option, in format like 10ms/10s/10m/10h. Useful if K is interrupted by Ctrl+C," + + " because it allows the backend to detect interruption and print diagnostics" + + " information. Currently interruption detection is implemented in Java Backend. If" + + " K is invoked from KServer (e.g. Nailgun), the option is ignored.", + descriptionKey = "time", + hidden = true) + public Duration shutdownWaitTime; + + @Parameter( + names = {"--timeout"}, + converter = DurationConverter.class, + description = + "If option is set, timeout for this process, in format like 10ms/10s/10m/10h. Using this" + + " option is preferred compared to bash timeout command, which has known limitations" + + " when invoked from scripts.", + descriptionKey = "duration", + hidden = true) + public Duration timeout; + + @Parameter( + names = {"--no-exc-wrap"}, + description = "Do not wrap exception messages to 80 chars. Keep long lines.", + hidden = true) + public boolean noExcWrap = false; + + public boolean debug() { + return debug || debugWarnings; + } + + @Parameter( + names = {"--temp-dir"}, + description = "Put temp files in this location. Default is /tmp/.-xxx", + descriptionKey = "path") + public String tempDir = null; } diff --git a/kernel/src/main/java/org/kframework/main/JavaVersion.java b/kernel/src/main/java/org/kframework/main/JavaVersion.java index eea02fb9943..8ef3445e881 100644 --- a/kernel/src/main/java/org/kframework/main/JavaVersion.java +++ b/kernel/src/main/java/org/kframework/main/JavaVersion.java @@ -1,13 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.main; -/** - * Created by dwightguth on 9/23/15. - */ +/** Created by dwightguth on 9/23/15. */ public class JavaVersion { - public static void main(String[] args) { - System.err.println("java version \"" + System.getProperty("java.version") + "\""); - System.err.println(System.getProperty("sun.arch.data.model") + "-Bit"); - } + public static void main(String[] args) { + System.err.println("java version \"" + System.getProperty("java.version") + "\""); + System.err.println(System.getProperty("sun.arch.data.model") + "-Bit"); + } } diff --git a/kernel/src/main/java/org/kframework/main/KModule.java b/kernel/src/main/java/org/kframework/main/KModule.java index 324779e53de..2f279c22726 100644 --- a/kernel/src/main/java/org/kframework/main/KModule.java +++ b/kernel/src/main/java/org/kframework/main/KModule.java @@ -2,15 +2,19 @@ package org.kframework.main; import com.google.inject.Module; - import java.util.List; public interface KModule { - List getKompileModules(); - List getKastModules(); - List getKRunModules(); - List getKEqModules(List definitionSpecificModules); - List getDefinitionSpecificKEqModules(); - List getKProveModules(); + List getKompileModules(); + + List getKastModules(); + + List getKRunModules(); + + List getKEqModules(List definitionSpecificModules); + + List getDefinitionSpecificKEqModules(); + + List getKProveModules(); } diff --git a/kernel/src/main/java/org/kframework/main/Main.java b/kernel/src/main/java/org/kframework/main/Main.java index adbdb5b2f3a..4313d59412e 100644 --- a/kernel/src/main/java/org/kframework/main/Main.java +++ b/kernel/src/main/java/org/kframework/main/Main.java @@ -12,6 +12,14 @@ import com.google.inject.name.Named; import com.google.inject.spi.Message; import com.martiansoftware.nailgun.NGContext; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; +import java.util.concurrent.ExecutionException; import org.fusesource.jansi.AnsiConsole; import org.kframework.kast.KastFrontEnd; import org.kframework.kdep.KDepFrontEnd; @@ -26,184 +34,191 @@ import org.kframework.utils.inject.SimpleScope; import org.kframework.utils.inject.StartTime; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; -import java.util.concurrent.ExecutionException; - public record Main( - Provider kem, - Provider frontEnd, - @Named("requestScope") SimpleScope requestScope -) { - - /** - * @param args - * - the running arguments for the K3 tool. First argument must be one of the following: kompile|kast|krun. - * @throws IOException when loadDefinition fails - */ - public static void main(String[] args) { - isNailgun = false; - long startTime = System.nanoTime(); - AnsiConsole.systemInstall(); - if (args.length >= 1) { - - String[] args2 = Arrays.copyOfRange(args, 1, args.length); - Injector injector = getInjector(args[0]); - int result = injector.getInstance(Main.class).runApplication(args[0], args2, new File("."), System.getenv(), startTime); - AnsiConsole.systemUninstall(); - System.exit(result); - } - AnsiConsole.systemUninstall(); - invalidJarArguments(); + Provider kem, + Provider frontEnd, + @Named("requestScope") SimpleScope requestScope) { + + /** + * @param args - the running arguments for the K3 tool. First argument must be one of the + * following: kompile|kast|krun. + * @throws IOException when loadDefinition fails + */ + public static void main(String[] args) { + isNailgun = false; + long startTime = System.nanoTime(); + AnsiConsole.systemInstall(); + if (args.length >= 1) { + + String[] args2 = Arrays.copyOfRange(args, 1, args.length); + Injector injector = getInjector(args[0]); + int result = + injector + .getInstance(Main.class) + .runApplication(args[0], args2, new File("."), System.getenv(), startTime); + AnsiConsole.systemUninstall(); + System.exit(result); } + AnsiConsole.systemUninstall(); + invalidJarArguments(); + } - private static volatile boolean isNailgun; + private static volatile boolean isNailgun; - public static boolean isNailgun() { - return isNailgun; - } + public static boolean isNailgun() { + return isNailgun; + } - private static NGContext context = null; + private static NGContext context = null; - public static void exit(int exitCode) { - if (context != null) { - context.exit(exitCode); - } else { - System.exit(exitCode); - } + public static void exit(int exitCode) { + if (context != null) { + context.exit(exitCode); + } else { + System.exit(exitCode); } + } - public static void nailMain(NGContext context) { - long startTime = System.nanoTime(); - KServerFrontEnd kserver = KServerFrontEnd.instance(); - if (!kserver.isLocal()) { - context.assertLoopbackClient(); - } - isNailgun = true; - Main.context = context; - if (context.getArgs().length >= 1) { - String[] args2 = Arrays.copyOfRange(context.getArgs(), 1, context.getArgs().length); - int result = kserver.run(context.getArgs()[0], args2, new File(context.getWorkingDirectory()), (Map) context.getEnv(), startTime); - exit(result); - return; - } - invalidJarArguments(); + public static void nailMain(NGContext context) { + long startTime = System.nanoTime(); + KServerFrontEnd kserver = KServerFrontEnd.instance(); + if (!kserver.isLocal()) { + context.assertLoopbackClient(); } - - @Inject - public Main {} - - public SimpleScope getRequestScope() { - return requestScope; + isNailgun = true; + Main.context = context; + if (context.getArgs().length >= 1) { + String[] args2 = Arrays.copyOfRange(context.getArgs(), 1, context.getArgs().length); + int result = + kserver.run( + context.getArgs()[0], + args2, + new File(context.getWorkingDirectory()), + (Map) context.getEnv(), + startTime); + exit(result); + return; } - - public int runApplication(String tool, String[] args, File workingDir, Map env, long startTime) { - try { - requestScope.enter(); - seedInjector(requestScope, tool, args, workingDir, env, startTime); - return runApplication(); - } finally { - requestScope.exit(); - } + invalidJarArguments(); + } + + @Inject + public Main {} + + public SimpleScope getRequestScope() { + return requestScope; + } + + public int runApplication( + String tool, String[] args, File workingDir, Map env, long startTime) { + try { + requestScope.enter(); + seedInjector(requestScope, tool, args, workingDir, env, startTime); + return runApplication(); + } finally { + requestScope.exit(); } - - public int runApplication() { - KExceptionManager kem = this.kem.get(); - kem.installForUncaughtExceptions(); - try { - return frontEnd.get().main(); - } catch (ProvisionException e) { - for (Message m : e.getErrorMessages()) { - if (!(m.getCause() instanceof KEMException ex)) { - throw e; - } else { - kem.registerThrown(ex); - } - } - kem.print(); - return 1; + } + + public int runApplication() { + KExceptionManager kem = this.kem.get(); + kem.installForUncaughtExceptions(); + try { + return frontEnd.get().main(); + } catch (ProvisionException e) { + for (Message m : e.getErrorMessages()) { + if (!(m.getCause() instanceof KEMException ex)) { + throw e; + } else { + kem.registerThrown(ex); } + } + kem.print(); + return 1; } - - public static void seedInjector(SimpleScope scope, String tool, String[] args, File workingDir, - Map env, long startTime) { - scope.seed(Key.get(File.class, WorkingDir.class), workingDir); - scope.seed(Key.get(new TypeLiteral>() {}, Environment.class), env); - scope.seed(Key.get(String[].class, Options.class), args); - scope.seed(Key.get(Long.class, StartTime.class), startTime); + } + + public static void seedInjector( + SimpleScope scope, + String tool, + String[] args, + File workingDir, + Map env, + long startTime) { + scope.seed(Key.get(File.class, WorkingDir.class), workingDir); + scope.seed(Key.get(new TypeLiteral>() {}, Environment.class), env); + scope.seed(Key.get(String[].class, Options.class), args); + scope.seed(Key.get(Long.class, StartTime.class), startTime); + } + + public static Injector getInjector(String tool) { + ServiceLoader kLoader = ServiceLoader.load(KModule.class); + List kModules = new ArrayList<>(); + for (KModule m : kLoader) { + kModules.add(m); } - public static Injector getInjector(String tool) { - ServiceLoader kLoader = ServiceLoader.load(KModule.class); - List kModules = new ArrayList<>(); - for (KModule m : kLoader) { - kModules.add(m); - } + List modules = new ArrayList<>(); - List modules = new ArrayList<>(); - - switch (tool) { - case "-klsp": - try { - org.kframework.lsp.KLanguageServerLauncher.startServer(System.in, System.out); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - break; - case "-kserver": - modules.addAll(KServerFrontEnd.getModules()); - break; - case "-kompile": - modules.addAll(KompileFrontEnd.getModules()); - for (KModule kModule : kModules) { - List ms = kModule.getKompileModules(); - if (ms != null) { - modules.addAll(ms); - } - } - break; - case "-kast": - modules.addAll(KastFrontEnd.getModules()); - for (KModule kModule : kModules) { - List ms = kModule.getKastModules(); - if (ms != null) { - modules.addAll(ms); - } - } - break; - case "-kdep": - modules = KDepFrontEnd.getModules(); - break; - case "-k-compile-search-pattern": - modules = KSearchPatternFrontEnd.getModules(); - break; - case "-kprove": - modules.addAll(org.kframework.kprove.KProveFrontEnd.getModules()); - for (KModule kModule : kModules) { - List ms = kModule.getKProveModules(); - if (ms != null) { - modules.addAll(ms); - } - } - break; - default: - invalidJarArguments(); - throw new AssertionError("unreachable"); + switch (tool) { + case "-klsp": + try { + org.kframework.lsp.KLanguageServerLauncher.startServer(System.in, System.out); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); } - if (modules.size() == 0) { - //boot error, we should have printed it already - Main.exit(1); + break; + case "-kserver": + modules.addAll(KServerFrontEnd.getModules()); + break; + case "-kompile": + modules.addAll(KompileFrontEnd.getModules()); + for (KModule kModule : kModules) { + List ms = kModule.getKompileModules(); + if (ms != null) { + modules.addAll(ms); + } } - return Guice.createInjector(modules); + break; + case "-kast": + modules.addAll(KastFrontEnd.getModules()); + for (KModule kModule : kModules) { + List ms = kModule.getKastModules(); + if (ms != null) { + modules.addAll(ms); + } + } + break; + case "-kdep": + modules = KDepFrontEnd.getModules(); + break; + case "-k-compile-search-pattern": + modules = KSearchPatternFrontEnd.getModules(); + break; + case "-kprove": + modules.addAll(org.kframework.kprove.KProveFrontEnd.getModules()); + for (KModule kModule : kModules) { + List ms = kModule.getKProveModules(); + if (ms != null) { + modules.addAll(ms); + } + } + break; + default: + invalidJarArguments(); + throw new AssertionError("unreachable"); } - - private static void invalidJarArguments() { - System.err.println("The first argument of the K java compiler not recognized. Try -kompile, -kast, -kdep, -kserver, or -klsp."); - Main.exit(1); + if (modules.size() == 0) { + // boot error, we should have printed it already + Main.exit(1); } + return Guice.createInjector(modules); + } + + private static void invalidJarArguments() { + System.err.println( + "The first argument of the K java compiler not recognized. Try -kompile, -kast, -kdep," + + " -kserver, or -klsp."); + Main.exit(1); + } } diff --git a/kernel/src/main/java/org/kframework/main/Tool.java b/kernel/src/main/java/org/kframework/main/Tool.java index 1cd161e379b..b9f74af6159 100644 --- a/kernel/src/main/java/org/kframework/main/Tool.java +++ b/kernel/src/main/java/org/kframework/main/Tool.java @@ -2,5 +2,10 @@ package org.kframework.main; public enum Tool { - KOMPILE, KAST, KPROVE, KSEARCHPATTERN, KSERVER, KDEP + KOMPILE, + KAST, + KPROVE, + KSEARCHPATTERN, + KSERVER, + KDEP } diff --git a/kernel/src/main/java/org/kframework/parser/InputModes.java b/kernel/src/main/java/org/kframework/parser/InputModes.java index f545727b9c5..930ba8efd0d 100644 --- a/kernel/src/main/java/org/kframework/parser/InputModes.java +++ b/kernel/src/main/java/org/kframework/parser/InputModes.java @@ -2,5 +2,10 @@ package org.kframework.parser; public enum InputModes { - PROGRAM, BINARY, JSON, KAST, KORE, RULE + PROGRAM, + BINARY, + JSON, + KAST, + KORE, + RULE } diff --git a/kernel/src/main/java/org/kframework/parser/KRead.java b/kernel/src/main/java/org/kframework/parser/KRead.java index 63dbcab708e..1b0e9ae148c 100644 --- a/kernel/src/main/java/org/kframework/parser/KRead.java +++ b/kernel/src/main/java/org/kframework/parser/KRead.java @@ -1,6 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonReader; import org.kframework.attributes.Source; import org.kframework.definition.Module; import org.kframework.kompile.CompiledDefinition; @@ -20,139 +30,181 @@ import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.List; -import java.util.ArrayList; -import java.util.Arrays; - -import javax.json.Json; -import javax.json.JsonObject; -import javax.json.JsonReader; - public record KRead( - KExceptionManager kem, - FileUtil files, - InputModes input, - GlobalOptions globalOptions -) { - - public String showTokens(Module mod, CompiledDefinition def, String stringToParse, Source source) { - return def.showTokens(mod, files, stringToParse, source); - } - - public K prettyRead(Module mod, Sort sort, String startSymbolLocation, CompiledDefinition def, Source source, String stringToParse, boolean partialParseDebug) { - return prettyRead(mod, sort, startSymbolLocation, def, source, stringToParse, this.input, partialParseDebug); - } - - public K prettyRead(Module mod, Sort sort, String startSymbolLocation, CompiledDefinition def, Source source, String stringToParse, InputModes inputMode, boolean partialParseDebug) { - return switch (inputMode) { - case BINARY, JSON, KAST -> deserialize(stringToParse, inputMode, source); - case KORE -> new KoreParser(mod.sortAttributesFor()).parseString(stringToParse); - case PROGRAM -> def.parseSingleTerm(mod, sort, startSymbolLocation, kem, files, stringToParse, source, partialParseDebug); - case RULE -> throw KEMException.internalError("Should have been handled directly by the kast front end: " + inputMode); - default -> throw KEMException.criticalError("Unsupported input mode: " + inputMode); - }; - } - - public void createBisonParser(Module mod, Sort sort, File outputFile, boolean glr, String bisonFile, long stackDepth, boolean library) { - Stopwatch sw = new Stopwatch(globalOptions); - try (ParseInModule parseInModule = RuleGrammarGenerator.getCombinedGrammar(mod, true, false, true, false, files)) { - try (Scanner scanner = parseInModule.getScanner(kem.options)) { - File scannerFile = files.resolveTemp("scanner.l"); - File scanHdr = files.resolveTemp("scanner.h"); - File parserFile = files.resolveTemp("parser.y"); - scanner.writeStandaloneScanner(scannerFile); - KSyntax2Bison.writeParser(parseInModule.getParsingModule(), parseInModule.getDisambiguationModule(), scanner, sort, parserFile, glr, stackDepth, kem); - int exit = files.getProcessBuilder() - .directory(files.resolveTemp(".")) - .command("flex", "--header-file=" + scanHdr.getAbsolutePath(), "-w", scannerFile.getAbsolutePath()) - .inheritIO() - .start() - .waitFor(); - if (exit != 0) { - throw KEMException.internalError("flex returned nonzero exit code: " + exit + "\n"); - } - exit = files.getProcessBuilder() - .directory(files.resolveTemp(".")) - .command("bison", "-d", "-Wno-other", "-Wno-conflicts-sr", "-Wno-conflicts-rr", parserFile.getAbsolutePath()) - .inheritIO() - .start() - .waitFor(); - if (exit != 0) { - throw KEMException.internalError("bison returned nonzero exit code: " + exit + "\n"); - } - List command = new ArrayList<>(Arrays.asList( - Scanner.COMPILER, - "-DK_BISON_PARSER_SORT=" + sort.name(), - files.resolveKInclude("cparser/main.c").getAbsolutePath(), - files.resolveTemp("lex.yy.c").getAbsolutePath(), - files.resolveTemp("parser.tab.c").getAbsolutePath(), - "-iquote", files.resolveTemp(".").getAbsolutePath(), - "-iquote", files.resolveKInclude("cparser").getAbsolutePath(), - "-o", outputFile.getAbsolutePath())); - - if (library) { - command.addAll(OS.current().getSharedLibraryCompilerFlags()); - } else { - command.add("-DK_BISON_PARSER_MAIN"); - } + KExceptionManager kem, FileUtil files, InputModes input, GlobalOptions globalOptions) { + + public String showTokens( + Module mod, CompiledDefinition def, String stringToParse, Source source) { + return def.showTokens(mod, files, stringToParse, source); + } + + public K prettyRead( + Module mod, + Sort sort, + String startSymbolLocation, + CompiledDefinition def, + Source source, + String stringToParse, + boolean partialParseDebug) { + return prettyRead( + mod, sort, startSymbolLocation, def, source, stringToParse, this.input, partialParseDebug); + } + + public K prettyRead( + Module mod, + Sort sort, + String startSymbolLocation, + CompiledDefinition def, + Source source, + String stringToParse, + InputModes inputMode, + boolean partialParseDebug) { + return switch (inputMode) { + case BINARY, JSON, KAST -> deserialize(stringToParse, inputMode, source); + case KORE -> new KoreParser(mod.sortAttributesFor()).parseString(stringToParse); + case PROGRAM -> def.parseSingleTerm( + mod, sort, startSymbolLocation, kem, files, stringToParse, source, partialParseDebug); + case RULE -> throw KEMException.internalError( + "Should have been handled directly by the kast front end: " + inputMode); + default -> throw KEMException.criticalError("Unsupported input mode: " + inputMode); + }; + } + + public void createBisonParser( + Module mod, + Sort sort, + File outputFile, + boolean glr, + String bisonFile, + long stackDepth, + boolean library) { + Stopwatch sw = new Stopwatch(globalOptions); + try (ParseInModule parseInModule = + RuleGrammarGenerator.getCombinedGrammar(mod, true, false, true, false, files)) { + try (Scanner scanner = parseInModule.getScanner(kem.options)) { + File scannerFile = files.resolveTemp("scanner.l"); + File scanHdr = files.resolveTemp("scanner.h"); + File parserFile = files.resolveTemp("parser.y"); + scanner.writeStandaloneScanner(scannerFile); + KSyntax2Bison.writeParser( + parseInModule.getParsingModule(), + parseInModule.getDisambiguationModule(), + scanner, + sort, + parserFile, + glr, + stackDepth, + kem); + int exit = + files + .getProcessBuilder() + .directory(files.resolveTemp(".")) + .command( + "flex", + "--header-file=" + scanHdr.getAbsolutePath(), + "-w", + scannerFile.getAbsolutePath()) + .inheritIO() + .start() + .waitFor(); + if (exit != 0) { + throw KEMException.internalError("flex returned nonzero exit code: " + exit + "\n"); + } + exit = + files + .getProcessBuilder() + .directory(files.resolveTemp(".")) + .command( + "bison", + "-d", + "-Wno-other", + "-Wno-conflicts-sr", + "-Wno-conflicts-rr", + parserFile.getAbsolutePath()) + .inheritIO() + .start() + .waitFor(); + if (exit != 0) { + throw KEMException.internalError("bison returned nonzero exit code: " + exit + "\n"); + } + List command = + new ArrayList<>( + Arrays.asList( + Scanner.COMPILER, + "-DK_BISON_PARSER_SORT=" + sort.name(), + files.resolveKInclude("cparser/main.c").getAbsolutePath(), + files.resolveTemp("lex.yy.c").getAbsolutePath(), + files.resolveTemp("parser.tab.c").getAbsolutePath(), + "-iquote", + files.resolveTemp(".").getAbsolutePath(), + "-iquote", + files.resolveKInclude("cparser").getAbsolutePath(), + "-o", + outputFile.getAbsolutePath())); + + if (library) { + command.addAll(OS.current().getSharedLibraryCompilerFlags()); + } else { + command.add("-DK_BISON_PARSER_MAIN"); + } - if (bisonFile != null) { - command.add(files.resolveWorkingDirectory(bisonFile).getAbsolutePath()); - } - exit = files.getProcessBuilder() - .command(command.toArray(new String[0])) - .inheritIO() - .start() - .waitFor(); - if (exit != 0) { - throw KEMException.internalError(Scanner.COMPILER + " returned nonzero exit code: " + exit + "\n"); - } - } catch(IOException | InterruptedException e) { - throw KEMException.internalError("Failed to execute process.", e); - } + if (bisonFile != null) { + command.add(files.resolveWorkingDirectory(bisonFile).getAbsolutePath()); + } + exit = + files + .getProcessBuilder() + .command(command.toArray(new String[0])) + .inheritIO() + .start() + .waitFor(); + if (exit != 0) { + throw KEMException.internalError( + Scanner.COMPILER + " returned nonzero exit code: " + exit + "\n"); } - sw.printIntermediate(" New Bison parser: " + mod.name()); + } catch (IOException | InterruptedException e) { + throw KEMException.internalError("Failed to execute process.", e); + } } - - public K deserialize(String stringToParse, Source source) { - return deserialize(stringToParse, this.input, source); + sw.printIntermediate(" New Bison parser: " + mod.name()); + } + + public K deserialize(String stringToParse, Source source) { + return deserialize(stringToParse, this.input, source); + } + + public static K deserialize(String stringToParse, InputModes inputMode, Source source) { + return switch (inputMode) { + case BINARY -> BinaryParser.parse(stringToParse.getBytes()); + case JSON -> JsonParser.parse(stringToParse); + case KAST -> KastParser.parse(stringToParse, source); + default -> throw KEMException.criticalError( + "Unsupported input mode for deserialization: " + inputMode); + }; + } + + public static K autoDeserialize(byte[] kast, Source source) { + if (BinaryParser.isBinaryKast(kast)) return BinaryParser.parse(kast); + + InputStream input = new ByteArrayInputStream(kast); + int c; + try { + while (Character.isWhitespace(c = input.read())) + ; + } catch (IOException e) { + throw KEMException.criticalError("Could not read output from parser: ", e); } - public static K deserialize(String stringToParse, InputModes inputMode, Source source) { - return switch (inputMode) { - case BINARY -> BinaryParser.parse(stringToParse.getBytes()); - case JSON -> JsonParser.parse(stringToParse); - case KAST -> KastParser.parse(stringToParse, source); - default -> throw KEMException.criticalError("Unsupported input mode for deserialization: " + inputMode); - }; + if (c == '{') { + JsonReader reader = Json.createReader(new ByteArrayInputStream(kast)); + JsonObject data = reader.readObject(); + return JsonParser.parseJson(data); } - public static K autoDeserialize(byte[] kast, Source source) { - if (BinaryParser.isBinaryKast(kast)) - return BinaryParser.parse(kast); - - InputStream input = new ByteArrayInputStream(kast); - int c; - try { - while (Character.isWhitespace(c = input.read())); - } catch (IOException e) { - throw KEMException.criticalError("Could not read output from parser: ", e); - } - - if ( c == '{' ) { - JsonReader reader = Json.createReader(new ByteArrayInputStream(kast)); - JsonObject data = reader.readObject(); - return JsonParser.parseJson(data); - } - - try { - return KastParser.parse(new String(kast), source); - } catch ( KEMException e ) { - throw KEMException.criticalError("Could not read input: " + source.source()); - } + try { + return KastParser.parse(new String(kast), source); + } catch (KEMException e) { + throw KEMException.criticalError("Could not read input: " + source.source()); } + } } diff --git a/kernel/src/main/java/org/kframework/parser/ParserUtils.java b/kernel/src/main/java/org/kframework/parser/ParserUtils.java index 711997864f4..4349231eff4 100644 --- a/kernel/src/main/java/org/kframework/parser/ParserUtils.java +++ b/kernel/src/main/java/org/kframework/parser/ParserUtils.java @@ -1,7 +1,23 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Streams; +import java.io.File; +import java.io.IOException; +import java.nio.file.LinkOption; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.kframework.attributes.Att; import org.kframework.attributes.Location; @@ -29,321 +45,402 @@ import org.kframework.utils.options.OuterParsingOptions; import scala.Tuple4; -import java.io.File; -import java.io.IOException; -import java.nio.file.LinkOption; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - -/** - * A few functions that are a common pattern when calling the new parser. - */ +/** A few functions that are a common pattern when calling the new parser. */ public class ParserUtils { - private final KExceptionManager kem; - private final GlobalOptions options; - private final FileUtil files; - private final ExtractFencedKCodeFromMarkdown mdExtractor; - - public ParserUtils(FileUtil files, KExceptionManager kem) { - this(files, kem, new GlobalOptions(), new OuterParsingOptions()); + private final KExceptionManager kem; + private final GlobalOptions options; + private final FileUtil files; + private final ExtractFencedKCodeFromMarkdown mdExtractor; + + public ParserUtils(FileUtil files, KExceptionManager kem) { + this(files, kem, new GlobalOptions(), new OuterParsingOptions()); + } + + public ParserUtils( + FileUtil files, + KExceptionManager kem, + GlobalOptions options, + OuterParsingOptions outerParsingOptions) { + this.kem = kem; + this.options = options; + this.files = files; + this.mdExtractor = new ExtractFencedKCodeFromMarkdown(this.kem, outerParsingOptions.mdSelector); + } + + /** + * Takes a definition in e-kore textual format and a main module name, and returns the KORE + * representation of that module. Current implementation uses JavaCC and goes through KIL. + * + * @param definitionText textual representation of the modules. + * @param mainModule main module name. + * @return KORE representation of the main module. + */ + public static Module parseMainModuleOuterSyntax( + String definitionText, Source source, String mainModule) { + Definition def = new Definition(); + def.setItems(Outer.parse(source, definitionText, null)); + def.setMainModule(mainModule); + def.setMainSyntaxModule(mainModule); + + ProcessGroupAttributes.apply(def); + Context context = new Context(); + new CollectProductionsVisitor(context).visit(def); + + KILtoKORE kilToKore = new KILtoKORE(context, false, false); + return kilToKore.apply(def).getModule(mainModule).get(); + } + + public List slurp( + String definitionText, + Source source, + File currentDirectory, + List lookupDirectories, + Set requiredFiles) { + try { + source = + Source.apply(Paths.get(source.source()).toRealPath(LinkOption.NOFOLLOW_LINKS).toString()); + } catch (IOException e) { + // if it fails, just keep the original option } - - public ParserUtils(FileUtil files, KExceptionManager kem, GlobalOptions options, OuterParsingOptions outerParsingOptions) { - this.kem = kem; - this.options = options; - this.files = files; - this.mdExtractor = new ExtractFencedKCodeFromMarkdown(this.kem, outerParsingOptions.mdSelector); + if (source.source().endsWith(".md")) { + definitionText = mdExtractor.extract(definitionText, source); + if (options.debug()) { // save .k files in temp directory + String fname = new File(source.source()).getName(); + fname = fname.substring(0, fname.lastIndexOf(".md")) + ".k"; + File file = files.resolveTemp(".md2.k/" + fname); + // if multiple files exists with the same name, append an index + // and add a comment at the end of the file with the full path + // Note: the comment is not sent to the parser + int index = 2; + while (file.exists()) file = files.resolveTemp(".md2.k/" + fname + "_" + index++); + FileUtil.save(file, definitionText + "\n// " + source.source() + "\n"); + } } + List items = Outer.parse(source, definitionText, null); + items.stream() + .filter((d) -> d instanceof org.kframework.kil.Module) + .forEach((m) -> ProcessGroupAttributes.apply((org.kframework.kil.Module) m)); - /** - * Takes a definition in e-kore textual format and a main module name, and returns the KORE - * representation of that module. Current implementation uses JavaCC and goes through KIL. - * - * @param definitionText textual representation of the modules. - * @param mainModule main module name. - * @return KORE representation of the main module. - */ - public static Module parseMainModuleOuterSyntax(String definitionText, Source source, String mainModule) { - Definition def = new Definition(); - def.setItems(Outer.parse(source, definitionText, null)); - def.setMainModule(mainModule); - def.setMainSyntaxModule(mainModule); - - ProcessGroupAttributes.apply(def); - Context context = new Context(); - new CollectProductionsVisitor(context).visit(def); - - KILtoKORE kilToKore = new KILtoKORE(context, false, false); - return kilToKore.apply(def).getModule(mainModule).get(); + if (options.verbose) { + System.out.println("Importing: " + source); } - - public List slurp( - String definitionText, - Source source, - File currentDirectory, - List lookupDirectories, - Set requiredFiles) { - try { - source = Source.apply(Paths.get(source.source()).toRealPath(LinkOption.NOFOLLOW_LINKS).toString()); - } catch (IOException e) { - // if it fails, just keep the original option + List results = new ArrayList<>(); + + for (DefinitionItem di : items) { + if (di instanceof org.kframework.kil.Module) results.add((org.kframework.kil.Module) di); + else if (di instanceof Require) { + // resolve location of the new file + + String definitionFileName = ((Require) di).getValue(); + + if (definitionFileName.equals("ffi.k") + || definitionFileName.equals("json.k") + || definitionFileName.equals("rat.k") + || definitionFileName.equals("substitution.k") + || definitionFileName.equals("domains.k") + || definitionFileName.equals("kast.k")) { + kem.registerCompilerWarning( + ExceptionType.FUTURE_ERROR, + "Requiring a K file in the K builtin directory via " + + "a deprecated filename. Please replace \"" + + definitionFileName + + "\" with \"" + + definitionFileName.substring(0, definitionFileName.length() - 2) + + ".md\".", + di); + definitionFileName = + definitionFileName.substring(0, definitionFileName.length() - 2) + ".md"; } - if (source.source().endsWith(".md")) { - definitionText = mdExtractor.extract(definitionText, source); - if (options.debug()) { // save .k files in temp directory - String fname = new File(source.source()).getName(); - fname = fname.substring(0, fname.lastIndexOf(".md")) + ".k"; - File file = files.resolveTemp(".md2.k/" + fname); - // if multiple files exists with the same name, append an index - // and add a comment at the end of the file with the full path - // Note: the comment is not sent to the parser - int index = 2; - while (file.exists()) - file = files.resolveTemp(".md2.k/" + fname + "_" + index++); - FileUtil.save(file, definitionText + "\n// " + source.source() + "\n"); - } - } - List items = Outer.parse(source, definitionText, null); - items.stream().filter((d) -> d instanceof org.kframework.kil.Module) - .forEach((m) -> ProcessGroupAttributes.apply((org.kframework.kil.Module) m)); - if (options.verbose) { - System.out.println("Importing: " + source); - } - List results = new ArrayList<>(); - - for (DefinitionItem di : items) { - if (di instanceof org.kframework.kil.Module) - results.add((org.kframework.kil.Module) di); - else if (di instanceof Require) { - // resolve location of the new file - - String definitionFileName = ((Require) di).getValue(); - - if (definitionFileName.equals("ffi.k") || definitionFileName.equals("json.k") || - definitionFileName.equals("rat.k") || definitionFileName.equals("substitution.k") || - definitionFileName.equals("domains.k") || definitionFileName.equals("kast.k")) { - kem.registerCompilerWarning(ExceptionType.FUTURE_ERROR, - "Requiring a K file in the K builtin directory via " + - "a deprecated filename. Please replace \"" + definitionFileName + - "\" with \"" + definitionFileName.substring(0, definitionFileName.length() - 2) + ".md\".", di); - definitionFileName = definitionFileName.substring(0, definitionFileName.length() - 2) + ".md"; - } - - String finalDefinitionFile = definitionFileName; - - ArrayList allLookupDirectories = new ArrayList<>(lookupDirectories); - allLookupDirectories.add(1, currentDirectory); //after builtin directory but before anything else - - Optional definitionFile = allLookupDirectories.stream() - .map(lookupDirectory -> { - if (new File(finalDefinitionFile).isAbsolute()) { - return new File(finalDefinitionFile); - } else { - return new File(lookupDirectory, finalDefinitionFile); - } - }) - .filter(file -> file.exists()).findFirst(); - - if (definitionFile.isPresent()) { - File canonical = definitionFile.get().getAbsoluteFile(); - try { - canonical = definitionFile.get().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).toFile(); - } catch (IOException e) { - // if it fails, just keep the original option - } - if (!requiredFiles.contains(canonical)) { - requiredFiles.add(canonical); - results.addAll(slurp(loadDefinitionText(canonical), - Source.apply(canonical.getAbsolutePath()), - canonical.getParentFile(), - lookupDirectories, requiredFiles)); - } - } else { - throw KEMException.criticalError("Could not find file: " + - finalDefinitionFile + "\nLookup directories:" + allLookupDirectories, di); - } - } + String finalDefinitionFile = definitionFileName; + + ArrayList allLookupDirectories = new ArrayList<>(lookupDirectories); + allLookupDirectories.add( + 1, currentDirectory); // after builtin directory but before anything else + + Optional definitionFile = + allLookupDirectories.stream() + .map( + lookupDirectory -> { + if (new File(finalDefinitionFile).isAbsolute()) { + return new File(finalDefinitionFile); + } else { + return new File(lookupDirectory, finalDefinitionFile); + } + }) + .filter(file -> file.exists()) + .findFirst(); + + if (definitionFile.isPresent()) { + File canonical = definitionFile.get().getAbsoluteFile(); + try { + canonical = + definitionFile.get().toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).toFile(); + } catch (IOException e) { + // if it fails, just keep the original option + } + if (!requiredFiles.contains(canonical)) { + requiredFiles.add(canonical); + results.addAll( + slurp( + loadDefinitionText(canonical), + Source.apply(canonical.getAbsolutePath()), + canonical.getParentFile(), + lookupDirectories, + requiredFiles)); + } + } else { + throw KEMException.criticalError( + "Could not find file: " + + finalDefinitionFile + + "\nLookup directories:" + + allLookupDirectories, + di); } - return results; + } } - - private String loadDefinitionText(File definitionFile) { - try { - return FileUtils.readFileToString(files.resolveWorkingDirectory(definitionFile)); - } catch (IOException e) { - throw KEMException.criticalError(e.getMessage(), e); - } + return results; + } + + private String loadDefinitionText(File definitionFile) { + try { + return FileUtils.readFileToString(files.resolveWorkingDirectory(definitionFile)); + } catch (IOException e) { + throw KEMException.criticalError(e.getMessage(), e); } - - public Set loadModules( - Set previousModules, - Context context, - String definitionText, - Source source, - File currentDirectory, - List lookupDirectories, - Set requiredFiles, - boolean preprocess, - boolean leftAssoc) { - - List kilModules = - slurp(definitionText, source, currentDirectory, lookupDirectories, requiredFiles); - - Definition def = new Definition(); - def.setItems((List) (Object) kilModules); - - ProcessGroupAttributes.apply(def); - new CollectProductionsVisitor(context).visit(def); - - // Tuple4 of moduleName, Source, Location, digest - Map>> groupedModules = - Streams.concat( - previousModules.stream().map(m -> Tuple4.apply(m.name(), m.att().get(Att.SOURCE(), Source.class), - m.att().get(Att.LOCATION(), Location.class), m.att().get(Att.DIGEST()))), - kilModules.stream().map(m -> Tuple4.apply(m.getName(), m.getSource(), m.getLocation(), m.digest()))) - // make sure we have unique modules (double requires), and preserve order - .collect(Collectors.toCollection(LinkedHashSet::new)).stream() - .collect(Collectors.groupingBy(Tuple4::_1)); - - List duplicateModules = groupedModules - .entrySet().stream() - .filter(e -> e.getValue().size() > 1) - .map(Map.Entry::getKey) - .collect(Collectors.toList()); - - int errors = 0; - for (String moduleName : duplicateModules) { - Tuple4 firstMod = groupedModules.get(moduleName).get(0); - Tuple4 secondMod = groupedModules.get(moduleName).get(1); - // give an error message only if we have - // the same module name found in different filenames (path doesn't matter) - // the location is different or - // the hashes of the pretty printed contents are different. - if (!Paths.get(firstMod._2().source()).getFileName().equals(Paths.get(secondMod._2().source()).getFileName()) - || !firstMod._3().equals(secondMod._3()) - || !firstMod._4().equals(secondMod._4())) { - String extraMDWarning = ""; - if (Paths.get(secondMod._2().source()).getFileName().toString().endsWith(".md")) - extraMDWarning = ". This can happen if --md-selector differs for kompile and kprove"; - KEMException ex = KEMException.outerParserError("Module " + moduleName + " differs from previous declaration at " - + firstMod._2() + " and " + firstMod._3() + extraMDWarning, secondMod._2(), secondMod._3()); - errors++; - kem.addKException(ex.getKException()); - } - } - - if (errors > 0) { - throw KEMException.outerParserError("Had " + errors + " outer parsing errors."); - } - - if (preprocess) { - System.out.println(def); - } - - KILtoKORE kilToKore = new KILtoKORE(context, false, leftAssoc); - // Order modules by name to stabilize the error message for circular imports - java.util.List flatModules = kilModules.stream().map(kilToKore::toFlatModule).sorted(Comparator.comparing(FlatModule::name)).collect(Collectors.toList()); - Set finalModules = mutable(FlatModule.toModules(immutable(flatModules), immutable(previousModules))); - - Set result = new HashSet<>(); - ModuleTransformer applySynonyms = ModuleTransformer.fromSentenceTransformer(new ApplySynonyms()::apply, "Apply sort synonyms"); - for (Module mod : finalModules) { - result.add(applySynonyms.apply(mod)); - } - return result; + } + + public Set loadModules( + Set previousModules, + Context context, + String definitionText, + Source source, + File currentDirectory, + List lookupDirectories, + Set requiredFiles, + boolean preprocess, + boolean leftAssoc) { + + List kilModules = + slurp(definitionText, source, currentDirectory, lookupDirectories, requiredFiles); + + Definition def = new Definition(); + def.setItems((List) (Object) kilModules); + + ProcessGroupAttributes.apply(def); + new CollectProductionsVisitor(context).visit(def); + + // Tuple4 of moduleName, Source, Location, digest + Map>> groupedModules = + Streams.concat( + previousModules.stream() + .map( + m -> + Tuple4.apply( + m.name(), + m.att().get(Att.SOURCE(), Source.class), + m.att().get(Att.LOCATION(), Location.class), + m.att().get(Att.DIGEST()))), + kilModules.stream() + .map( + m -> Tuple4.apply(m.getName(), m.getSource(), m.getLocation(), m.digest()))) + // make sure we have unique modules (double requires), and preserve order + .collect(Collectors.toCollection(LinkedHashSet::new)) + .stream() + .collect(Collectors.groupingBy(Tuple4::_1)); + + List duplicateModules = + groupedModules.entrySet().stream() + .filter(e -> e.getValue().size() > 1) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + + int errors = 0; + for (String moduleName : duplicateModules) { + Tuple4 firstMod = groupedModules.get(moduleName).get(0); + Tuple4 secondMod = groupedModules.get(moduleName).get(1); + // give an error message only if we have + // the same module name found in different filenames (path doesn't matter) + // the location is different or + // the hashes of the pretty printed contents are different. + if (!Paths.get(firstMod._2().source()) + .getFileName() + .equals(Paths.get(secondMod._2().source()).getFileName()) + || !firstMod._3().equals(secondMod._3()) + || !firstMod._4().equals(secondMod._4())) { + String extraMDWarning = ""; + if (Paths.get(secondMod._2().source()).getFileName().toString().endsWith(".md")) + extraMDWarning = ". This can happen if --md-selector differs for kompile and kprove"; + KEMException ex = + KEMException.outerParserError( + "Module " + + moduleName + + " differs from previous declaration at " + + firstMod._2() + + " and " + + firstMod._3() + + extraMDWarning, + secondMod._2(), + secondMod._3()); + errors++; + kem.addKException(ex.getKException()); + } } - public org.kframework.definition.Definition loadDefinition( - String mainModuleName, - Set previousModules, - String definitionText, - Source source, - File currentDirectory, - List lookupDirectories, - boolean preprocess, - boolean leftAssoc) { - Set modules = loadModules(previousModules, new Context(), definitionText, source, currentDirectory, lookupDirectories, new HashSet<>(), preprocess, leftAssoc); - Set allModules = new HashSet<>(modules); - allModules.addAll(previousModules); - Module mainModule = getMainModule(mainModuleName, allModules); - return org.kframework.definition.Definition.apply(mainModule, immutable(allModules), Att.empty()); + if (errors > 0) { + throw KEMException.outerParserError("Had " + errors + " outer parsing errors."); } - public org.kframework.definition.Definition loadDefinition( - String mainModuleName, - String syntaxModuleName, - String definitionText, - File source, - File currentDirectory, - List lookupDirectories, - boolean autoImportDomains, - boolean preprocess, - boolean leftAssoc) { - String strSource = source.getAbsolutePath(); - try { - strSource = source.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).toString(); - } catch (IOException e) { - // if it fails, just keep the original option - } - return loadDefinition(mainModuleName, syntaxModuleName, definitionText, - Source.apply(strSource), - currentDirectory, lookupDirectories, autoImportDomains, preprocess, leftAssoc); + if (preprocess) { + System.out.println(def); } - public org.kframework.definition.Definition loadDefinition( - String mainModuleName, - String syntaxModuleName, - String definitionText, - Source source, - File currentDirectory, - List lookupDirectories, - boolean autoImportDomains, - boolean preprocess, - boolean leftAssoc) { - Set previousModules = new HashSet<>(); - Set requiredFiles = new HashSet<>(); - Context context = new Context(); - if (autoImportDomains) - previousModules.addAll(loadModules(new HashSet<>(), context, Kompile.REQUIRE_PRELUDE_K, Source.apply("Auto imported prelude"), currentDirectory, lookupDirectories, requiredFiles, preprocess, leftAssoc)); - Set modules = loadModules(previousModules, context, definitionText, source, currentDirectory, lookupDirectories, requiredFiles, preprocess, leftAssoc); - if (preprocess) { - Main.exit(0); - } - modules.addAll(previousModules); // add the previous modules, since load modules is not additive - Module mainModule = getMainModule(mainModuleName, modules); - Optional opt; - opt = modules.stream().filter(m -> m.name().equals(syntaxModuleName)).findFirst(); - Module syntaxModule; - if (!opt.isPresent()) { - kem.registerCompilerWarning(ExceptionType.MISSING_SYNTAX_MODULE, "Could not find main syntax module with name " + syntaxModuleName - + " in definition. Use --syntax-module to specify one. Using " + mainModuleName + " as default."); - syntaxModule = mainModule; - } else { - syntaxModule = opt.get(); - } - - return org.kframework.definition.Definition.apply(mainModule, immutable(modules), Att().add(Att.SYNTAX_MODULE(), syntaxModule.name())); + KILtoKORE kilToKore = new KILtoKORE(context, false, leftAssoc); + // Order modules by name to stabilize the error message for circular imports + java.util.List flatModules = + kilModules.stream() + .map(kilToKore::toFlatModule) + .sorted(Comparator.comparing(FlatModule::name)) + .collect(Collectors.toList()); + Set finalModules = + mutable(FlatModule.toModules(immutable(flatModules), immutable(previousModules))); + + Set result = new HashSet<>(); + ModuleTransformer applySynonyms = + ModuleTransformer.fromSentenceTransformer( + new ApplySynonyms()::apply, "Apply sort synonyms"); + for (Module mod : finalModules) { + result.add(applySynonyms.apply(mod)); + } + return result; + } + + public org.kframework.definition.Definition loadDefinition( + String mainModuleName, + Set previousModules, + String definitionText, + Source source, + File currentDirectory, + List lookupDirectories, + boolean preprocess, + boolean leftAssoc) { + Set modules = + loadModules( + previousModules, + new Context(), + definitionText, + source, + currentDirectory, + lookupDirectories, + new HashSet<>(), + preprocess, + leftAssoc); + Set allModules = new HashSet<>(modules); + allModules.addAll(previousModules); + Module mainModule = getMainModule(mainModuleName, allModules); + return org.kframework.definition.Definition.apply( + mainModule, immutable(allModules), Att.empty()); + } + + public org.kframework.definition.Definition loadDefinition( + String mainModuleName, + String syntaxModuleName, + String definitionText, + File source, + File currentDirectory, + List lookupDirectories, + boolean autoImportDomains, + boolean preprocess, + boolean leftAssoc) { + String strSource = source.getAbsolutePath(); + try { + strSource = source.toPath().toRealPath(LinkOption.NOFOLLOW_LINKS).toString(); + } catch (IOException e) { + // if it fails, just keep the original option + } + return loadDefinition( + mainModuleName, + syntaxModuleName, + definitionText, + Source.apply(strSource), + currentDirectory, + lookupDirectories, + autoImportDomains, + preprocess, + leftAssoc); + } + + public org.kframework.definition.Definition loadDefinition( + String mainModuleName, + String syntaxModuleName, + String definitionText, + Source source, + File currentDirectory, + List lookupDirectories, + boolean autoImportDomains, + boolean preprocess, + boolean leftAssoc) { + Set previousModules = new HashSet<>(); + Set requiredFiles = new HashSet<>(); + Context context = new Context(); + if (autoImportDomains) + previousModules.addAll( + loadModules( + new HashSet<>(), + context, + Kompile.REQUIRE_PRELUDE_K, + Source.apply("Auto imported prelude"), + currentDirectory, + lookupDirectories, + requiredFiles, + preprocess, + leftAssoc)); + Set modules = + loadModules( + previousModules, + context, + definitionText, + source, + currentDirectory, + lookupDirectories, + requiredFiles, + preprocess, + leftAssoc); + if (preprocess) { + Main.exit(0); + } + modules.addAll(previousModules); // add the previous modules, since load modules is not additive + Module mainModule = getMainModule(mainModuleName, modules); + Optional opt; + opt = modules.stream().filter(m -> m.name().equals(syntaxModuleName)).findFirst(); + Module syntaxModule; + if (!opt.isPresent()) { + kem.registerCompilerWarning( + ExceptionType.MISSING_SYNTAX_MODULE, + "Could not find main syntax module with name " + + syntaxModuleName + + " in definition. Use --syntax-module to specify one. Using " + + mainModuleName + + " as default."); + syntaxModule = mainModule; + } else { + syntaxModule = opt.get(); } - private Module getMainModule(String mainModuleName, Set modules) { - Optional opt = modules.stream().filter(m -> m.name().equals(mainModuleName)).findFirst(); - if (!opt.isPresent()) { - throw KEMException.compilerError("Could not find main module with name " + mainModuleName - + " in definition. Use --main-module to specify one."); - } - return opt.get(); + return org.kframework.definition.Definition.apply( + mainModule, immutable(modules), Att().add(Att.SYNTAX_MODULE(), syntaxModule.name())); + } + + private Module getMainModule(String mainModuleName, Set modules) { + Optional opt = + modules.stream().filter(m -> m.name().equals(mainModuleName)).findFirst(); + if (!opt.isPresent()) { + throw KEMException.compilerError( + "Could not find main module with name " + + mainModuleName + + " in definition. Use --main-module to specify one."); } + return opt.get(); + } } diff --git a/kernel/src/main/java/org/kframework/parser/binary/BinaryParser.java b/kernel/src/main/java/org/kframework/parser/binary/BinaryParser.java index dead9cabc35..05d5d27a546 100644 --- a/kernel/src/main/java/org/kframework/parser/binary/BinaryParser.java +++ b/kernel/src/main/java/org/kframework/parser/binary/BinaryParser.java @@ -1,11 +1,7 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.binary; -import org.kframework.kore.K; -import org.kframework.kore.KLabel; -import org.kframework.kore.KToken; -import org.kframework.parser.outer.Outer; -import org.kframework.utils.errorsystem.KEMException; +import static org.kframework.kore.KORE.*; import java.io.IOException; import java.nio.ByteBuffer; @@ -16,188 +12,196 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.kframework.kore.K; +import org.kframework.kore.KLabel; +import org.kframework.kore.KToken; +import org.kframework.parser.outer.Outer; +import org.kframework.utils.errorsystem.KEMException; -import static org.kframework.kore.KORE.*; /** * Parses a KAST binary term into the KORE data structures. * - * Format of the KAST binary term is as follows: + *

Format of the KAST binary term is as follows: * - * First five bytes are the magic header "\x7fKAST". - * Next 3 bytes are the major, minor, and release version of the format. Currently - * they are set to "\x04\x00\x00". + *

First five bytes are the magic header "\x7fKAST". Next 3 bytes are the major, minor, and + * release version of the format. Currently they are set to "\x04\x00\x00". * - * Subsequently, the format contains a post-order traversal of the term according to the following rules: + *

Subsequently, the format contains a post-order traversal of the term according to the + * following rules: * - * * KToken: the byte "\x01" followed by a representation of the string of the token, and then the sort of the - * token. - * * KApply: Representation of each child of the KApply followed by the byte "\x02" followed by a representation - * of the klabel, followed by a 4-byte arity of the KApply. - * * KSequence: Representation of each child of the KSequence followed by the byte "\x03" followed by a 4-byte - * length of the KSequence. - * * KVariable: The byte "\x04" followed by a representation of the name of the variable. - * * KRewrite: Representation of the LHS of the rewrite, followed by the RHS, followed by the byte "\x05". - * * InjectedKLabel: The byte "\x06" followed by the representation of the klabel. - * * KLabel: The representation of the string of the klabel, followed by the byte "\x01" if the klabel is a - * variable, and "\x00" if it's a concrete klabel. - * * String: A 4-byte offset in the string intern table. The intern table is commputed as the term is traversed. - * An offset of 0 means that the string has not appeared before in this term, and is followed by a - * 4-byte length of the string followed by the String in UTF-16. An offset of 1 means the string - * refers to the most recent previous string in the intern table. An offset of 2 means the - * next-most-recent, and so forth. + *

* KToken: the byte "\x01" followed by a representation of the string of the token, and then + * the sort of the token. * KApply: Representation of each child of the KApply followed by the byte + * "\x02" followed by a representation of the klabel, followed by a 4-byte arity of the KApply. * + * KSequence: Representation of each child of the KSequence followed by the byte "\x03" followed by + * a 4-byte length of the KSequence. * KVariable: The byte "\x04" followed by a representation of + * the name of the variable. * KRewrite: Representation of the LHS of the rewrite, followed by the + * RHS, followed by the byte "\x05". * InjectedKLabel: The byte "\x06" followed by the + * representation of the klabel. * KLabel: The representation of the string of the klabel, followed + * by the byte "\x01" if the klabel is a variable, and "\x00" if it's a concrete klabel. * String: A + * 4-byte offset in the string intern table. The intern table is commputed as the term is traversed. + * An offset of 0 means that the string has not appeared before in this term, and is followed by a + * 4-byte length of the string followed by the String in UTF-16. An offset of 1 means the string + * refers to the most recent previous string in the intern table. An offset of 2 means the + * next-most-recent, and so forth. * - * Note one exception to this rule in binary format 4.0.1: if a term is encountered that has already been serialized, - * instead of serializing it again we serialize the byte '\x08' followed by a 4-byte offset in the term intern table. - * The term intern table behaves the same as the string intern table except that it contains every term that has been - * traversed to date. + *

Note one exception to this rule in binary format 4.0.1: if a term is encountered that has + * already been serialized, instead of serializing it again we serialize the byte '\x08' followed by + * a 4-byte offset in the term intern table. The term intern table behaves the same as the string + * intern table except that it contains every term that has been traversed to date. * - * After the term is traversed, it terminates with the byte "\x07". Note that KAST terms are constructed to be - * self-contained and composable. A client can take the output of two KAST terms and combine them into a single term - * simply by concatenating the terms together after stripping their MAGIC prefix and suffix. This will not be as - * space-compact as if the term was outputted all at once, but can be done in constant time without requiring the terms - * to be modified internally, and will still deserialze correctly. + *

After the term is traversed, it terminates with the byte "\x07". Note that KAST terms are + * constructed to be self-contained and composable. A client can take the output of two KAST terms + * and combine them into a single term simply by concatenating the terms together after stripping + * their MAGIC prefix and suffix. This will not be as space-compact as if the term was outputted all + * at once, but can be done in constant time without requiring the terms to be modified internally, + * and will still deserialze correctly. */ public class BinaryParser { - public static final byte[] MAGIC = {0x7f, 'K', 'A', 'S', 'T'}; - - public static final int BEGIN = 0, KTOKEN = 1, KAPPLY = 2, KSEQUENCE = 3, KVARIABLE = 4, KREWRITE = 5, - INJECTEDKLABEL = 6, END = 7, BACK_REFERENCE = 8; - - private final ByteBuffer data; - private final List interns = new ArrayList<>(); - private final List kInterns = new ArrayList<>(); - - private static final K[] EMPTY_KLIST = new K[0]; - - private BinaryParser(ByteBuffer data) { - this.data = data; + public static final byte[] MAGIC = {0x7f, 'K', 'A', 'S', 'T'}; + + public static final int BEGIN = 0, + KTOKEN = 1, + KAPPLY = 2, + KSEQUENCE = 3, + KVARIABLE = 4, + KREWRITE = 5, + INJECTEDKLABEL = 6, + END = 7, + BACK_REFERENCE = 8; + + private final ByteBuffer data; + private final List interns = new ArrayList<>(); + private final List kInterns = new ArrayList<>(); + + private static final K[] EMPTY_KLIST = new K[0]; + + private BinaryParser(ByteBuffer data) { + this.data = data; + } + + private K read400(boolean _401) throws IOException { + + Deque stack = new ArrayDeque<>(); + int type = 0; + while (type != END) { + type = data.get(); + K[] items; + int arity; + switch (type) { + case KTOKEN: + String s = readString(); + String sort = readString(); + Map sortCache = + ktokenCache.computeIfAbsent(sort, sort2 -> new HashMap<>()); + KToken token = sortCache.computeIfAbsent(s, s2 -> KToken(s, Outer.parseSort(sort))); + stack.push(token); + break; + case KAPPLY: + KLabel lbl = readKLabel(); + arity = data.getInt(); + if (arity == 0) items = EMPTY_KLIST; + else items = new K[arity]; + for (int i = arity - 1; i >= 0; i--) { + items[i] = stack.pop(); + } + stack.push(KApply(lbl, items)); + break; + case KSEQUENCE: + arity = data.getInt(); + if (arity == 0) items = EMPTY_KLIST; + else items = new K[arity]; + for (int i = arity - 1; i >= 0; i--) { + items[i] = stack.pop(); + } + stack.push(KSequence(items)); + break; + case KVARIABLE: + stack.push(KVariable(readString())); + break; + case KREWRITE: + K right = stack.pop(); + K left = stack.pop(); + stack.push(KRewrite(left, right)); + break; + case INJECTEDKLABEL: + stack.push(InjectedKLabel(readKLabel())); + break; + case END: + break; + case BACK_REFERENCE: + if (!_401) + throw KEMException.criticalError("Unexpected code found in KAST binary term: " + type); + int idx = data.getInt(); + stack.push(kInterns.get(kInterns.size() - idx)); + break; + default: + throw KEMException.criticalError("Unexpected code found in KAST binary term: " + type); + } + kInterns.add(stack.peek()); } - - private K read400(boolean _401) throws IOException { - - Deque stack = new ArrayDeque<>(); - int type = 0; - while(type != END) { - type = data.get(); - K[] items; - int arity; - switch (type) { - case KTOKEN: - String s = readString(); - String sort = readString(); - Map sortCache = ktokenCache.computeIfAbsent(sort, sort2 -> new HashMap<>()); - KToken token = sortCache.computeIfAbsent(s, s2 -> KToken(s, Outer.parseSort(sort))); - stack.push(token); - break; - case KAPPLY: - KLabel lbl = readKLabel(); - arity = data.getInt(); - if (arity == 0) - items = EMPTY_KLIST; - else - items = new K[arity]; - for (int i = arity - 1; i >= 0; i--) { - items[i] = stack.pop(); - } - stack.push(KApply(lbl, items)); - break; - case KSEQUENCE: - arity = data.getInt(); - if (arity == 0) - items = EMPTY_KLIST; - else - items = new K[arity]; - for (int i = arity - 1; i >= 0; i--) { - items[i] = stack.pop(); - } - stack.push(KSequence(items)); - break; - case KVARIABLE: - stack.push(KVariable(readString())); - break; - case KREWRITE: - K right = stack.pop(); - K left = stack.pop(); - stack.push(KRewrite(left, right)); - break; - case INJECTEDKLABEL: - stack.push(InjectedKLabel(readKLabel())); - break; - case END: - break; - case BACK_REFERENCE: - if (!_401) - throw KEMException.criticalError("Unexpected code found in KAST binary term: " + type); - int idx = data.getInt(); - stack.push(kInterns.get(kInterns.size() - idx)); - break; - default: - throw KEMException.criticalError("Unexpected code found in KAST binary term: " + type); - } - kInterns.add(stack.peek()); - } - // gc hints - interns.clear(); - klabelCache.clear(); - ktokenCache.clear(); - kInterns.clear(); - return stack.peek(); + // gc hints + interns.clear(); + klabelCache.clear(); + ktokenCache.clear(); + kInterns.clear(); + return stack.peek(); + } + + private final Map klabelCache = new HashMap<>(); + private final Map> ktokenCache = new HashMap<>(); + + private KLabel readKLabel() throws IOException { + String lbl = readString(); + if (data.get() != 0) return KVariable(lbl); + return klabelCache.computeIfAbsent(lbl, org.kframework.kore.KORE::KLabel); + } + + private String readString() throws IOException { + int idx = data.getInt(); + if (idx == 0) { + int len = data.getInt(); + char[] buf = new char[len]; + for (int i = 0; i < len; i++) { + buf[i] = data.getChar(); + } + String s = new String(buf); + interns.add(s); + return s; + } else { + return interns.get(interns.size() - idx); } - - private final Map klabelCache = new HashMap<>(); - private final Map> ktokenCache = new HashMap<>(); - - private KLabel readKLabel() throws IOException { - String lbl = readString(); - if (data.get() != 0) - return KVariable(lbl); - return klabelCache.computeIfAbsent(lbl, org.kframework.kore.KORE::KLabel); - } - - private String readString() throws IOException { - int idx = data.getInt(); - if (idx == 0) { - int len = data.getInt(); - char[] buf = new char[len]; - for (int i = 0; i < len; i++) { - buf[i] = data.getChar(); - } - String s = new String(buf); - interns.add(s); - return s; - } else { - return interns.get(interns.size() - idx); - } - } - - public static boolean isBinaryKast(byte[] bytes) { - return Arrays.equals(Arrays.copyOfRange(bytes, 0, 5), MAGIC); - } - - public static K parse(byte[] in) { - return parse(ByteBuffer.wrap(in)); - } - - public static K parse(ByteBuffer data) { - try { - byte[] magic = new byte[5]; - data.get(magic); - if (!Arrays.equals(magic, MAGIC)) { - throw KEMException.compilerError("Reading binary data from input source which is not a KAST term."); - } - int major = data.get(); - int minor = data.get(); - int build = data.get(); - if (major == 4 && minor == 0 && build == 0) { - return new BinaryParser(data).read400(false); - } else if (major == 4 && minor == 0 && build == 1) { - return new BinaryParser(data).read400(true); - } else { - throw KEMException.compilerError("Unsupported version of KAST binary file: " + major + "." + minor + "." + build); - } - } catch (IOException e) { - throw KEMException.criticalError("Could not read K term from binary", e); - } + } + + public static boolean isBinaryKast(byte[] bytes) { + return Arrays.equals(Arrays.copyOfRange(bytes, 0, 5), MAGIC); + } + + public static K parse(byte[] in) { + return parse(ByteBuffer.wrap(in)); + } + + public static K parse(ByteBuffer data) { + try { + byte[] magic = new byte[5]; + data.get(magic); + if (!Arrays.equals(magic, MAGIC)) { + throw KEMException.compilerError( + "Reading binary data from input source which is not a KAST term."); + } + int major = data.get(); + int minor = data.get(); + int build = data.get(); + if (major == 4 && minor == 0 && build == 0) { + return new BinaryParser(data).read400(false); + } else if (major == 4 && minor == 0 && build == 1) { + return new BinaryParser(data).read400(true); + } else { + throw KEMException.compilerError( + "Unsupported version of KAST binary file: " + major + "." + minor + "." + build); + } + } catch (IOException e) { + throw KEMException.criticalError("Could not read K term from binary", e); } + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/ApplySynonyms.java b/kernel/src/main/java/org/kframework/parser/inner/ApplySynonyms.java index 18211cff8fa..2e197d685e2 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/ApplySynonyms.java +++ b/kernel/src/main/java/org/kframework/parser/inner/ApplySynonyms.java @@ -1,6 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; + +import java.util.ArrayList; +import java.util.List; import org.kframework.definition.Module; import org.kframework.definition.NonTerminal; import org.kframework.definition.Production; @@ -8,32 +13,26 @@ import org.kframework.definition.Sentence; import org.kframework.kore.Sort; -import java.util.ArrayList; -import java.util.List; - -import static org.kframework.definition.Constructors.*; -import static org.kframework.Collections.*; - public class ApplySynonyms { - public Production apply(Module m, Production p) { - Sort returnSort = m.sortSynonymMap().applyOrElse(p.sort(), s -> p.sort()); - List pis = new ArrayList<>(); - for (ProductionItem pi : iterable(p.items())) { - if (pi instanceof NonTerminal nt) { - pis.add(NonTerminal(m.sortSynonymMap().applyOrElse(nt.sort(), s -> nt.sort()), nt.name())); - } else { - pis.add(pi); - } + public Production apply(Module m, Production p) { + Sort returnSort = m.sortSynonymMap().applyOrElse(p.sort(), s -> p.sort()); + List pis = new ArrayList<>(); + for (ProductionItem pi : iterable(p.items())) { + if (pi instanceof NonTerminal nt) { + pis.add(NonTerminal(m.sortSynonymMap().applyOrElse(nt.sort(), s -> nt.sort()), nt.name())); + } else { + pis.add(pi); } - return Production(p.klabel(), p.params(), returnSort, immutable(pis), p.att()); } + return Production(p.klabel(), p.params(), returnSort, immutable(pis), p.att()); + } - public Sentence apply(Module m, Sentence s) { - if (s instanceof Production) { - return apply(m, (Production)s); - } else { - return s; - } + public Sentence apply(Module m, Sentence s) { + if (s instanceof Production) { + return apply(m, (Production) s); + } else { + return s; } + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/CollectProductionsVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/CollectProductionsVisitor.java index 9ace6039109..a4c3e57722c 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/CollectProductionsVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/CollectProductionsVisitor.java @@ -1,45 +1,52 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner; +import java.util.List; import org.kframework.kil.Definition; import org.kframework.kil.Module; import org.kframework.kil.Production; -import org.kframework.kore.Sort; import org.kframework.kil.Syntax; import org.kframework.kil.loader.Context; - -import java.util.List; +import org.kframework.kore.Sort; public class CollectProductionsVisitor { - private final Context context; - - public CollectProductionsVisitor(Context context) { - this.context = context; - } - - private String moduleName; - private Sort sort; - private List params; - - public void visit(Module mod) { - this.moduleName = mod.getName(); - mod.getItems().forEach(mi -> { if (mi instanceof Syntax) visit((Syntax)mi); }); - } - - public void visit(Syntax syntax) { - this.sort = syntax.getDeclaredSort().getRealSort(); - this.params = syntax.getParams(); - syntax.getPriorityBlocks().forEach(pb -> pb.getProductions().forEach(this::visit)); - } - - public void visit(Production node) { - node.setSort(sort); - node.setOwnerModuleName(moduleName); - node.setParams(params); - context.addProduction(node); - } - - public void visit(Definition def) { - def.getItems().forEach(di -> { if (di instanceof Module) visit((Module)di); }); - } + private final Context context; + + public CollectProductionsVisitor(Context context) { + this.context = context; + } + + private String moduleName; + private Sort sort; + private List params; + + public void visit(Module mod) { + this.moduleName = mod.getName(); + mod.getItems() + .forEach( + mi -> { + if (mi instanceof Syntax) visit((Syntax) mi); + }); + } + + public void visit(Syntax syntax) { + this.sort = syntax.getDeclaredSort().getRealSort(); + this.params = syntax.getParams(); + syntax.getPriorityBlocks().forEach(pb -> pb.getProductions().forEach(this::visit)); + } + + public void visit(Production node) { + node.setSort(sort); + node.setOwnerModuleName(moduleName); + node.setParams(params); + context.addProduction(node); + } + + public void visit(Definition def) { + def.getItems() + .forEach( + di -> { + if (di instanceof Module) visit((Module) di); + }); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/ParseCache.java b/kernel/src/main/java/org/kframework/parser/inner/ParseCache.java index 0c4fee0651f..57acd30cdb2 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/ParseCache.java +++ b/kernel/src/main/java/org/kframework/parser/inner/ParseCache.java @@ -1,23 +1,23 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner; +import java.io.Serializable; +import java.util.Map; +import java.util.Set; import org.kframework.attributes.Source; import org.kframework.definition.Module; import org.kframework.kore.K; import org.kframework.utils.errorsystem.KEMException; -import java.io.Serializable; -import java.util.Map; -import java.util.Set; - -/** - * Created by dwightguth on 4/20/15. - */ -public record ParseCache(Module module, boolean strict, - Map cache) implements Serializable { - public record ParsedSentence(K parse, - Set warnings, - Set errors, int startLine, - int startColumn, Source source) implements Serializable { - } +/** Created by dwightguth on 4/20/15. */ +public record ParseCache(Module module, boolean strict, Map cache) + implements Serializable { + public record ParsedSentence( + K parse, + Set warnings, + Set errors, + int startLine, + int startColumn, + Source source) + implements Serializable {} } diff --git a/kernel/src/main/java/org/kframework/parser/inner/ParseInModule.java b/kernel/src/main/java/org/kframework/parser/inner/ParseInModule.java index 059dfda65fe..9a71cc3d75f 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/ParseInModule.java +++ b/kernel/src/main/java/org/kframework/parser/inner/ParseInModule.java @@ -2,6 +2,13 @@ package org.kframework.parser.inner; import com.google.common.collect.Sets; +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.kframework.attributes.Location; import org.kframework.attributes.Source; @@ -27,362 +34,477 @@ import scala.util.Left; import scala.util.Right; -import java.io.File; -import java.io.IOException; -import java.io.Serializable; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.stream.Collectors; - /** - * A wrapper that takes a module and one can call the parser - * for that module in thread safe way. + * A wrapper that takes a module and one can call the parser for that module in thread safe way. * Declarative disambiguation filters are also applied. */ public class ParseInModule implements Serializable, AutoCloseable { - private final Module seedModule; - private Module extensionModule; - /** - * The module in which parsing will be done. - * Note that this module will be used for disambiguation, and the parsing module can be different. - * This allows for grammar rewriting and more flexibility in the implementation. - */ - private Module disambModule; - /** - * The exact module used for parsing. This can contain productions and sorts that are not - * necessarily representable in KORE (sorts like Ne#Ids, to avoid name collisions). - * In this case the modified production will be annotated with the information from the - * original production, so disambiguation can be done safely. - */ - private volatile Module parsingModule; - private volatile EarleyParser parser = null; - private final boolean strict; - private final boolean profileRules; - private final boolean isBison; - private final boolean forGlobalScanner; - private final FileUtil files; - private final String typeInferenceDebug; - private final boolean partialParseDebug; - - ParseInModule(Module seedModule, boolean strict, boolean profileRules, boolean isBison, boolean forGlobalScanner, FileUtil files, String typeInferenceDebug, boolean partialParseDebug) { - this(seedModule, null, null, null, null, strict, profileRules, isBison, forGlobalScanner, files, typeInferenceDebug, partialParseDebug); - } + private final Module seedModule; + private Module extensionModule; - ParseInModule(Module seedModule, Scanner scanner, boolean strict, boolean profileRules, boolean isBison, boolean forGlobalScanner, FileUtil files, String typeInferenceDebug, boolean partialParseDebug) { - this(seedModule, null, null, null, scanner, strict, profileRules, isBison, forGlobalScanner, files, typeInferenceDebug, partialParseDebug); - } + /** + * The module in which parsing will be done. Note that this module will be used for + * disambiguation, and the parsing module can be different. This allows for grammar rewriting and + * more flexibility in the implementation. + */ + private Module disambModule; - private ParseInModule(Module seedModule, Module extensionModule, Module disambModule, Module parsingModule, Scanner scanner, boolean strict, boolean profileRules, boolean isBison, boolean forGlobalScanner, FileUtil files, String typeInferenceDebug, boolean partialParseDebug) { - this.seedModule = seedModule; - this.extensionModule = extensionModule; - this.disambModule = disambModule; - this.parsingModule = parsingModule; - this.scanner = scanner; - this.strict = strict; - this.profileRules = profileRules; - this.isBison = isBison; - this.forGlobalScanner = forGlobalScanner; - this.files = files; - this.typeInferenceDebug = typeInferenceDebug; - this.partialParseDebug = partialParseDebug; - } + /** + * The exact module used for parsing. This can contain productions and sorts that are not + * necessarily representable in KORE (sorts like Ne#Ids, to avoid name collisions). In this case + * the modified production will be annotated with the information from the original production, so + * disambiguation can be done safely. + */ + private volatile Module parsingModule; - /** - * The original module, which includes all the marker/flags imports. - * This can be used to invalidate caches. - * @return Module given by the user. - */ - public Module seedModule() { - return seedModule; - } + private volatile EarleyParser parser = null; + private final boolean strict; + private final boolean profileRules; + private final boolean isBison; + private final boolean forGlobalScanner; + private final FileUtil files; + private final String typeInferenceDebug; + private final boolean partialParseDebug; - /** - * An extension module of the seedModule which includes all productions, unmodified, and in addition, - * contains extra productions auto-defined, like casts. - * @return Module with extra productions defined during parser generator. - */ - public Module getExtensionModule() { - Module extM = extensionModule; - if (extM == null) { - Tuple3 mods = RuleGrammarGenerator.getCombinedGrammarImpl(seedModule, isBison, forGlobalScanner); - extM = mods._1(); - disambModule = mods._2(); - parsingModule = mods._3(); - extensionModule = extM; - } - return extM; + ParseInModule( + Module seedModule, + boolean strict, + boolean profileRules, + boolean isBison, + boolean forGlobalScanner, + FileUtil files, + String typeInferenceDebug, + boolean partialParseDebug) { + this( + seedModule, + null, + null, + null, + null, + strict, + profileRules, + isBison, + forGlobalScanner, + files, + typeInferenceDebug, + partialParseDebug); + } + + ParseInModule( + Module seedModule, + Scanner scanner, + boolean strict, + boolean profileRules, + boolean isBison, + boolean forGlobalScanner, + FileUtil files, + String typeInferenceDebug, + boolean partialParseDebug) { + this( + seedModule, + null, + null, + null, + scanner, + strict, + profileRules, + isBison, + forGlobalScanner, + files, + typeInferenceDebug, + partialParseDebug); + } + + private ParseInModule( + Module seedModule, + Module extensionModule, + Module disambModule, + Module parsingModule, + Scanner scanner, + boolean strict, + boolean profileRules, + boolean isBison, + boolean forGlobalScanner, + FileUtil files, + String typeInferenceDebug, + boolean partialParseDebug) { + this.seedModule = seedModule; + this.extensionModule = extensionModule; + this.disambModule = disambModule; + this.parsingModule = parsingModule; + this.scanner = scanner; + this.strict = strict; + this.profileRules = profileRules; + this.isBison = isBison; + this.forGlobalScanner = forGlobalScanner; + this.files = files; + this.typeInferenceDebug = typeInferenceDebug; + this.partialParseDebug = partialParseDebug; + } + + /** + * The original module, which includes all the marker/flags imports. This can be used to + * invalidate caches. + * + * @return Module given by the user. + */ + public Module seedModule() { + return seedModule; + } + + /** + * An extension module of the seedModule which includes all productions, unmodified, and in + * addition, contains extra productions auto-defined, like casts. + * + * @return Module with extra productions defined during parser generator. + */ + public Module getExtensionModule() { + Module extM = extensionModule; + if (extM == null) { + Tuple3 mods = + RuleGrammarGenerator.getCombinedGrammarImpl(seedModule, isBison, forGlobalScanner); + extM = mods._1(); + disambModule = mods._2(); + parsingModule = mods._3(); + extensionModule = extM; } + return extM; + } - public Module getParsingModule() { - Module parseM = parsingModule; - if (parseM == null) { - Tuple3 mods = RuleGrammarGenerator.getCombinedGrammarImpl(seedModule, isBison, forGlobalScanner); - extensionModule = mods._1(); - disambModule = mods._2(); - parseM = mods._3(); - parsingModule = parseM; - } - return parseM; + public Module getParsingModule() { + Module parseM = parsingModule; + if (parseM == null) { + Tuple3 mods = + RuleGrammarGenerator.getCombinedGrammarImpl(seedModule, isBison, forGlobalScanner); + extensionModule = mods._1(); + disambModule = mods._2(); + parseM = mods._3(); + parsingModule = parseM; } + return parseM; + } - public Module getDisambiguationModule() { - Module disambM = disambModule; - if (disambM == null) { - Tuple3 mods = RuleGrammarGenerator.getCombinedGrammarImpl(seedModule, isBison, forGlobalScanner); - extensionModule = mods._1(); - disambM = mods._2(); - parsingModule = mods._3(); - disambModule = disambM; - } - return disambM; + public Module getDisambiguationModule() { + Module disambM = disambModule; + if (disambM == null) { + Tuple3 mods = + RuleGrammarGenerator.getCombinedGrammarImpl(seedModule, isBison, forGlobalScanner); + extensionModule = mods._1(); + disambM = mods._2(); + parsingModule = mods._3(); + disambModule = disambM; } + return disambM; + } + public void initialize() { + Module m = getDisambiguationModule(); + m.definedSorts(); + m.subsorts(); + m.priorities(); + m.leftAssoc(); + m.rightAssoc(); + m.productionsFor(); + m.overloads(); + } - public void initialize() { - Module m = getDisambiguationModule(); - m.definedSorts(); - m.subsorts(); - m.priorities(); - m.leftAssoc(); - m.rightAssoc(); - m.productionsFor(); - m.overloads(); + /** + * Parse as input the given string and start symbol using the module stored in the object. + * + * @param input the string to parse. + * @param startSymbol the start symbol from which to parse. + * @return the Term representation of the parsed input. + */ + public Tuple2, K>, Set> parseString( + String input, Sort startSymbol, Source source) { + try (Scanner scanner = getScanner()) { + return parseString(input, startSymbol, "unit test", scanner, source, 1, 1, true, false); } + } - /** - * Parse as input the given string and start symbol using the module stored in the object. - * @param input the string to parse. - * @param startSymbol the start symbol from which to parse. - * @return the Term representation of the parsed input. - */ - public Tuple2, K>, Set> - parseString(String input, Sort startSymbol, Source source) { - try (Scanner scanner = getScanner()) { - return parseString(input, startSymbol, "unit test", scanner, source, 1, 1, true, false); - } + /** + * Print the list of tokens matched by the scanner, the location and the Regex Terminal The output + * is a valid Markdown table. + */ + public String tokenizeString(String input, Source source) { + StringBuilder sb = new StringBuilder(); + try (Scanner scanner = getScanner()) { + EarleyParser.ParserMetadata mdata = + new EarleyParser.ParserMetadata(input, scanner, source, 1, 1); + Map kind2Token = + scanner.getTokens().entrySet().stream() + .map(a -> new Tuple2<>(a.getValue()._1, a.getKey())) + .collect(Collectors.toMap(Tuple2::_1, Tuple2::_2)); + List lines = mdata.getLines(); + List columns = mdata.getColumns(); + int maxTokenLen = 7, maxLocLen = 10, maxTerminalLen = 10; + List locs = new ArrayList<>(); + List tokens = new ArrayList<>(); + List terminals = new ArrayList<>(); + List words = mdata.getWords(); + for (Scanner.Token word : mdata.getWords()) { + String loc = + String.format( + "(%d,%d,%d,%d)", + lines.get(word.startLoc), + columns.get(word.startLoc), + lines.get(word.endLoc), + columns.get(word.endLoc)); + locs.add(loc); + maxLocLen = Math.max(maxLocLen, loc.length()); + String tok = StringUtil.enquoteKString(word.value); + tokens.add(tok); + maxTokenLen = Math.max(maxTokenLen, tok.length()); + String terminal = kind2Token.getOrDefault(word.kind, Terminal.apply("")).toString(); + terminals.add(terminal); + maxTerminalLen = Math.max(maxTerminalLen, terminal.length()); + } + // if the token is absurdly large limit the column to 80 chars to maintain alignment + maxTokenLen = Math.min(maxTokenLen, 80); + maxTerminalLen = Math.min(maxTerminalLen, 20); + sb.append( + String.format( + "|%-" + maxTokenLen + "s | %-" + maxLocLen + "s | %-" + maxTerminalLen + "s|\n", + "\"Match\"", + "(location)", + "Terminal")); + sb.append( + String.format( + "|-%s|--%s|-%s|\n", + "-".repeat(maxTokenLen), "-".repeat(maxLocLen), "-".repeat(maxTerminalLen))); + for (int i = 0; i < words.size(); i++) { + Scanner.Token word = words.get(i); + sb.append( + String.format( + "|%-" + maxTokenLen + "s | %-" + maxLocLen + "s | %-" + maxTerminalLen + "s|\n", + tokens.get(i), + locs.get(i), + terminals.get(i))); + } } + return sb.toString(); + } - /** - * Print the list of tokens matched by the scanner, the location and the Regex Terminal - * The output is a valid Markdown table. - */ - public String tokenizeString(String input, Source source) { - StringBuilder sb = new StringBuilder(); - try (Scanner scanner = getScanner()) { - EarleyParser.ParserMetadata mdata = new EarleyParser.ParserMetadata(input, scanner, source, 1, 1); - Map kind2Token = - scanner.getTokens().entrySet().stream().map(a -> new Tuple2<>(a.getValue()._1, a.getKey())) - .collect(Collectors.toMap(Tuple2::_1, Tuple2::_2)); - List lines = mdata.getLines(); - List columns = mdata.getColumns(); - int maxTokenLen = 7, maxLocLen = 10, maxTerminalLen = 10; - List locs = new ArrayList<>(); - List tokens = new ArrayList<>(); - List terminals = new ArrayList<>(); - List words = mdata.getWords(); - for (Scanner.Token word : mdata.getWords()) { - String loc = String.format("(%d,%d,%d,%d)", - lines.get(word.startLoc), columns.get(word.startLoc), - lines.get(word.endLoc), columns.get(word.endLoc)); - locs.add(loc); - maxLocLen = Math.max(maxLocLen, loc.length()); - String tok = StringUtil.enquoteKString(word.value); - tokens.add(tok); - maxTokenLen = Math.max(maxTokenLen, tok.length()); - String terminal = kind2Token.getOrDefault(word.kind, Terminal.apply("")).toString(); - terminals.add(terminal); - maxTerminalLen = Math.max(maxTerminalLen, terminal.length()); - } - // if the token is absurdly large limit the column to 80 chars to maintain alignment - maxTokenLen = Math.min(maxTokenLen, 80); - maxTerminalLen = Math.min(maxTerminalLen, 20); - sb.append(String.format("|%-" + maxTokenLen + "s | %-" + maxLocLen + "s | %-" + maxTerminalLen + "s|\n", - "\"Match\"", "(location)", "Terminal")); - sb.append(String.format("|-%s|--%s|-%s|\n", "-".repeat(maxTokenLen), "-".repeat(maxLocLen), "-".repeat(maxTerminalLen))); - for (int i = 0; i < words.size(); i++) { - Scanner.Token word = words.get(i); - sb.append(String.format("|%-" + maxTokenLen + "s | %-" + maxLocLen + "s | %-" + maxTerminalLen + "s|\n", - tokens.get(i), locs.get(i), terminals.get(i))); - } - } - return sb.toString(); + public Tuple2, K>, Set> parseString( + String input, Sort startSymbol, String startSymbolLocation, Source source) { + try (Scanner scanner = getScanner()) { + return parseString( + input, startSymbol, startSymbolLocation, scanner, source, 1, 1, true, false); } + } - public Tuple2, K>, Set> - parseString(String input, Sort startSymbol, String startSymbolLocation, Source source) { - try (Scanner scanner = getScanner()) { - return parseString(input, startSymbol, startSymbolLocation, scanner, source, 1, 1, true, false); - } - } - private void getParser(Scanner scanner, Sort startSymbol) { - EarleyParser p = parser; - if (p == null) { - Module m = getParsingModule(); - p = new EarleyParser(m, scanner, startSymbol, partialParseDebug); - parser = p; - } + private void getParser(Scanner scanner, Sort startSymbol) { + EarleyParser p = parser; + if (p == null) { + Module m = getParsingModule(); + p = new EarleyParser(m, scanner, startSymbol, partialParseDebug); + parser = p; } + } - private Scanner scanner; - private final ThreadLocal inferencer = new ThreadLocal<>(); - private final Queue inferencers = new ConcurrentLinkedQueue<>(); + private Scanner scanner; + private final ThreadLocal inferencer = new ThreadLocal<>(); + private final Queue inferencers = new ConcurrentLinkedQueue<>(); - public Scanner getScanner(GlobalOptions go) { - if (scanner == null) { - scanner = new Scanner(this, go); - } - return scanner; + public Scanner getScanner(GlobalOptions go) { + if (scanner == null) { + scanner = new Scanner(this, go); } - public Scanner getScanner() { - if (scanner == null) { - scanner = new Scanner(this); - } - return scanner; + return scanner; + } + + public Scanner getScanner() { + if (scanner == null) { + scanner = new Scanner(this); } - public void setScanner(Scanner s) { - scanner = s; + return scanner; + } + + public void setScanner(Scanner s) { + scanner = s; + } + + public Tuple2, K>, Set> parseString( + String input, + Sort startSymbol, + String startSymbolLocation, + Scanner scanner, + Source source, + int startLine, + int startColumn, + boolean inferSortChecks, + boolean isAnywhere) { + final Tuple2, Term>, Set> result = + parseStringTerm( + input, + startSymbol, + startSymbolLocation, + scanner, + source, + startLine, + startColumn, + inferSortChecks, + isAnywhere); + Either, K> parseInfo; + if (result._1().isLeft()) { + parseInfo = Left.apply(result._1().left().get()); + } else { + parseInfo = + Right.apply( + new TreeNodesToKORE(Outer::parseSort, inferSortChecks && strict) + .apply(result._1().right().get())); } + return new Tuple2<>(parseInfo, result._2()); + } + + /** + * Parse the given input. This function is private because the final disambiguation in {@link + * AmbFilter} eliminates ambiguities that will be equivalent only after calling {@link + * TreeNodesToKORE#apply(Term)}, but returns a result that is somewhat arbitrary as an actual + * parser {@link Term}. Fortunately all callers want the result as a K, and can use the public + * version of this method. + * + * @param input + * @param startSymbol + * @param source + * @param startLine + * @param startColumn + * @return + */ + private Tuple2, Term>, Set> parseStringTerm( + String input, + Sort startSymbol, + String startSymbolLocation, + Scanner scanner, + Source source, + int startLine, + int startColumn, + boolean inferSortChecks, + boolean isAnywhere) { + if (!parsingModule.definedSorts().contains(startSymbol.head())) + throw KEMException.innerParserError( + "Could not find start symbol: " + startSymbol + " provided to " + startSymbolLocation, + source, + Location.apply(startLine, startColumn, startLine, startColumn + 1)); + getParser(scanner, startSymbol); - public Tuple2, K>, Set> - parseString(String input, Sort startSymbol, String startSymbolLocation, Scanner scanner, Source source, int startLine, int startColumn, boolean inferSortChecks, boolean isAnywhere) { - final Tuple2, Term>, Set> result - = parseStringTerm(input, startSymbol, startSymbolLocation, scanner, source, startLine, startColumn, inferSortChecks, isAnywhere); - Either, K> parseInfo; - if (result._1().isLeft()) { - parseInfo = Left.apply(result._1().left().get()); - } else { - parseInfo = Right.apply(new TreeNodesToKORE(Outer::parseSort, inferSortChecks && strict).apply(result._1().right().get())); + long start, endParse = 0, startTypeInf = 0, endTypeInf = 0; + start = profileRules ? System.currentTimeMillis() : 0; + + try { + Set warn = Sets.newHashSet(); + Term parsed; + try { + parsed = parser.parse(input, source, startLine, startColumn); + } catch (KEMException e) { + return Tuple2.apply(Left.apply(Collections.singleton(e)), Collections.emptySet()); + } + endParse = profileRules ? System.currentTimeMillis() : 0; + + Term rez3 = new TreeCleanerVisitor().apply(parsed); + Either, Term> rez = new CollapseRecordProdsVisitor(rez3).apply(rez3); + if (rez.isLeft()) return new Tuple2<>(rez, warn); + rez = + new PriorityVisitor( + disambModule.priorities(), disambModule.leftAssoc(), disambModule.rightAssoc()) + .apply(rez.right().get()); + if (rez.isLeft()) return new Tuple2<>(rez, warn); + rez = new KAppToTermConsVisitor(disambModule).apply(rez.right().get()); + if (rez.isLeft()) return new Tuple2<>(rez, warn); + rez3 = new PushAmbiguitiesDownAndPreferAvoid().apply(rez.right().get()); + rez3 = new PushTopAmbiguityUp().apply(rez3); + startTypeInf = profileRules ? System.currentTimeMillis() : 0; + + TypeInferencer currentInferencer; + if (isDebug(source, startLine)) { + currentInferencer = new TypeInferencer(disambModule, true); + inferencers.add(currentInferencer); + } else { + currentInferencer = inferencer.get(); + if (currentInferencer == null) { + currentInferencer = new TypeInferencer(disambModule, isDebug(source, startLine)); + inferencer.set(currentInferencer); + inferencers.add(currentInferencer); } - return new Tuple2<>(parseInfo, result._2()); - } + } + + rez = + new TypeInferenceVisitor( + currentInferencer, startSymbol, strict && inferSortChecks, true, isAnywhere) + .apply(rez3); + if (rez.isLeft()) return new Tuple2<>(rez, warn); + endTypeInf = profileRules ? System.currentTimeMillis() : 0; - /** - * Parse the given input. This function is private because the final disambiguation - * in {@link AmbFilter} eliminates ambiguities that will be equivalent only after - * calling {@link TreeNodesToKORE#apply(Term)}, but returns a result that is - * somewhat arbitrary as an actual parser {@link Term}. - * Fortunately all callers want the result as a K, and can use the public - * version of this method. - * @param input - * @param startSymbol - * @param source - * @param startLine - * @param startColumn - * @return - */ - private Tuple2, Term>, Set> - parseStringTerm(String input, Sort startSymbol, String startSymbolLocation, Scanner scanner, Source source, int startLine, int startColumn, boolean inferSortChecks, boolean isAnywhere) { - if (!parsingModule.definedSorts().contains(startSymbol.head())) - throw KEMException.innerParserError("Could not find start symbol: " + startSymbol + " provided to " + startSymbolLocation, source, Location.apply(startLine, startColumn, startLine, startColumn + 1)); - getParser(scanner, startSymbol); - - long start, endParse = 0, startTypeInf = 0, endTypeInf = 0; - start = profileRules ? System.currentTimeMillis() : 0; + rez = new ResolveOverloadedTerminators(disambModule.overloads()).apply(rez.right().get()); + if (rez.isLeft()) return new Tuple2<>(rez, warn); + rez3 = + new PushAmbiguitiesDownAndPreferAvoid(disambModule.overloads()).apply(rez.right().get()); + rez = new AmbFilterError(strict && inferSortChecks).apply(rez3); + if (rez.isLeft()) return new Tuple2<>(rez, warn); + Tuple2, Term>, Set> rez2 = + new AddEmptyLists(disambModule, startSymbol).apply(rez.right().get()); + warn = Sets.union(rez2._2(), warn); + if (rez2._1().isLeft()) return rez2; + rez3 = new RemoveBracketVisitor().apply(rez2._1().right().get()); + return new Tuple2<>(Right.apply(rez3), warn); + } finally { + if (profileRules) { try { - Set warn = Sets.newHashSet(); - Term parsed; - try { - parsed = parser.parse(input, source, startLine, startColumn); - } catch (KEMException e) { - return Tuple2.apply(Left.apply(Collections.singleton(e)), Collections.emptySet()); - } - endParse = profileRules ? System.currentTimeMillis() : 0; - - Term rez3 = new TreeCleanerVisitor().apply(parsed); - Either, Term> rez = new CollapseRecordProdsVisitor(rez3).apply(rez3); - if (rez.isLeft()) - return new Tuple2<>(rez, warn); - rez = new PriorityVisitor(disambModule.priorities(), disambModule.leftAssoc(), disambModule.rightAssoc()).apply(rez.right().get()); - if (rez.isLeft()) - return new Tuple2<>(rez, warn); - rez = new KAppToTermConsVisitor(disambModule).apply(rez.right().get()); - if (rez.isLeft()) - return new Tuple2<>(rez, warn); - rez3 = new PushAmbiguitiesDownAndPreferAvoid().apply(rez.right().get()); - rez3 = new PushTopAmbiguityUp().apply(rez3); - startTypeInf = profileRules ? System.currentTimeMillis() : 0; - - TypeInferencer currentInferencer; - if (isDebug(source, startLine)) { - currentInferencer = new TypeInferencer(disambModule, true); - inferencers.add(currentInferencer); - } else { - currentInferencer = inferencer.get(); - if (currentInferencer == null) { - currentInferencer = new TypeInferencer(disambModule, isDebug(source, startLine)); - inferencer.set(currentInferencer); - inferencers.add(currentInferencer); - } - } - - rez = new TypeInferenceVisitor(currentInferencer, startSymbol, strict && inferSortChecks, true, isAnywhere).apply(rez3); - if (rez.isLeft()) - return new Tuple2<>(rez, warn); - endTypeInf = profileRules ? System.currentTimeMillis() : 0; - - rez = new ResolveOverloadedTerminators(disambModule.overloads()).apply(rez.right().get()); - if (rez.isLeft()) - return new Tuple2<>(rez, warn); - rez3 = new PushAmbiguitiesDownAndPreferAvoid(disambModule.overloads()).apply(rez.right().get()); - rez = new AmbFilterError(strict && inferSortChecks).apply(rez3); - if (rez.isLeft()) - return new Tuple2<>(rez, warn); - Tuple2, Term>, Set> rez2 = new AddEmptyLists(disambModule, startSymbol).apply(rez.right().get()); - warn = Sets.union(rez2._2(), warn); - if (rez2._1().isLeft()) - return rez2; - rez3 = new RemoveBracketVisitor().apply(rez2._1().right().get()); - - return new Tuple2<>(Right.apply(rez3), warn); - } finally { - if (profileRules) { - try { - long stop = System.currentTimeMillis(); - long totalTime = stop - start; - long parseTime = endParse - start; - long tiTime = endTypeInf - startTypeInf; - File f = File.createTempFile("timing", ".log", files.resolveTemp("")); - FileUtils.writeStringToFile(f, String.format("%s:%d\n%5d %s:%d parse:%4d typeInf:%4d", - source.source(), startLine, totalTime, source.source(), startLine, parseTime, tiTime), StandardCharsets.UTF_8); - } catch (IOException e) { - throw KEMException.internalError("Could not write to timing.log", e); - } - } + long stop = System.currentTimeMillis(); + long totalTime = stop - start; + long parseTime = endParse - start; + long tiTime = endTypeInf - startTypeInf; + File f = File.createTempFile("timing", ".log", files.resolveTemp("")); + FileUtils.writeStringToFile( + f, + String.format( + "%s:%d\n%5d %s:%d parse:%4d typeInf:%4d", + source.source(), + startLine, + totalTime, + source.source(), + startLine, + parseTime, + tiTime), + StandardCharsets.UTF_8); + } catch (IOException e) { + throw KEMException.internalError("Could not write to timing.log", e); } + } } + } - private boolean isDebug(Source source, int startLine) { - if (typeInferenceDebug == null) { - return false; - } - return (source.source() + ":" + startLine).endsWith(typeInferenceDebug); + private boolean isDebug(Source source, int startLine) { + if (typeInferenceDebug == null) { + return false; } + return (source.source() + ":" + startLine).endsWith(typeInferenceDebug); + } - public void close() { - if (scanner != null) { - scanner.close(); - } - for (TypeInferencer inferencer : inferencers) { - inferencer.close(); - } - inferencers.clear(); + public void close() { + if (scanner != null) { + scanner.close(); + } + for (TypeInferencer inferencer : inferencers) { + inferencer.close(); } + inferencers.clear(); + } - public static Term disambiguateForUnparse(Module mod, Term ambiguity) { - Term rez3 = new PushTopAmbiguityUp().apply(ambiguity); - Either, Term> rez; - Tuple2, Term>, Set> rez2; - try (TypeInferencer inferencer = new TypeInferencer(mod, false)) { - rez = new TypeInferenceVisitor(inferencer, Sorts.K(), false, false, false).apply(rez3); - } - if (rez.isLeft()) { - rez2 = new AmbFilter(false).apply(rez3); - return rez2._1().right().get(); - } - rez3 = new PushAmbiguitiesDownAndPreferAvoid(mod.overloads()).apply(rez.right().get()); - rez2 = new AmbFilter(false).apply(rez3); - return rez2._1().right().get(); + public static Term disambiguateForUnparse(Module mod, Term ambiguity) { + Term rez3 = new PushTopAmbiguityUp().apply(ambiguity); + Either, Term> rez; + Tuple2, Term>, Set> rez2; + try (TypeInferencer inferencer = new TypeInferencer(mod, false)) { + rez = new TypeInferenceVisitor(inferencer, Sorts.K(), false, false, false).apply(rez3); + } + if (rez.isLeft()) { + rez2 = new AmbFilter(false).apply(rez3); + return rez2._1().right().get(); } + rez3 = new PushAmbiguitiesDownAndPreferAvoid(mod.overloads()).apply(rez.right().get()); + rez2 = new AmbFilter(false).apply(rez3); + return rez2._1().right().get(); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/RuleGrammarGenerator.java b/kernel/src/main/java/org/kframework/parser/inner/RuleGrammarGenerator.java index 9181ef13773..55dfe71747a 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/RuleGrammarGenerator.java +++ b/kernel/src/main/java/org/kframework/parser/inner/RuleGrammarGenerator.java @@ -1,6 +1,19 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.definition.Constructors.Module; +import static org.kframework.kore.KORE.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.collections4.trie.PatriciaTrie; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; @@ -29,545 +42,733 @@ import scala.Tuple3; import scala.collection.Seq; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.UnaryOperator; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.Module; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - /** - * Generator for rule and ground parsers. - * Takes as input a reference to a definition containing all the base syntax of K - * and uses it to generate a grammar by connecting all users sorts in a lattice with - * the top sort KItem#Top and the bottom sort KItem#Bottom. - *

- * The instances of the non-terminal KItem is renamed in KItem#Top if found in the right - * hand side of a production, and into KItem#Bottom if found in the left hand side. + * Generator for rule and ground parsers. Takes as input a reference to a definition containing all + * the base syntax of K and uses it to generate a grammar by connecting all users sorts in a lattice + * with the top sort KItem#Top and the bottom sort KItem#Bottom. + * + *

The instances of the non-terminal KItem is renamed in KItem#Top if found in the right hand + * side of a production, and into KItem#Bottom if found in the left hand side. */ public record RuleGrammarGenerator(Definition baseK) { - private static final Set kSorts = new HashSet<>(); - - static { - kSorts.add(Sorts.KBott()); - kSorts.add(Sorts.K()); - kSorts.add(Sorts.KLabel()); - kSorts.add(Sorts.KList()); - kSorts.add(Sorts.KItem()); - kSorts.add(Sorts.KConfigVar()); - kSorts.add(Sorts.KString()); + private static final Set kSorts = new HashSet<>(); + + static { + kSorts.add(Sorts.KBott()); + kSorts.add(Sorts.K()); + kSorts.add(Sorts.KLabel()); + kSorts.add(Sorts.KList()); + kSorts.add(Sorts.KItem()); + kSorts.add(Sorts.KConfigVar()); + kSorts.add(Sorts.KString()); + } + + private static Set kSorts() { + return java.util.Collections.unmodifiableSet(kSorts); + } + + /// modules that have a meaning: + public static final String DEFAULT_LAYOUT = "DEFAULT-LAYOUT"; + public static final String RULE_CELLS = "RULE-CELLS"; + public static final String CONFIG_CELLS = "CONFIG-CELLS"; + public static final String K = "K"; + public static final String AUTO_CASTS = "AUTO-CASTS"; + public static final String KSEQ_SYMBOLIC = "KSEQ-SYMBOLIC"; + public static final String K_TOP_SORT = "K-TOP-SORT"; + public static final String K_BOTTOM_SORT = "K-BOTTOM-SORT"; + public static final String AUTO_FOLLOW = "AUTO-FOLLOW"; + public static final String PROGRAM_LISTS = "PROGRAM-LISTS"; + public static final String RULE_LISTS = "RULE-LISTS"; + public static final String RECORD_PRODS = "RECORD-PRODUCTIONS"; + public static final String SORT_PREDICATES = "SORT-PREDICATES"; + + public static final String POSTFIX = "-PROGRAM-PARSING"; + + public static final String NOT_INJECTION = "notInjection"; + public static final String ID = "ID"; + private static final String ID_SYNTAX = "ID-SYNTAX"; + public static final String ID_PROGRAM_PARSING = ID_SYNTAX + POSTFIX; + + /** + * Initialize a grammar generator. + * + * @param baseK A Definition containing a K module giving the syntax of K itself. The default K + * syntax is defined in include/kast.k. + */ + public RuleGrammarGenerator {} + + private Set renameKItem2Bottom(Set def) { + // TODO: do renaming of KItem and K in the LHS to KBott? + return def; + } + + /** + * Creates the seed module that can be used to parse rules. Imports module markers RULE-CELLS and + * K found in /include/kast.k. + * + * @param mod The user defined module from which to start. + * @return a new module which imports the original user module and a set of marker modules. + */ + public Module getRuleGrammar(Module mod) { + return getGrammar(mod, RULE_CELLS); + } + + private Module getGrammar(Module mod, String name) { + // import RULE-CELLS in order to parse cells specific to rules + Module newM = + new Module( + mod.name() + "-" + name, + (scala.collection.Set) + mod.imports() + .$bar( + Set( + Import(baseK.getModule(K).get(), true), + Import(baseK.getModule(name).get(), true), + Import(baseK.getModule(DEFAULT_LAYOUT).get(), true))), + mod.localSentences(), + mod.att()); + return newM; + } + + /** + * Creates the seed module that can be used to parse configurations. Imports module markers + * CONFIG-CELLS and K found in /include/kast.k. + * + * @param mod The user defined module from which to start. + * @return a new module which imports the original user module and a set of marker modules. + */ + public Module getConfigGrammar(Module mod) { + return getGrammar(mod, CONFIG_CELLS); + } + + /** + * Creates the seed module that can be used to parse programs. Imports module markers + * PROGRAM-LISTS found in /include/kast.k. + * + * @param mod The user defined module from which to start. + * @return a new module which imports the original user module and a set of marker modules. + */ + public Module getProgramsGrammar(Module mod) { + + if (mod.name().endsWith(POSTFIX)) { + return mod; + } else { + Module newMod = + ModuleTransformer.from( + oldMod -> { + UnaryOperator f = + _import -> { + Option programParsing = + baseK.getModule(_import.module().name() + "-PROGRAM-PARSING"); + if (programParsing.isDefined()) { + return Import(programParsing.get(), _import.isPublic()); + } + return _import; + }; + Set imports = + stream(oldMod.imports()).map(f).collect(Collectors.toSet()); + return Module.apply( + oldMod.name(), immutable(imports), oldMod.localSentences(), oldMod.att()); + }, + "apply program parsing modules") + .apply(mod); + + Set modules = new HashSet(); + for (Import m : iterable(newMod.imports())) { + modules.add(m); + } + + // import PROGRAM-LISTS so user lists are modified to parse programs + modules.add(Import(baseK.getModule(PROGRAM_LISTS).get(), true)); + + // check if `#Layout` has been declared, import `DEFAULT-LAYOUT` if not + if (!mod.allSorts().contains(Sorts.Layout())) { + modules.add(Import(baseK.getModule(DEFAULT_LAYOUT).get(), true)); + } + + return Module.apply( + mod.name() + "-PROGRAM-GRAMMAR", + immutable(modules), + newMod.localSentences(), + newMod.att()); } - - private static Set kSorts() { - return java.util.Collections.unmodifiableSet(kSorts); - } - - /// modules that have a meaning: - public static final String DEFAULT_LAYOUT = "DEFAULT-LAYOUT"; - public static final String RULE_CELLS = "RULE-CELLS"; - public static final String CONFIG_CELLS = "CONFIG-CELLS"; - public static final String K = "K"; - public static final String AUTO_CASTS = "AUTO-CASTS"; - public static final String KSEQ_SYMBOLIC = "KSEQ-SYMBOLIC"; - public static final String K_TOP_SORT = "K-TOP-SORT"; - public static final String K_BOTTOM_SORT = "K-BOTTOM-SORT"; - public static final String AUTO_FOLLOW = "AUTO-FOLLOW"; - public static final String PROGRAM_LISTS = "PROGRAM-LISTS"; - public static final String RULE_LISTS = "RULE-LISTS"; - public static final String RECORD_PRODS = "RECORD-PRODUCTIONS"; - public static final String SORT_PREDICATES = "SORT-PREDICATES"; - - public static final String POSTFIX = "-PROGRAM-PARSING"; - - public static final String NOT_INJECTION = "notInjection"; - public static final String ID = "ID"; - private static final String ID_SYNTAX = "ID-SYNTAX"; - public static final String ID_PROGRAM_PARSING = ID_SYNTAX + POSTFIX; - - /** - * Initialize a grammar generator. - * - * @param baseK A Definition containing a K module giving the syntax of K itself. - * The default K syntax is defined in include/kast.k. - */ - public RuleGrammarGenerator { - } - - private Set renameKItem2Bottom(Set def) { - // TODO: do renaming of KItem and K in the LHS to KBott? - return def; + } + + public static boolean isParserSort(Sort s) { + return kSorts.contains(s) || s.name().startsWith("#") || s.isNat(); + } + + /* use this overload if you don't need to profile rule parse times. */ + public static ParseInModule getCombinedGrammar(Module mod, boolean strict, FileUtil files) { + return getCombinedGrammar(mod, strict, false, false, false, files, null, false); + } + + public static ParseInModule getCombinedGrammar( + Module mod, boolean strict, FileUtil files, boolean partialParseDebug) { + return getCombinedGrammar(mod, strict, false, false, false, files, null, partialParseDebug); + } + + public static ParseInModule getCombinedGrammar( + Module mod, boolean strict, boolean timing, FileUtil files) { + return getCombinedGrammar(mod, strict, timing, false, false, files, null, false); + } + + public static ParseInModule getCombinedGrammar( + Module mod, boolean strict, boolean timing, FileUtil files, String debugTypeInference) { + return getCombinedGrammar(mod, strict, timing, false, false, files, debugTypeInference, false); + } + + public static ParseInModule getCombinedGrammar( + Module mod, boolean strict, boolean timing, boolean isBison, FileUtil files) { + return getCombinedGrammar(mod, strict, timing, isBison, false, files, null, false); + } + + public static ParseInModule getCombinedGrammar( + Module mod, + boolean strict, + boolean timing, + boolean isBison, + boolean forGlobalScanner, + FileUtil files) { + return getCombinedGrammar(mod, strict, timing, isBison, forGlobalScanner, files, null, false); + } + + public static ParseInModule getCombinedGrammar( + Module mod, + Scanner scanner, + boolean strict, + boolean timing, + boolean isBison, + FileUtil files) { + return getCombinedGrammar(mod, scanner, strict, timing, isBison, files, null, false); + } + + // the forGlobalScanner flag tells the ParseInModule class not to exclude + // private syntax from the grammar generated for the module. It should + // not be used when actually performing parsing as this will lead to + // incorrect grammars. However, it is used in one place in the code: + // during rule parsing, we generate a single scanner to scan all the + // modules. This must include the private syntax of those modules, + // otherwise we would not be able to use it to scan the modules in which + // that private syntax is visible. + + /** + * Create the rule parser for the given module. It creates a module which includes the given + * module and the base K module given to the constructor. The new module contains syntax + * declaration for Casts and the diamond which connects the user concrete syntax with K syntax. + * + * @param mod module for which to create the parser. + * @param partialParseDebug + * @return parser which applies disambiguation filters by default. + */ + public static ParseInModule getCombinedGrammar( + Module mod, + boolean strict, + boolean timing, + boolean isBison, + boolean forGlobalScanner, + FileUtil files, + String debugTypeInference, + boolean partialParseDebug) { + return new ParseInModule( + mod, + strict, + timing, + isBison, + forGlobalScanner, + files, + debugTypeInference, + partialParseDebug); + } + + public static ParseInModule getCombinedGrammar( + Module mod, + Scanner scanner, + boolean strict, + boolean timing, + boolean isBison, + FileUtil files, + String debugTypeInference, + boolean partialParseDebug) { + return new ParseInModule( + mod, scanner, strict, timing, isBison, false, files, debugTypeInference, partialParseDebug); + } + + public static Tuple3 getCombinedGrammarImpl( + Module mod, boolean isBison, boolean forGlobalScanner) { + Set prods = new HashSet<>(); + Set extensionProds = new HashSet<>(); + Set disambProds; + + Module origMod = mod; + + if (!forGlobalScanner) { + mod = mod.signature(); } - /** - * Creates the seed module that can be used to parse rules. - * Imports module markers RULE-CELLS and K found in /include/kast.k. - * - * @param mod The user defined module from which to start. - * @return a new module which imports the original user module and a set of marker modules. - */ - public Module getRuleGrammar(Module mod) { - return getGrammar(mod, RULE_CELLS); - } - - private Module getGrammar(Module mod, String name) { - // import RULE-CELLS in order to parse cells specific to rules - Module newM = new Module(mod.name() + "-" + name - , (scala.collection.Set) mod.imports().$bar(Set(Import(baseK.getModule(K).get(), true), Import(baseK.getModule(name).get(), true), Import(baseK.getModule(DEFAULT_LAYOUT).get(), true))) - , mod.localSentences() - , mod.att() - ); - return newM; - } - - /** - * Creates the seed module that can be used to parse configurations. - * Imports module markers CONFIG-CELLS and K found in /include/kast.k. - * - * @param mod The user defined module from which to start. - * @return a new module which imports the original user module and a set of marker modules. - */ - public Module getConfigGrammar(Module mod) { - return getGrammar(mod, CONFIG_CELLS); - } - - /** - * Creates the seed module that can be used to parse programs. - * Imports module markers PROGRAM-LISTS found in /include/kast.k. - * - * @param mod The user defined module from which to start. - * @return a new module which imports the original user module and a set of marker modules. - */ - public Module getProgramsGrammar(Module mod) { - - if (mod.name().endsWith(POSTFIX)) { - return mod; - } else { - Module newMod = ModuleTransformer.from(oldMod -> { - UnaryOperator f = _import -> { - Option programParsing = baseK.getModule(_import.module().name() + "-PROGRAM-PARSING"); - if (programParsing.isDefined()) { - return Import(programParsing.get(), _import.isPublic()); + if (isBison) { + mod = + ModuleTransformer.from( + m -> { + if (m.att().contains(Att.NOT_LR1())) { + return Module(m.name(), m.imports(), Set(), m.att()); } - return _import; - }; - Set imports = stream(oldMod.imports()).map(f).collect(Collectors.toSet()); - return Module.apply(oldMod.name(), immutable(imports), oldMod.localSentences(), oldMod.att()); - }, "apply program parsing modules").apply(mod); - - Set modules = new HashSet(); - for (Import m : iterable(newMod.imports())) { - modules.add(m); - } - - // import PROGRAM-LISTS so user lists are modified to parse programs - modules.add(Import(baseK.getModule(PROGRAM_LISTS).get(), true)); - - // check if `#Layout` has been declared, import `DEFAULT-LAYOUT` if not - if (!mod.allSorts().contains(Sorts.Layout())) { - modules.add(Import(baseK.getModule(DEFAULT_LAYOUT).get(), true)); - } - - return Module.apply(mod.name() + "-PROGRAM-GRAMMAR", immutable(modules), newMod.localSentences(), newMod.att()); - } - } - - public static boolean isParserSort(Sort s) { - return kSorts.contains(s) || s.name().startsWith("#") || s.isNat(); + return m; + }, + "strip not-lr1 modules from bison grammar") + .apply(mod); } - /* use this overload if you don't need to profile rule parse times. */ - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, FileUtil files) { - return getCombinedGrammar(mod, strict, false, false, false, files, null, false); - } - - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, FileUtil files, boolean partialParseDebug) { - return getCombinedGrammar(mod, strict, false, false, false, files, null, partialParseDebug); - } - - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, boolean timing, FileUtil files) { - return getCombinedGrammar(mod, strict, timing, false, false, files, null, false); - } - - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, boolean timing, FileUtil files, String debugTypeInference) { - return getCombinedGrammar(mod, strict, timing, false, false, files, debugTypeInference, false); + if (mod.importedModuleNames().contains(AUTO_CASTS)) { // create the diamond + Set temp; + for (Sort srt : iterable(mod.allSorts())) { + if (!isParserSort(srt) || mod.subsorts().directlyLessThan(Sorts.KVariable(), srt)) { + // K ::= K "::Sort" | K ":Sort" | K "<:Sort" | K ":>Sort" + prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), srt, srt)); + } + } + prods.addAll(makeCasts(Sorts.KLabel(), Sorts.KLabel(), Sorts.KLabel(), Sorts.KLabel())); + prods.addAll(makeCasts(Sorts.KList(), Sorts.KList(), Sorts.KList(), Sorts.KList())); + prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), Sorts.KItem(), Sorts.KItem())); + prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), Sorts.K(), Sorts.K())); + for (SortSynonym syn : iterable(mod.sortSynonyms())) { + prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), syn.newSort(), syn.oldSort())); + } } - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, boolean timing, boolean isBison, FileUtil files) { - return getCombinedGrammar(mod, strict, timing, isBison, false, files, null, false); + if (mod.importedModuleNames().contains(SORT_PREDICATES)) { + for (Sort s : iterable(mod.allSorts())) { + prods.addAll(new GenerateSortPredicateSyntax().gen(mod, s)); + prods.addAll(new GenerateSortProjections(mod).gen(s).collect(Collectors.toSet())); + } } - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, boolean timing, boolean isBison, boolean forGlobalScanner, FileUtil files) { - return getCombinedGrammar(mod, strict, timing, isBison, forGlobalScanner, files, null, false); + for (Production p : iterable(mod.productions())) + prods.addAll(new GenerateSortProjections(mod).gen(p).collect(Collectors.toSet())); + + // Because parametric productions introduce Non-Terminal names that do not exist in the module, + // we can't + // create a valid parsing grammar. + // Here we go through every parametric production and, we replace it with concrete sorts. + // We have 4 distinct cases depending on whether the return type of the production is parametric + // or not: + // 1 - prod sort is a simple parameter + // 2 - prod sort is a parametric sort + // 3 - special case for `syntax {Sort} KItem ::= Sort` // the subsort production found in + // kast.md + // 4 - prod sort is a concrete sort. + // Because, at parse time, the prod sort is decided by the parent production we can instantiate + // it with concrete + // sorts. Parameters appearing only on the RHS of a production do not have any sort information + // at parsing time, + // so we use the top sort `K` as a placeholder. Meaning we can expect anything there. The + // connection is then handled + // at case 3 where we add subsorts for every parsable sort in the module. + // TODO: for now we only have `MInt{Widht}` as parametric sorts, so we can treat it as a corner + // case. + // LHS gets instantiated the same way, but RHS gets instantiated with `MInt{K}` and we need to + // add an extra subsort + // production `syntax MInt{K} ::= MInt{6}` to make the connection between the new sort and the + // concrete sorts. + // This production doesn't have a klabel so it's not going to appear in the final AST. + List allSorts = + stream(mod.allSorts()) + .filter(s -> (!isParserSort(s) || s.equals(Sorts.KItem()) || s.equals(Sorts.K()))) + .collect(Collectors.toList()); + for (SortHead sh : mutable(mod.definedInstantiations()).keySet()) { + for (Sort s : mutable(mod.definedInstantiations().apply(sh))) { + // syntax MInt{K} ::= MInt{6} + Production p1 = + Production( + Option.empty(), Seq(), Sort(s.name(), Sorts.K()), Seq(NonTerminal(s)), Att()); + prods.add(p1); + } } - - public static ParseInModule getCombinedGrammar(Module mod, Scanner scanner, boolean strict, boolean timing, boolean isBison, FileUtil files) { - return getCombinedGrammar(mod, scanner, strict, timing, isBison, files, null, false); + for (Production p : iterable(mod.productions())) { + if (p.params().nonEmpty()) { + if (p.params().contains(p.sort())) { // case 1 + // syntax {P, R} P ::= P "+" R "-" Int + // syntax S ::= S "+" K "-" Int + for (Sort s : allSorts) { + List instantiationMask = new ArrayList<>(); + for (Sort param : mutable(p.params())) + if (param.equals(p.sort())) instantiationMask.add(s); + else instantiationMask.add(Sorts.K()); + Production subst = p.substitute(immutable(instantiationMask)); + Production p1 = + Production( + subst.klabel().map(lbl -> KLabel(lbl.name())), + Seq(), + subst.sort(), + subst.items(), + subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); + prods.add(p1); + } + } else if (!p.sort().params().isEmpty()) { // case 2 + // TODO: assuming sorts have only one parameter for now + // syntax {W, X, Y} MInt{W} ::= MInt{W} "+" MInt{X} "-" Y "/" Int + // syntax MInt{6} ::= MInt{6} "+" MInt{K} "-" K "/" Int + Set instantations = mutable(mod.definedInstantiations().apply(p.sort().head())); + for (Sort s : instantations) { + List instantiationMask = new ArrayList<>(); + for (Sort param : mutable(p.params())) + if (param.equals(p.sort().params().apply(0))) + instantiationMask.add(s.params().apply(0)); + else instantiationMask.add(Sorts.K()); + Production subst = p.substitute(immutable(instantiationMask)); + Production p1 = + Production( + subst.klabel().map(lbl -> KLabel(lbl.name())), + Seq(), + subst.sort(), + subst.items(), + subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); + prods.add(p1); + } + } else if (p.isSyntacticSubsort()) { // case 3 + // a single production found in kast.md that handles the subsorting to the top sort + // syntax {Sort} KItem ::= Sort + // syntax KItem ::= Int + for (Sort s : allSorts) { + if (!p.params().contains(p.sort()) && (s.equals(Sorts.KItem()) || s.equals(Sorts.K()))) + continue; + List instantiationMask = new ArrayList<>(); + instantiationMask.add(s); + Production subst = p.substitute(immutable(instantiationMask)); + Production p1 = + Production( + subst.klabel().map(lbl -> KLabel(lbl.name())), + Seq(), + subst.sort(), + subst.items(), + subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); + prods.add(p1); + } + } else { // case 4 + // the rest of the productions that return a concrete sort can accept any sort inside + // syntax {P} Int ::= P "+" Int + // syntax Int ::= K "+" Int + List instantiationMask = new ArrayList<>(); + for (Sort param : mutable(p.params())) instantiationMask.add(Sorts.K()); + Production subst = p.substitute(immutable(instantiationMask)); + Production p1 = + Production( + subst.klabel().map(lbl -> KLabel(lbl.name())), + Seq(), + subst.sort(), + subst.items(), + subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); + prods.add(p1); + } + } } - - // the forGlobalScanner flag tells the ParseInModule class not to exclude - // private syntax from the grammar generated for the module. It should - // not be used when actually performing parsing as this will lead to - // incorrect grammars. However, it is used in one place in the code: - // during rule parsing, we generate a single scanner to scan all the - // modules. This must include the private syntax of those modules, - // otherwise we would not be able to use it to scan the modules in which - // that private syntax is visible. - - /** - * Create the rule parser for the given module. - * It creates a module which includes the given module and the base K module given to the - * constructor. The new module contains syntax declaration for Casts and the diamond - * which connects the user concrete syntax with K syntax. - * - * @param mod module for which to create the parser. - * @param partialParseDebug - * @return parser which applies disambiguation filters by default. - */ - public static ParseInModule getCombinedGrammar(Module mod, boolean strict, boolean timing, boolean isBison, boolean forGlobalScanner, FileUtil files, String debugTypeInference, boolean partialParseDebug) { - return new ParseInModule(mod, strict, timing, isBison, forGlobalScanner, files, debugTypeInference, partialParseDebug); + extensionProds.addAll(prods); + + Set recordProds = new HashSet<>(); + if (mod.importedModuleNames().contains(RECORD_PRODS)) { + // these should be visible only in the parsing module + // but are required by config cell names + UidProvider uid = new UidProvider(mod.name()); + for (Production p : iterable(mod.productions())) { + if (p.isPrefixProduction()) { + recordProds.addAll(mutable(p.recordProductions(uid))); + } + } } - public static ParseInModule getCombinedGrammar(Module mod, Scanner scanner, boolean strict, boolean timing, boolean isBison, FileUtil files, String debugTypeInference, boolean partialParseDebug) { - return new ParseInModule(mod, scanner, strict, timing, isBison, false, files, debugTypeInference, partialParseDebug); + boolean addRuleCells; + if (mod.importedModuleNames() + .contains(RULE_CELLS)) { // prepare cell productions for rule parsing + // make sure a configuration actually exists, otherwise ConfigurationInfoFromModule explodes. + addRuleCells = + mod.sentences().exists(p -> p instanceof Production && p.att().contains(Att.CELL())); + } else { + addRuleCells = false; } - - public static Tuple3 getCombinedGrammarImpl(Module mod, boolean isBison, boolean forGlobalScanner) { - Set prods = new HashSet<>(); - Set extensionProds = new HashSet<>(); - Set disambProds; - - Module origMod = mod; - - if (!forGlobalScanner) { - mod = mod.signature(); - } - - if (isBison) { - mod = ModuleTransformer.from(m -> { - if (m.att().contains(Att.NOT_LR1())) { - return Module(m.name(), m.imports(), Set(), m.att()); - } - return m; - }, "strip not-lr1 modules from bison grammar").apply(mod); - } - - if (mod.importedModuleNames().contains(AUTO_CASTS)) { // create the diamond - Set temp; - for (Sort srt : iterable(mod.allSorts())) { - if (!isParserSort(srt) || mod.subsorts().directlyLessThan(Sorts.KVariable(), srt)) { - // K ::= K "::Sort" | K ":Sort" | K "<:Sort" | K ":>Sort" - prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), srt, srt)); - } - } - prods.addAll(makeCasts(Sorts.KLabel(), Sorts.KLabel(), Sorts.KLabel(), Sorts.KLabel())); - prods.addAll(makeCasts(Sorts.KList(), Sorts.KList(), Sorts.KList(), Sorts.KList())); - prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), Sorts.KItem(), Sorts.KItem())); - prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), Sorts.K(), Sorts.K())); - for (SortSynonym syn : iterable(mod.sortSynonyms())) { - prods.addAll(makeCasts(Sorts.KBott(), Sorts.K(), syn.newSort(), syn.oldSort())); - } - } - - if (mod.importedModuleNames().contains(SORT_PREDICATES)) { - for (Sort s : iterable(mod.allSorts())) { - prods.addAll(new GenerateSortPredicateSyntax().gen(mod, s)); - prods.addAll(new GenerateSortProjections(mod).gen(s).collect(Collectors.toSet())); - } - } - - for (Production p : iterable(mod.productions())) - prods.addAll(new GenerateSortProjections(mod).gen(p).collect(Collectors.toSet())); - - // Because parametric productions introduce Non-Terminal names that do not exist in the module, we can't - // create a valid parsing grammar. - // Here we go through every parametric production and, we replace it with concrete sorts. - // We have 4 distinct cases depending on whether the return type of the production is parametric or not: - // 1 - prod sort is a simple parameter - // 2 - prod sort is a parametric sort - // 3 - special case for `syntax {Sort} KItem ::= Sort` // the subsort production found in kast.md - // 4 - prod sort is a concrete sort. - // Because, at parse time, the prod sort is decided by the parent production we can instantiate it with concrete - // sorts. Parameters appearing only on the RHS of a production do not have any sort information at parsing time, - // so we use the top sort `K` as a placeholder. Meaning we can expect anything there. The connection is then handled - // at case 3 where we add subsorts for every parsable sort in the module. - // TODO: for now we only have `MInt{Widht}` as parametric sorts, so we can treat it as a corner case. - // LHS gets instantiated the same way, but RHS gets instantiated with `MInt{K}` and we need to add an extra subsort - // production `syntax MInt{K} ::= MInt{6}` to make the connection between the new sort and the concrete sorts. - // This production doesn't have a klabel so it's not going to appear in the final AST. - List allSorts = stream(mod.allSorts()).filter( - s -> (!isParserSort(s) || s.equals(Sorts.KItem()) || s.equals(Sorts.K()))).collect(Collectors.toList()); - for (SortHead sh : mutable(mod.definedInstantiations()).keySet()) { - for (Sort s : mutable(mod.definedInstantiations().apply(sh))) { - // syntax MInt{K} ::= MInt{6} - Production p1 = Production(Option.empty(), Seq(), Sort(s.name(), Sorts.K()), Seq(NonTerminal(s)), Att()); - prods.add(p1); - } - } - for (Production p : iterable(mod.productions())) { - if (p.params().nonEmpty()) { - if (p.params().contains(p.sort())) { // case 1 - // syntax {P, R} P ::= P "+" R "-" Int - // syntax S ::= S "+" K "-" Int - for (Sort s : allSorts) { - List instantiationMask = new ArrayList<>(); - for (Sort param : mutable(p.params())) - if (param.equals(p.sort())) - instantiationMask.add(s); - else - instantiationMask.add(Sorts.K()); - Production subst = p.substitute(immutable(instantiationMask)); - Production p1 = Production(subst.klabel().map(lbl -> KLabel(lbl.name())), Seq(), subst.sort(), subst.items(), subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); - prods.add(p1); - } - } else if (!p.sort().params().isEmpty()) { // case 2 - // TODO: assuming sorts have only one parameter for now - // syntax {W, X, Y} MInt{W} ::= MInt{W} "+" MInt{X} "-" Y "/" Int - // syntax MInt{6} ::= MInt{6} "+" MInt{K} "-" K "/" Int - Set instantations = mutable(mod.definedInstantiations().apply(p.sort().head())); - for (Sort s : instantations) { - List instantiationMask = new ArrayList<>(); - for (Sort param : mutable(p.params())) - if (param.equals(p.sort().params().apply(0))) - instantiationMask.add(s.params().apply(0)); - else - instantiationMask.add(Sorts.K()); - Production subst = p.substitute(immutable(instantiationMask)); - Production p1 = Production(subst.klabel().map(lbl -> KLabel(lbl.name())), Seq(), subst.sort(), subst.items(), subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); - prods.add(p1); + boolean addConfigCells = mod.importedModuleNames().contains(CONFIG_CELLS); + Set parseProds; + if (addRuleCells) { + ConfigurationInfo cfgInfo = new ConfigurationInfoFromModule(mod); + parseProds = + Stream.concat(prods.stream(), stream(mod.sentences())) + .flatMap( + s -> { + if (s instanceof Production && s.att().contains(Att.CELL_COLLECTION())) { + return Stream.empty(); } - } else if (p.isSyntacticSubsort()) { // case 3 - // a single production found in kast.md that handles the subsorting to the top sort - // syntax {Sort} KItem ::= Sort - // syntax KItem ::= Int - for (Sort s : allSorts) { - if (!p.params().contains(p.sort()) && (s.equals(Sorts.KItem()) || s.equals(Sorts.K()))) - continue; - List instantiationMask = new ArrayList<>(); - instantiationMask.add(s); - Production subst = p.substitute(immutable(instantiationMask)); - Production p1 = Production(subst.klabel().map(lbl -> KLabel(lbl.name())), Seq(), subst.sort(), subst.items(), subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); - prods.add(p1); - } - } else { // case 4 - // the rest of the productions that return a concrete sort can accept any sort inside - // syntax {P} Int ::= P "+" Int - // syntax Int ::= K "+" Int - List instantiationMask = new ArrayList<>(); - for (Sort param : mutable(p.params())) - instantiationMask.add(Sorts.K()); - Production subst = p.substitute(immutable(instantiationMask)); - Production p1 = Production(subst.klabel().map(lbl -> KLabel(lbl.name())), Seq(), subst.sort(), subst.items(), subst.att().add(Att.ORIGINAL_PRD(), Production.class, p)); - prods.add(p1); - } - } - } - extensionProds.addAll(prods); - - Set recordProds = new HashSet<>(); - if (mod.importedModuleNames().contains(RECORD_PRODS)) { - // these should be visible only in the parsing module - // but are required by config cell names - UidProvider uid = new UidProvider(mod.name()); - for (Production p : iterable(mod.productions())) { - if (p.isPrefixProduction()) { - recordProds.addAll(mutable(p.recordProductions(uid))); - } - } - } - - boolean addRuleCells; - if (mod.importedModuleNames().contains(RULE_CELLS)) { // prepare cell productions for rule parsing - // make sure a configuration actually exists, otherwise ConfigurationInfoFromModule explodes. - addRuleCells = mod.sentences().exists(p -> p instanceof Production && p.att().contains(Att.CELL())); - } else { - addRuleCells = false; - } - boolean addConfigCells = mod.importedModuleNames().contains(CONFIG_CELLS); - Set parseProds; - if (addRuleCells) { - ConfigurationInfo cfgInfo = new ConfigurationInfoFromModule(mod); - parseProds = Stream.concat(prods.stream(), stream(mod.sentences())).flatMap(s -> { - if (s instanceof Production && s.att().contains(Att.CELL_COLLECTION())) { - return Stream.empty(); - } - if (s instanceof Production p && (s.att().contains(Att.CELL()))) { - // assuming that productions tagged with 'cell' start and end with terminals, and only have non-terminals in the middle - assert p.items().head() instanceof Terminal || p.items().head() instanceof RegexTerminal; - assert p.items().last() instanceof Terminal || p.items().last() instanceof RegexTerminal; - final ProductionItem body; - if (cfgInfo.isLeafCell(p.sort())) { + if (s instanceof Production p && (s.att().contains(Att.CELL()))) { + // assuming that productions tagged with 'cell' start and end with terminals, + // and only have non-terminals in the middle + assert p.items().head() instanceof Terminal + || p.items().head() instanceof RegexTerminal; + assert p.items().last() instanceof Terminal + || p.items().last() instanceof RegexTerminal; + final ProductionItem body; + if (cfgInfo.isLeafCell(p.sort())) { body = p.items().tail().head(); - } else { + } else { body = NonTerminal(Sorts.Bag()); + } + final ProductionItem optDots = NonTerminal(Sort("#OptionalDots")); + Seq pi = + Seq(p.items().head(), optDots, body, optDots, p.items().last()); + Production p1 = Production(p.klabel().get(), p.sort(), pi, p.att()); + Production p2 = Production(Seq(), Sorts.Cell(), Seq(NonTerminal(p.sort()))); + return Stream.of(p1, p2); } - final ProductionItem optDots = NonTerminal(Sort("#OptionalDots")); - Seq pi = Seq(p.items().head(), optDots, body, optDots, p.items().last()); - Production p1 = Production(p.klabel().get(), p.sort(), pi, p.att()); - Production p2 = Production(Seq(), Sorts.Cell(), Seq(NonTerminal(p.sort()))); - return Stream.of(p1, p2); - } - if (s instanceof Production p && (s.att().contains(Att.CELL_FRAGMENT(), Sort.class))) { - Production p1 = Production(Seq(), Sorts.Cell(), Seq(NonTerminal(p.sort()))); - return Stream.of(p, p1); - } - return Stream.of(s); - }).collect(Collectors.toSet()); - } else if (addConfigCells) { - // remove cells from parsing config cells so they don't conflict with the production in kast.k - // also add all matching terminals to the #CellName sort - for (Sentence prod : extensionProds) { - addCellNameProd(prods, prod); - } - for (Sentence prod : recordProds) { - addCellNameProd(prods, prod); - } - for (Sentence prod : iterable(mod.productions())) { - addCellNameProd(prods, prod); - } - parseProds = Stream.concat(prods.stream(), stream(mod.sentences()).filter(s -> !s.att().contains(Att.CELL()))).collect(Collectors.toSet()); - } else - parseProds = Stream.concat(prods.stream(), stream(mod.sentences())).collect(Collectors.toSet()); - - if (mod.importedModuleNames().contains(AUTO_FOLLOW)) { - Object PRESENT = new Object(); - PatriciaTrie terminals = new PatriciaTrie<>(); // collect all terminals so we can do automatic follow restriction for prefix terminals - parseProds.stream().filter(sent -> sent instanceof Production).forEach(p -> stream(((Production) p).items()).forEach(i -> { - if (i instanceof Terminal) terminals.put(((Terminal) i).value(), PRESENT); - })); - parseProds = parseProds.stream().map(s -> { - if (s instanceof Production p) { - if (p.sort().name().startsWith("#")) - return p; // don't do anything for such productions since they are advanced features - // rewrite productions to contain follow restrictions for prefix terminals - // example _==_ and _==K_ can produce ambiguities. Rewrite the first into _(==(?![K])_ - // this also takes care of casting and productions that have ":" - if (p.klabel().isDefined()) + if (s instanceof Production p + && (s.att().contains(Att.CELL_FRAGMENT(), Sort.class))) { + Production p1 = Production(Seq(), Sorts.Cell(), Seq(NonTerminal(p.sort()))); + return Stream.of(p, p1); + } + return Stream.of(s); + }) + .collect(Collectors.toSet()); + } else if (addConfigCells) { + // remove cells from parsing config cells so they don't conflict with the production in kast.k + // also add all matching terminals to the #CellName sort + for (Sentence prod : extensionProds) { + addCellNameProd(prods, prod); + } + for (Sentence prod : recordProds) { + addCellNameProd(prods, prod); + } + for (Sentence prod : iterable(mod.productions())) { + addCellNameProd(prods, prod); + } + parseProds = + Stream.concat( + prods.stream(), + stream(mod.sentences()).filter(s -> !s.att().contains(Att.CELL()))) + .collect(Collectors.toSet()); + } else + parseProds = + Stream.concat(prods.stream(), stream(mod.sentences())).collect(Collectors.toSet()); + + if (mod.importedModuleNames().contains(AUTO_FOLLOW)) { + Object PRESENT = new Object(); + PatriciaTrie terminals = + new PatriciaTrie<>(); // collect all terminals so we can do automatic follow restriction + // for prefix terminals + parseProds.stream() + .filter(sent -> sent instanceof Production) + .forEach( + p -> + stream(((Production) p).items()) + .forEach( + i -> { + if (i instanceof Terminal) + terminals.put(((Terminal) i).value(), PRESENT); + })); + parseProds = + parseProds.stream() + .map( + s -> { + if (s instanceof Production p) { + if (p.sort().name().startsWith("#")) + return p; // don't do anything for such productions since they are advanced + // features + // rewrite productions to contain follow restrictions for prefix terminals + // example _==_ and _==K_ can produce ambiguities. Rewrite the first into + // _(==(?![K])_ + // this also takes care of casting and productions that have ":" + if (p.klabel().isDefined()) p = Production(p.klabel().get(), p.sort(), p.items(), p.att()); - else - p = Production(p.params(), p.sort(), p.items(), p.att()); - return p; - } - return s; - }).collect(Collectors.toSet()); - } - - disambProds = parseProds.stream().collect(Collectors.toSet()); - if (mod.importedModuleNames().contains(PROGRAM_LISTS)) { - Set prods3 = new HashSet<>(); - // if no start symbol has been defined in the configuration, then use K - for (Sort srt : iterable(mod.allSorts())) { - if (!isParserSort(srt) && !mod.listSorts().contains(srt)) { - // K ::= Sort - prods3.add(Production(Seq(), Sorts.KItem(), Seq(NonTerminal(srt)), Att())); - } - } - // for each triple, generate a new pattern which works better for parsing lists in programs. - prods3.addAll(parseProds.stream().collect(Collectors.toSet())); - Set res = new HashSet<>(); - for (UserList ul : UserList.getLists(prods3)) { - Production prod1, prod2, prod3 = null, prod4 = null, prod5 = null; - - Att newAtts = ul.attrs.remove(Att.USER_LIST()); - if (ul.leftAssoc && ul.nonEmpty) { - prod1 = Production(ul.klabel, ul.sort, - Seq(NonTerminal(ul.sort), Terminal(ul.separator), NonTerminal(ul.childSort)), - newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList)); - prod2 = Production(Seq(), ul.sort, - Seq(NonTerminal(ul.childSort)), - newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList).add(Att.USER_LIST(), ul.klabel.name()).add(Att.USER_LIST_TERMINATOR(), ul.terminatorKLabel.name())); - prod3 = Production(ul.terminatorKLabel, Sort(ul.sort.name() + "#Terminator", ul.sort.params()), Seq(Terminal("")), - newAtts.remove(Att.FORMAT()).add(Att.ORIGINAL_PRD(), Production.class, ul.pTerminator)); - } else if (ul.leftAssoc) { - throw KEMException.compilerError("Cannot use List with --bison-lists", ul.pList); - } else { - // Es#Terminator ::= "" [klabel('.Es)] - prod1 = Production(ul.terminatorKLabel, Sort(ul.sort.name() + "#Terminator", ul.sort.params()), Seq(Terminal("")), - newAtts.remove(Att.FORMAT()).add(Att.ORIGINAL_PRD(), Production.class, ul.pTerminator)); - // Ne#Es ::= E "," Ne#Es [klabel('_,_)] - prod2 = Production(ul.klabel, Sort("Ne#" + ul.sort.name(), ul.sort.params()), - Seq(NonTerminal(ul.childSort), Terminal(ul.separator), NonTerminal(Sort("Ne#" + ul.sort.name(), ul.sort.params()))), - newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList)); - // Ne#Es ::= E "" Es#Terminator [klabel('_,_)] - prod3 = Production(ul.klabel, Sort("Ne#" + ul.sort.name(), ul.sort.params()), - Seq(NonTerminal(ul.childSort), Terminal(""), NonTerminal(Sort(ul.sort.name() + "#Terminator", ul.sort.params()))), - newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList)); - // Es ::= Ne#Es - prod4 = Production(Seq(), ul.sort, Seq(NonTerminal(Sort("Ne#" + ul.sort.name(), ul.sort.params()))), Att().add(Att.NOT_INJECTION())); - // Es ::= Es#Terminator // if the list is * - prod5 = Production(Seq(), ul.sort, Seq(NonTerminal(Sort(ul.sort.name() + "#Terminator", ul.sort.params()))), Att().add(Att.NOT_INJECTION())); - } - - res.add(prod1); - res.add(prod2); - res.add(prod3); - if (!ul.leftAssoc) { - res.add(prod4); - res.add(SyntaxSort(Seq(), Sort(ul.sort.name() + "#Terminator", ul.sort.params()))); - res.add(SyntaxSort(Seq(), Sort("Ne#" + ul.sort.name(), ul.sort.params()))); - if (!ul.nonEmpty) { - res.add(prod5); + else p = Production(p.params(), p.sort(), p.items(), p.att()); + return p; } - } - } - res.addAll(prods3.stream().filter(p -> !(p instanceof Production && (p.att().contains(Att.GENERATED_BY_LIST_SUBSORTING()) || p.att().contains(Att.USER_LIST())))).collect(Collectors.toSet())); - parseProds = res; - } + return s; + }) + .collect(Collectors.toSet()); + } - if (mod.importedModuleNames().contains(RULE_LISTS)) { - Set res = new HashSet<>(); - for (UserList ul : UserList.getLists(parseProds)) { - Production prod1; - // Es ::= E - prod1 = Production(Seq(), ul.sort, Seq(NonTerminal(ul.childSort))); - res.add(prod1); - } - - parseProds.addAll(res); - disambProds.addAll(res); + disambProds = parseProds.stream().collect(Collectors.toSet()); + if (mod.importedModuleNames().contains(PROGRAM_LISTS)) { + Set prods3 = new HashSet<>(); + // if no start symbol has been defined in the configuration, then use K + for (Sort srt : iterable(mod.allSorts())) { + if (!isParserSort(srt) && !mod.listSorts().contains(srt)) { + // K ::= Sort + prods3.add(Production(Seq(), Sorts.KItem(), Seq(NonTerminal(srt)), Att())); + } + } + // for each triple, generate a new pattern which works better for parsing lists in programs. + prods3.addAll(parseProds.stream().collect(Collectors.toSet())); + Set res = new HashSet<>(); + for (UserList ul : UserList.getLists(prods3)) { + Production prod1, prod2, prod3 = null, prod4 = null, prod5 = null; + + Att newAtts = ul.attrs.remove(Att.USER_LIST()); + if (ul.leftAssoc && ul.nonEmpty) { + prod1 = + Production( + ul.klabel, + ul.sort, + Seq(NonTerminal(ul.sort), Terminal(ul.separator), NonTerminal(ul.childSort)), + newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList)); + prod2 = + Production( + Seq(), + ul.sort, + Seq(NonTerminal(ul.childSort)), + newAtts + .add(Att.ORIGINAL_PRD(), Production.class, ul.pList) + .add(Att.USER_LIST(), ul.klabel.name()) + .add(Att.USER_LIST_TERMINATOR(), ul.terminatorKLabel.name())); + prod3 = + Production( + ul.terminatorKLabel, + Sort(ul.sort.name() + "#Terminator", ul.sort.params()), + Seq(Terminal("")), + newAtts + .remove(Att.FORMAT()) + .add(Att.ORIGINAL_PRD(), Production.class, ul.pTerminator)); + } else if (ul.leftAssoc) { + throw KEMException.compilerError("Cannot use List with --bison-lists", ul.pList); + } else { + // Es#Terminator ::= "" [klabel('.Es)] + prod1 = + Production( + ul.terminatorKLabel, + Sort(ul.sort.name() + "#Terminator", ul.sort.params()), + Seq(Terminal("")), + newAtts + .remove(Att.FORMAT()) + .add(Att.ORIGINAL_PRD(), Production.class, ul.pTerminator)); + // Ne#Es ::= E "," Ne#Es [klabel('_,_)] + prod2 = + Production( + ul.klabel, + Sort("Ne#" + ul.sort.name(), ul.sort.params()), + Seq( + NonTerminal(ul.childSort), + Terminal(ul.separator), + NonTerminal(Sort("Ne#" + ul.sort.name(), ul.sort.params()))), + newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList)); + // Ne#Es ::= E "" Es#Terminator [klabel('_,_)] + prod3 = + Production( + ul.klabel, + Sort("Ne#" + ul.sort.name(), ul.sort.params()), + Seq( + NonTerminal(ul.childSort), + Terminal(""), + NonTerminal(Sort(ul.sort.name() + "#Terminator", ul.sort.params()))), + newAtts.add(Att.ORIGINAL_PRD(), Production.class, ul.pList)); + // Es ::= Ne#Es + prod4 = + Production( + Seq(), + ul.sort, + Seq(NonTerminal(Sort("Ne#" + ul.sort.name(), ul.sort.params()))), + Att().add(Att.NOT_INJECTION())); + // Es ::= Es#Terminator // if the list is * + prod5 = + Production( + Seq(), + ul.sort, + Seq(NonTerminal(Sort(ul.sort.name() + "#Terminator", ul.sort.params()))), + Att().add(Att.NOT_INJECTION())); } - parseProds.addAll(recordProds); - Att att = mod.att(); - List notLrModules = stream(mod.importedModules()).filter(m -> m.att().contains(Att.NOT_LR1())).map(Module::name).collect(Collectors.toList()); - if (!notLrModules.isEmpty()) { - att = att.add(Att.NOT_LR1_MODULES(), notLrModules.toString()); + res.add(prod1); + res.add(prod2); + res.add(prod3); + if (!ul.leftAssoc) { + res.add(prod4); + res.add(SyntaxSort(Seq(), Sort(ul.sort.name() + "#Terminator", ul.sort.params()))); + res.add(SyntaxSort(Seq(), Sort("Ne#" + ul.sort.name(), ul.sort.params()))); + if (!ul.nonEmpty) { + res.add(prod5); + } } - Module extensionM = new Module(mod.name() + "-EXTENSION", Set(Import(origMod, true)), immutable(extensionProds), att); - Module disambM = new Module(mod.name() + "-DISAMB", Set(), immutable(disambProds), att); - Module parseM = new Module(mod.name() + "-PARSER", Set(), immutable(parseProds), att); - parseM.subsorts(); - return Tuple3.apply(extensionM, disambM, parseM); + } + res.addAll( + prods3.stream() + .filter( + p -> + !(p instanceof Production + && (p.att().contains(Att.GENERATED_BY_LIST_SUBSORTING()) + || p.att().contains(Att.USER_LIST())))) + .collect(Collectors.toSet())); + parseProds = res; } - private static final Pattern alphaNum = Pattern.compile("[A-Za-z][A-Za-z0-9\\-]*"); - - private static void addCellNameProd(Set prods, Sentence prod) { - if (prod instanceof Production) { - for (ProductionItem pi : iterable(((Production) prod).items())) { - if (pi instanceof Terminal t) { - if (alphaNum.matcher(t.value()).matches()) { - prods.add(Production(Seq(), Sorts.CellName(), Seq(t), Att().add(Att.TOKEN()))); - } - } - } - } + if (mod.importedModuleNames().contains(RULE_LISTS)) { + Set res = new HashSet<>(); + for (UserList ul : UserList.getLists(parseProds)) { + Production prod1; + // Es ::= E + prod1 = Production(Seq(), ul.sort, Seq(NonTerminal(ul.childSort))); + res.add(prod1); + } + + parseProds.addAll(res); + disambProds.addAll(res); } - private static Set makeCasts(Sort outerSort, Sort innerSort, Sort castSort, Sort labelSort) { - Set prods = new HashSet<>(); - Att attrs1 = Att().add(Sort.class, castSort); - prods.add(Production(KLabel("#SyntacticCast"), castSort, Seq(NonTerminal(labelSort), Terminal("::" + castSort.toString())), attrs1.add(Att.FORMAT(), "%1%2"))); - prods.add(Production(KLabel("#SemanticCastTo" + labelSort.toString()), labelSort, Seq(NonTerminal(labelSort), Terminal(":" + castSort)), attrs1.add(Att.FORMAT(), "%1%2"))); - prods.add(Production(KLabel("#InnerCast"), castSort, Seq(Terminal("{"), NonTerminal(labelSort), Terminal("}"), Terminal("<:" + castSort)), attrs1.add(Att.FORMAT(), "%1 %2 %3%4"))); - prods.add(Production(KLabel("#OuterCast"), labelSort, Seq(Terminal("{"), NonTerminal(innerSort), Terminal("}"), Terminal(":>" + castSort)), attrs1.add(Att.FORMAT(), "%1 %2 %3%4"))); - return prods; + parseProds.addAll(recordProds); + Att att = mod.att(); + List notLrModules = + stream(mod.importedModules()) + .filter(m -> m.att().contains(Att.NOT_LR1())) + .map(Module::name) + .collect(Collectors.toList()); + if (!notLrModules.isEmpty()) { + att = att.add(Att.NOT_LR1_MODULES(), notLrModules.toString()); + } + Module extensionM = + new Module( + mod.name() + "-EXTENSION", Set(Import(origMod, true)), immutable(extensionProds), att); + Module disambM = new Module(mod.name() + "-DISAMB", Set(), immutable(disambProds), att); + Module parseM = new Module(mod.name() + "-PARSER", Set(), immutable(parseProds), att); + parseM.subsorts(); + return Tuple3.apply(extensionM, disambM, parseM); + } + + private static final Pattern alphaNum = Pattern.compile("[A-Za-z][A-Za-z0-9\\-]*"); + + private static void addCellNameProd(Set prods, Sentence prod) { + if (prod instanceof Production) { + for (ProductionItem pi : iterable(((Production) prod).items())) { + if (pi instanceof Terminal t) { + if (alphaNum.matcher(t.value()).matches()) { + prods.add(Production(Seq(), Sorts.CellName(), Seq(t), Att().add(Att.TOKEN()))); + } + } + } } + } + + private static Set makeCasts( + Sort outerSort, Sort innerSort, Sort castSort, Sort labelSort) { + Set prods = new HashSet<>(); + Att attrs1 = Att().add(Sort.class, castSort); + prods.add( + Production( + KLabel("#SyntacticCast"), + castSort, + Seq(NonTerminal(labelSort), Terminal("::" + castSort.toString())), + attrs1.add(Att.FORMAT(), "%1%2"))); + prods.add( + Production( + KLabel("#SemanticCastTo" + labelSort.toString()), + labelSort, + Seq(NonTerminal(labelSort), Terminal(":" + castSort)), + attrs1.add(Att.FORMAT(), "%1%2"))); + prods.add( + Production( + KLabel("#InnerCast"), + castSort, + Seq(Terminal("{"), NonTerminal(labelSort), Terminal("}"), Terminal("<:" + castSort)), + attrs1.add(Att.FORMAT(), "%1 %2 %3%4"))); + prods.add( + Production( + KLabel("#OuterCast"), + labelSort, + Seq(Terminal("{"), NonTerminal(innerSort), Terminal("}"), Terminal(":>" + castSort)), + attrs1.add(Att.FORMAT(), "%1 %2 %3%4"))); + return prods; + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AddEmptyLists.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AddEmptyLists.java index f03c0439400..003d42404d7 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AddEmptyLists.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AddEmptyLists.java @@ -1,8 +1,21 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; import com.google.common.collect.Sets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.kframework.POSet; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; @@ -11,6 +24,7 @@ import org.kframework.definition.NonTerminal; import org.kframework.definition.Production; import org.kframework.definition.ProductionItem; +import org.kframework.definition.UserList; import org.kframework.kore.KLabel; import org.kframework.kore.Sort; import org.kframework.parser.Constant; @@ -18,7 +32,6 @@ import org.kframework.parser.SetsGeneralTransformer; import org.kframework.parser.Term; import org.kframework.parser.TermCons; -import org.kframework.definition.UserList; import org.kframework.utils.errorsystem.KEMException; import org.pcollections.ConsPStack; import scala.Tuple2; @@ -26,235 +39,268 @@ import scala.util.Left; import scala.util.Right; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.kframework.kore.KORE.*; -import static org.kframework.Collections.*; - -/** - * Transformer class adding the implicit terminator (.List{""}) to user defined lists. - */ +/** Transformer class adding the implicit terminator (.List{""}) to user defined lists. */ public class AddEmptyLists extends SetsGeneralTransformer { - private final Module m; - private final POSet subsorts; - private final scala.collection.Set listSorts; - private final Map> lists; - private final AddSortInjections inj; - private Sort expectedSort; + private final Module m; + private final POSet subsorts; + private final scala.collection.Set listSorts; + private final Map> lists; + private final AddSortInjections inj; + private Sort expectedSort; - public AddEmptyLists(Module m, Sort expectedSort) { - this.m = m; - subsorts = m.subsorts(); - listSorts = m.listSorts(); - lists = UserList.getLists(mutable(m.sentences())).stream().collect(Collectors.groupingBy(p -> p.sort)); - inj = new AddSortInjections(m); - this.expectedSort = expectedSort; - } + public AddEmptyLists(Module m, Sort expectedSort) { + this.m = m; + subsorts = m.subsorts(); + listSorts = m.listSorts(); + lists = + UserList.getLists(mutable(m.sentences())).stream() + .collect(Collectors.groupingBy(p -> p.sort)); + inj = new AddSortInjections(m); + this.expectedSort = expectedSort; + } - // instead of calling super.apply in the apply function below, we should - // call this function, because super.apply does not correctly set the - // expected sort before recursing, which means that we end up with - // the wrong sort computations otherwise - private Tuple2, Term>, Set> superApply(TermCons tc) { - Set warns = new HashSet<>(); - TermCons orig = tc; - Production p = inj.substituteProd(orig.production(), expectedSort, (i, fresh) -> getSort((ProductionReference)orig.get(i), fresh.nonterminals().apply(i).sort()), orig); - for (int i = 0; i < tc.items().size(); i++) { - Sort oldExpectedSort = expectedSort; - expectedSort = p.nonterminals().apply(i).sort(); - Tuple2, Term>, Set> rez = apply(tc.get(i)); - warns.addAll(rez._2()); - if (rez._1().isLeft()) { - return Tuple2.apply(rez._1(), warns); - } - tc = tc.with(i, rez._1().right().get()); - expectedSort = oldExpectedSort; - } - return Tuple2.apply(Right.apply(tc), warns); + // instead of calling super.apply in the apply function below, we should + // call this function, because super.apply does not correctly set the + // expected sort before recursing, which means that we end up with + // the wrong sort computations otherwise + private Tuple2, Term>, Set> superApply(TermCons tc) { + Set warns = new HashSet<>(); + TermCons orig = tc; + Production p = + inj.substituteProd( + orig.production(), + expectedSort, + (i, fresh) -> + getSort((ProductionReference) orig.get(i), fresh.nonterminals().apply(i).sort()), + orig); + for (int i = 0; i < tc.items().size(); i++) { + Sort oldExpectedSort = expectedSort; + expectedSort = p.nonterminals().apply(i).sort(); + Tuple2, Term>, Set> rez = apply(tc.get(i)); + warns.addAll(rez._2()); + if (rez._1().isLeft()) { + return Tuple2.apply(rez._1(), warns); + } + tc = tc.with(i, rez._1().right().get()); + expectedSort = oldExpectedSort; } + return Tuple2.apply(Right.apply(tc), warns); + } - @Override - public Tuple2, Term>, Set> apply(TermCons tc) { - TermCons orig = tc; - Production p = inj.substituteProd(orig.production(), expectedSort, (i, fresh) -> getSort((ProductionReference)orig.get(i), fresh.nonterminals().apply(i).sort()), orig); - java.util.Set warnings = new HashSet<>(); - - List reversed = tc.items().stream().collect(Collectors.toList()); - Collections.reverse(reversed); // TermCons with PStack requires the elements to be in the reverse order - Iterator items = reversed.iterator(); - List newItems = new LinkedList<>(); - boolean changed = false; + @Override + public Tuple2, Term>, Set> apply(TermCons tc) { + TermCons orig = tc; + Production p = + inj.substituteProd( + orig.production(), + expectedSort, + (i, fresh) -> + getSort((ProductionReference) orig.get(i), fresh.nonterminals().apply(i).sort()), + orig); + java.util.Set warnings = new HashSet<>(); - if (tc.production().klabel().isDefined()) { - final String tcLabelName = tc.production().klabel().get().name(); - // Never add a list wrapper between a sort annotation and the annotated term - if (tcLabelName.equals("#SyntacticCast") - || tcLabelName.startsWith("#SemanticCastTo") - || tcLabelName.equals("#InnerCast")) { - return superApply(tc); - } - } + List reversed = tc.items().stream().collect(Collectors.toList()); + Collections.reverse( + reversed); // TermCons with PStack requires the elements to be in the reverse order + Iterator items = reversed.iterator(); + List newItems = new LinkedList<>(); + boolean changed = false; - for (ProductionItem pi : mutable(p.items())) { - if (!(pi instanceof NonTerminal)) - continue; - Sort oldExpectedSort = expectedSort; - expectedSort = ((NonTerminal)pi).sort(); - ProductionReference child = (ProductionReference) items.next(); - Sort childSort = getSort(child, expectedSort); - if (listSorts.contains(expectedSort) && - !(subsorts.lessThanEq(childSort, expectedSort) && listSorts.contains(childSort))) { - final boolean isBracket = child.production().att().contains(Att.BRACKET()); - if (isBracket) { - newItems.add(child); - } else if (childSort.equals(Sorts.K()) || !subsorts.lessThan(childSort, expectedSort)) { - newItems.add(child); - } else { - Set least = subsorts.minimal(stream(listSorts).filter(s -> subsorts.greaterThanEq(lists.get(s).get(0).childSort, childSort) && subsorts.lessThanEq(s, expectedSort)).collect(Collectors.toList())); - if (least.size() != 1) { - String msg = "Overloaded term does not have a least sort. Possible sorts: " + least; - return new Tuple2<>(Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))), warnings); - } - UserList ul = lists.get(least.iterator().next()).get(0); - Set leastTerm = subsorts.minimal(stream(listSorts).filter(s -> subsorts.lessThanEq(s, expectedSort)).collect(Collectors.toList())); - if (leastTerm.size() != 1) { - String msg = "List terminator for overloaded term does not have a least sort. Possible sorts: " + leastTerm; - return new Tuple2<>(Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))), warnings); - } - UserList ulTerm = lists.get(leastTerm.iterator().next()).get(0); - TermCons terminator = TermCons.apply(ConsPStack.empty(), ulTerm.pTerminator, child.location(), child.source()); - // TermCons with PStack requires the elements to be in the reverse order - TermCons newTc; - if (ul.leftAssoc) { - newTc = TermCons.apply(ConsPStack.from(Arrays.asList(child, terminator)), ul.pList, child.location(), child.source()); - } else { - newTc = TermCons.apply(ConsPStack.from(Arrays.asList(terminator, child)), ul.pList, child.location(), child.source()); - } - newItems.add(newTc); - changed = true; - } - } else { - newItems.add(child); - } - expectedSort = oldExpectedSort; - } + if (tc.production().klabel().isDefined()) { + final String tcLabelName = tc.production().klabel().get().name(); + // Never add a list wrapper between a sort annotation and the annotated term + if (tcLabelName.equals("#SyntacticCast") + || tcLabelName.startsWith("#SemanticCastTo") + || tcLabelName.equals("#InnerCast")) { + return superApply(tc); + } + } - if (changed) { - Collections.reverse(newItems); // TermCons with PStack requires the elements to be in the reverse order - tc = TermCons.apply(ConsPStack.from(newItems), tc.production(), tc.location(), tc.source()); - } - if (!warnings.isEmpty()) { - Tuple2, Term>, Set> rez = superApply(tc); - return new Tuple2<>(Right.apply(rez._1().right().get()), Sets.union(warnings, rez._2())); + for (ProductionItem pi : mutable(p.items())) { + if (!(pi instanceof NonTerminal)) continue; + Sort oldExpectedSort = expectedSort; + expectedSort = ((NonTerminal) pi).sort(); + ProductionReference child = (ProductionReference) items.next(); + Sort childSort = getSort(child, expectedSort); + if (listSorts.contains(expectedSort) + && !(subsorts.lessThanEq(childSort, expectedSort) && listSorts.contains(childSort))) { + final boolean isBracket = child.production().att().contains(Att.BRACKET()); + if (isBracket) { + newItems.add(child); + } else if (childSort.equals(Sorts.K()) || !subsorts.lessThan(childSort, expectedSort)) { + newItems.add(child); } else { - return superApply(tc); + Set least = + subsorts.minimal( + stream(listSorts) + .filter( + s -> + subsorts.greaterThanEq(lists.get(s).get(0).childSort, childSort) + && subsorts.lessThanEq(s, expectedSort)) + .collect(Collectors.toList())); + if (least.size() != 1) { + String msg = "Overloaded term does not have a least sort. Possible sorts: " + least; + return new Tuple2<>( + Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))), warnings); + } + UserList ul = lists.get(least.iterator().next()).get(0); + Set leastTerm = + subsorts.minimal( + stream(listSorts) + .filter(s -> subsorts.lessThanEq(s, expectedSort)) + .collect(Collectors.toList())); + if (leastTerm.size() != 1) { + String msg = + "List terminator for overloaded term does not have a least sort. Possible sorts: " + + leastTerm; + return new Tuple2<>( + Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))), warnings); + } + UserList ulTerm = lists.get(leastTerm.iterator().next()).get(0); + TermCons terminator = + TermCons.apply( + ConsPStack.empty(), ulTerm.pTerminator, child.location(), child.source()); + // TermCons with PStack requires the elements to be in the reverse order + TermCons newTc; + if (ul.leftAssoc) { + newTc = + TermCons.apply( + ConsPStack.from(Arrays.asList(child, terminator)), + ul.pList, + child.location(), + child.source()); + } else { + newTc = + TermCons.apply( + ConsPStack.from(Arrays.asList(terminator, child)), + ul.pList, + child.location(), + child.source()); + } + newItems.add(newTc); + changed = true; } + } else { + newItems.add(child); + } + expectedSort = oldExpectedSort; } - private Sort getSort(ProductionReference child, Sort expectedSort) { - if (m.syntacticSubsorts().greaterThan(expectedSort, Sorts.K())) { - expectedSort = Sorts.K(); - } - return inj.substituteProd(child.production(), expectedSort, (i, fresh) -> getSort((ProductionReference)((TermCons)child).get(i), fresh.nonterminals().apply(i).sort()), child).sort(); + if (changed) { + Collections.reverse( + newItems); // TermCons with PStack requires the elements to be in the reverse order + tc = TermCons.apply(ConsPStack.from(newItems), tc.production(), tc.location(), tc.source()); } + if (!warnings.isEmpty()) { + Tuple2, Term>, Set> rez = superApply(tc); + return new Tuple2<>(Right.apply(rez._1().right().get()), Sets.union(warnings, rez._2())); + } else { + return superApply(tc); + } + } - /** - * Returns an element of sorts which is related to and no - * greater than every other element of sorts, if any exists. - */ - private Optional least(Iterable sorts) { - Iterator iter = sorts.iterator(); - if (!iter.hasNext()) { - return Optional.empty(); - } - Sort min = iter.next(); - while (iter.hasNext()) { - Sort next = iter.next(); - if (!subsorts.lessThanEq(min, next)) { - // if min is unrelated to next, it can't be the least sort so - // we also might as well switch - min = next; - } - } - for (Sort s : sorts) { - if (!subsorts.lessThanEq(min, s)) { - return Optional.empty(); - } - } - return Optional.of(min); + private Sort getSort(ProductionReference child, Sort expectedSort) { + if (m.syntacticSubsorts().greaterThan(expectedSort, Sorts.K())) { + expectedSort = Sorts.K(); } + return inj.substituteProd( + child.production(), + expectedSort, + (i, fresh) -> + getSort( + (ProductionReference) ((TermCons) child).get(i), + fresh.nonterminals().apply(i).sort()), + child) + .sort(); + } - /** - * Returns an element of sorts which is related to and no - * less than every other element of sorts, if any exists. - */ - private Optional greatest(Iterable sorts) { - Iterator iter = sorts.iterator(); - if (!iter.hasNext()) { - return Optional.empty(); - } - Sort max = iter.next(); - while (iter.hasNext()) { - Sort next = iter.next(); - if (!subsorts.greaterThanEq(max, next)) { - // if min is unrelated to next, it can't be the least sort so - // we also might as well switch - max = next; - } - } - for (Sort s : sorts) { - if (!subsorts.greaterThanEq(max, s)) { - return Optional.empty(); - } - } - return Optional.of(max); + /** + * Returns an element of sorts which is related to and no greater than every other element of + * sorts, if any exists. + */ + private Optional least(Iterable sorts) { + Iterator iter = sorts.iterator(); + if (!iter.hasNext()) { + return Optional.empty(); + } + Sort min = iter.next(); + while (iter.hasNext()) { + Sort next = iter.next(); + if (!subsorts.lessThanEq(min, next)) { + // if min is unrelated to next, it can't be the least sort so + // we also might as well switch + min = next; + } + } + for (Sort s : sorts) { + if (!subsorts.lessThanEq(min, s)) { + return Optional.empty(); + } } + return Optional.of(min); + } - private Optional klabelFromTerm(Term labelTerm) { - if (labelTerm instanceof Constant labelCon) { - if (labelCon.production().sort().equals(Sorts.KLabel())) { - String labelVal = labelCon.value(); - if (labelVal.charAt(0) == '`') { - return Optional.of(KLabel(labelVal.substring(1, labelVal.length() - 1))); - } else { - return Optional.of(KLabel(labelVal)); - } - } - } + /** + * Returns an element of sorts which is related to and no less than every other element of sorts, + * if any exists. + */ + private Optional greatest(Iterable sorts) { + Iterator iter = sorts.iterator(); + if (!iter.hasNext()) { + return Optional.empty(); + } + Sort max = iter.next(); + while (iter.hasNext()) { + Sort next = iter.next(); + if (!subsorts.greaterThanEq(max, next)) { + // if min is unrelated to next, it can't be the least sort so + // we also might as well switch + max = next; + } + } + for (Sort s : sorts) { + if (!subsorts.greaterThanEq(max, s)) { return Optional.empty(); + } } + return Optional.of(max); + } - private List lowerKList(Term listTerm) { - List items = new ArrayList<>(); - lowerKListAcc(listTerm, items); - return items; + private Optional klabelFromTerm(Term labelTerm) { + if (labelTerm instanceof Constant labelCon) { + if (labelCon.production().sort().equals(Sorts.KLabel())) { + String labelVal = labelCon.value(); + if (labelVal.charAt(0) == '`') { + return Optional.of(KLabel(labelVal.substring(1, labelVal.length() - 1))); + } else { + return Optional.of(KLabel(labelVal)); + } + } } + return Optional.empty(); + } + + private List lowerKList(Term listTerm) { + List items = new ArrayList<>(); + lowerKListAcc(listTerm, items); + return items; + } - private void lowerKListAcc(Term term, List items) { - if (term instanceof TermCons cons) { - if (cons.production().klabel().isDefined()) { - String labelName = cons.production().klabel().get().name(); - if (labelName.equals("#KList")) { - assert cons.items().size() == 2; - lowerKListAcc(cons.get(0), items); - lowerKListAcc(cons.get(1), items); - return; - } else if (labelName.equals("#EmptyKList")) { - return; - } - } + private void lowerKListAcc(Term term, List items) { + if (term instanceof TermCons cons) { + if (cons.production().klabel().isDefined()) { + String labelName = cons.production().klabel().get().name(); + if (labelName.equals("#KList")) { + assert cons.items().size() == 2; + lowerKListAcc(cons.get(0), items); + lowerKListAcc(cons.get(1), items); + return; + } else if (labelName.equals("#EmptyKList")) { + return; } - items.add(term); + } } + items.add(term); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilter.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilter.java index a934b9bca59..9ed5c7e2b33 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilter.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilter.java @@ -1,6 +1,7 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import java.util.Set; import org.kframework.kore.K; import org.kframework.parser.Ambiguity; import org.kframework.parser.ProductionReference; @@ -13,55 +14,54 @@ import scala.util.Either; import scala.util.Right; -import java.util.Set; - -/** - * Eliminate remaining ambiguities by choosing one of them. - */ +/** Eliminate remaining ambiguities by choosing one of them. */ public class AmbFilter extends SetsGeneralTransformer { - private final boolean strict; + private final boolean strict; - public AmbFilter(boolean strict) { - this.strict = strict; - } + public AmbFilter(boolean strict) { + this.strict = strict; + } - @Override - public Tuple2, Term>, Set> apply(Ambiguity amb) { - K last = null; - boolean equal = true; - Tuple2, Term>, Set> candidate = null; - for (Term t : amb.items()) { - candidate = this.apply(t); - K next = new TreeNodesToKORE(Outer::parseSort, strict).apply(new RemoveBracketVisitor().apply(candidate._1().right().get())); - if (last != null) { - if (!last.equals(next)) { - equal = false; - break; - } - } - last = next; - } - if(equal) { - // all ambiguities have the same abstract syntax, so just pick one - return candidate; + @Override + public Tuple2, Term>, Set> apply(Ambiguity amb) { + K last = null; + boolean equal = true; + Tuple2, Term>, Set> candidate = null; + for (Term t : amb.items()) { + candidate = this.apply(t); + K next = + new TreeNodesToKORE(Outer::parseSort, strict) + .apply(new RemoveBracketVisitor().apply(candidate._1().right().get())); + if (last != null) { + if (!last.equals(next)) { + equal = false; + break; } + } + last = next; + } + if (equal) { + // all ambiguities have the same abstract syntax, so just pick one + return candidate; + } - String msg = "Parsing ambiguity. Arbitrarily choosing the first."; + String msg = "Parsing ambiguity. Arbitrarily choosing the first."; - for (int i = 0; i < amb.items().size(); i++) { - msg += "\n" + (i + 1) + ": "; - Term elem = (Term) amb.items().toArray()[i]; - if (elem instanceof ProductionReference tc) { - msg += tc.production().toString(); - } - // TODO: use the unparser - //Unparser unparser = new Unparser(context); - //msg += "\n " + unparser.print(elem).replace("\n", "\n "); - msg += "\n " + new RemoveBracketVisitor().apply(elem); - } - // TODO: add location information - Tuple2, Term>, Set> rez = this.apply(amb.items().iterator().next()); - return new Tuple2<>(Right.apply(rez._1().right().get()), rez._2()); + for (int i = 0; i < amb.items().size(); i++) { + msg += "\n" + (i + 1) + ": "; + Term elem = (Term) amb.items().toArray()[i]; + if (elem instanceof ProductionReference tc) { + msg += tc.production().toString(); + } + // TODO: use the unparser + // Unparser unparser = new Unparser(context); + // msg += "\n " + unparser.print(elem).replace("\n", "\n "); + msg += "\n " + new RemoveBracketVisitor().apply(elem); } + // TODO: add location information + Tuple2, Term>, Set> rez = + this.apply(amb.items().iterator().next()); + return new Tuple2<>(Right.apply(rez._1().right().get()), rez._2()); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilterError.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilterError.java index 2d09a1612c3..033f8373595 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilterError.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/AmbFilterError.java @@ -2,6 +2,7 @@ package org.kframework.parser.inner.disambiguation; import com.google.common.collect.Sets; +import java.util.Set; import org.kframework.kore.K; import org.kframework.parser.Ambiguity; import org.kframework.parser.ProductionReference; @@ -13,59 +14,57 @@ import scala.util.Either; import scala.util.Left; -import java.util.Set; - -/** - * Report remaining ambiguities as errors. - */ +/** Report remaining ambiguities as errors. */ public class AmbFilterError extends SetsTransformerWithErrors { - private final boolean strict; + private final boolean strict; - public AmbFilterError(boolean strict) { - this.strict = strict; - } + public AmbFilterError(boolean strict) { + this.strict = strict; + } - @Override - public Either, Term> apply(Ambiguity amb) { - K last = null; - boolean equal = true; - Either, Term> candidate = null; - for (Term t : amb.items()) { - candidate = this.apply(t); - if (candidate.isLeft()) { - return candidate; - } - K next = new TreeNodesToKORE(Outer::parseSort, strict).apply(new RemoveBracketVisitor().apply(candidate.right().get())); - if (last != null) { - if (!last.equals(next)) { - equal = false; - break; - } - } - last = next; - } - if(equal) { - // all ambiguities have the same abstract syntax, so just pick one - return candidate; + @Override + public Either, Term> apply(Ambiguity amb) { + K last = null; + boolean equal = true; + Either, Term> candidate = null; + for (Term t : amb.items()) { + candidate = this.apply(t); + if (candidate.isLeft()) { + return candidate; + } + K next = + new TreeNodesToKORE(Outer::parseSort, strict) + .apply(new RemoveBracketVisitor().apply(candidate.right().get())); + if (last != null) { + if (!last.equals(next)) { + equal = false; + break; } + } + last = next; + } + if (equal) { + // all ambiguities have the same abstract syntax, so just pick one + return candidate; + } - String msg = "Parsing ambiguity."; + String msg = "Parsing ambiguity."; - for (int i = 0; i < amb.items().size(); i++) { - msg += "\n" + (i + 1) + ": "; - Term elem = (Term) amb.items().toArray()[i]; - if (elem instanceof ProductionReference tc) { - msg += tc.production().toString(); - } - // TODO: use the unparser - //Unparser unparser = new Unparser(context); - //msg += "\n " + unparser.print(elem).replace("\n", "\n "); - msg += "\n " + new RemoveBracketVisitor().apply(elem); - } + for (int i = 0; i < amb.items().size(); i++) { + msg += "\n" + (i + 1) + ": "; + Term elem = (Term) amb.items().toArray()[i]; + if (elem instanceof ProductionReference tc) { + msg += tc.production().toString(); + } + // TODO: use the unparser + // Unparser unparser = new Unparser(context); + // msg += "\n " + unparser.print(elem).replace("\n", "\n "); + msg += "\n " + new RemoveBracketVisitor().apply(elem); + } - KEMException e = KEMException.innerParserError(msg, amb.items().iterator().next()); + KEMException e = KEMException.innerParserError(msg, amb.items().iterator().next()); - return Left.apply(Sets.newHashSet(e)); - } + return Left.apply(Sets.newHashSet(e)); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/CollapseRecordProdsVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/CollapseRecordProdsVisitor.java index 67c26931f81..62603af5695 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/CollapseRecordProdsVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/CollapseRecordProdsVisitor.java @@ -1,7 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; + import com.google.common.collect.Sets; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.definition.NonTerminal; @@ -18,86 +24,91 @@ import scala.util.Either; import scala.util.Left; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import static org.kframework.Collections.*; - /** - * Collapse the record productions from a cons list to a single term with all parameters. - * Expecting the exact pattern of productions described in Production.recordProductions() + * Collapse the record productions from a cons list to a single term with all parameters. Expecting + * the exact pattern of productions described in Production.recordProductions() */ public class CollapseRecordProdsVisitor extends SetsTransformerWithErrors { - CollectVariableNames varNamesVis; - // require the term before starting the visitor to make sure we generate unique variable names - public CollapseRecordProdsVisitor(Term t) { - varNamesVis = new CollectVariableNames(); - varNamesVis.apply(t); - } + CollectVariableNames varNamesVis; - @Override - public Either, Term> apply(TermCons tc) { - if (tc.production().att().contains(Att.RECORD_PRD(), Production.class)) { - Production origPrd = tc.production().att().get(Att.RECORD_PRD(), Production.class); - Map children = new HashMap<>(); - TermCons iterator = tc; + // require the term before starting the visitor to make sure we generate unique variable names + public CollapseRecordProdsVisitor(Term t) { + varNamesVis = new CollectVariableNames(); + varNamesVis.apply(t); + } - // find all named items - while (iterator != null && iterator.production().att().contains(Att.RECORD_PRD(), Production.class)) { - if (iterator.production().att().contains(Att.RECORD_PRD_MAIN())) - iterator = (TermCons) iterator.get(0); - else if (iterator.production().att().contains(Att.RECORD_PRD_ONE())) { - String key = iterator.production().att().get(Att.RECORD_PRD_ONE()); - children.put(key, iterator.get(0)); - iterator = null; - } else if (iterator.production().att().contains(Att.RECORD_PRD_ITEM())) { - String key = iterator.production().att().get(Att.RECORD_PRD_ITEM()); - if (children.containsKey(key)) - return Left.apply(Sets.newHashSet(KEMException.innerParserError("Duplicate record production key: " + key, tc))); - else - children.put(key, iterator.get(0)); - iterator = null; - } else if (iterator.production().att().contains(Att.RECORD_PRD_REPEAT())) { - TermCons item = (TermCons) iterator.get(1); - String key = item.production().att().get(Att.RECORD_PRD_ITEM()); - if (children.containsKey(key)) - return Left.apply(Sets.newHashSet(KEMException.innerParserError("Duplicate record production key: " + key, tc))); - else - children.put(key, item.get(0)); - iterator = (TermCons) iterator.get(0); - } else - iterator = null; - } - // construct expanded term with provided items and anonymous variables for missing ones - PStack collapsedItems = ConsPStack.empty(); - for (NonTerminal nt : mutable(origPrd.nonterminals())) { - if (nt.name().isDefined() && children.containsKey(nt.name().get())) - collapsedItems = collapsedItems.plus(children.get(nt.name().get())); - else { - Production anonVarPrd = Production.apply(Seq(), Sorts.KVariable(), Seq(Terminal.apply("_[A-Z][A-Za-z0-9'_]*")), Att.empty()); - // The name is required so disambiguation doesn't collapse the variables into the same term. - String varName; - do { varName = "_" + nt.name().getOrElse(() -> "Gen") + uid++; } while (varNamesVis.varNames.contains(varName)); - collapsedItems = collapsedItems.plus(Constant.apply(varName, anonVarPrd, tc.location(), tc.source())); - } - } - TermCons collapsed = TermCons.apply(collapsedItems, origPrd, tc.location(), tc.source()); - return super.apply(collapsed); + @Override + public Either, Term> apply(TermCons tc) { + if (tc.production().att().contains(Att.RECORD_PRD(), Production.class)) { + Production origPrd = tc.production().att().get(Att.RECORD_PRD(), Production.class); + Map children = new HashMap<>(); + TermCons iterator = tc; + + // find all named items + while (iterator != null + && iterator.production().att().contains(Att.RECORD_PRD(), Production.class)) { + if (iterator.production().att().contains(Att.RECORD_PRD_MAIN())) + iterator = (TermCons) iterator.get(0); + else if (iterator.production().att().contains(Att.RECORD_PRD_ONE())) { + String key = iterator.production().att().get(Att.RECORD_PRD_ONE()); + children.put(key, iterator.get(0)); + iterator = null; + } else if (iterator.production().att().contains(Att.RECORD_PRD_ITEM())) { + String key = iterator.production().att().get(Att.RECORD_PRD_ITEM()); + if (children.containsKey(key)) + return Left.apply( + Sets.newHashSet( + KEMException.innerParserError("Duplicate record production key: " + key, tc))); + else children.put(key, iterator.get(0)); + iterator = null; + } else if (iterator.production().att().contains(Att.RECORD_PRD_REPEAT())) { + TermCons item = (TermCons) iterator.get(1); + String key = item.production().att().get(Att.RECORD_PRD_ITEM()); + if (children.containsKey(key)) + return Left.apply( + Sets.newHashSet( + KEMException.innerParserError("Duplicate record production key: " + key, tc))); + else children.put(key, item.get(0)); + iterator = (TermCons) iterator.get(0); + } else iterator = null; + } + // construct expanded term with provided items and anonymous variables for missing ones + PStack collapsedItems = ConsPStack.empty(); + for (NonTerminal nt : mutable(origPrd.nonterminals())) { + if (nt.name().isDefined() && children.containsKey(nt.name().get())) + collapsedItems = collapsedItems.plus(children.get(nt.name().get())); + else { + Production anonVarPrd = + Production.apply( + Seq(), + Sorts.KVariable(), + Seq(Terminal.apply("_[A-Z][A-Za-z0-9'_]*")), + Att.empty()); + // The name is required so disambiguation doesn't collapse the variables into the same + // term. + String varName; + do { + varName = "_" + nt.name().getOrElse(() -> "Gen") + uid++; + } while (varNamesVis.varNames.contains(varName)); + collapsedItems = + collapsedItems.plus(Constant.apply(varName, anonVarPrd, tc.location(), tc.source())); } - return super.apply(tc); + } + TermCons collapsed = TermCons.apply(collapsedItems, origPrd, tc.location(), tc.source()); + return super.apply(collapsed); } + return super.apply(tc); + } - private int uid = 0; + private int uid = 0; - private static class CollectVariableNames extends SafeTransformer { - public Set varNames = new HashSet<>(); - @Override - public Term apply(Constant c) { - if (c.production().sort().equals(Sorts.KVariable())) - varNames.add(c.value()); - return super.apply(c); - } + private static class CollectVariableNames extends SafeTransformer { + public Set varNames = new HashSet<>(); + + @Override + public Term apply(Constant c) { + if (c.production().sort().equals(Sorts.KVariable())) varNames.add(c.value()); + return super.apply(c); } + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/KAppToTermConsVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/KAppToTermConsVisitor.java index fc09bb686f9..df5d928f050 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/KAppToTermConsVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/KAppToTermConsVisitor.java @@ -1,8 +1,17 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Lists; import com.google.common.collect.Sets; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; @@ -21,94 +30,110 @@ import scala.util.Either; import scala.util.Left; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - - /** - * Transform the KApps found in a term into the corresponding TermCons so type checking and - * variable type inference takes place correctly. Must be applied between type inference and - * priority filter. + * Transform the KApps found in a term into the corresponding TermCons so type checking and variable + * type inference takes place correctly. Must be applied between type inference and priority filter. */ public class KAppToTermConsVisitor extends SetsTransformerWithErrors { - private final Module mod; + private final Module mod; - public KAppToTermConsVisitor(Module mod) { - super(); - this.mod = mod; - } + public KAppToTermConsVisitor(Module mod) { + super(); + this.mod = mod; + } - @Override - public Either, Term> apply(TermCons tc) { - assert tc.production() != null : this.getClass() + ":" + " production not found." + tc; - if (tc.production().klabel().isDefined() && tc.production().klabel().get().equals(KLabels.KAPP)) { - if (!(tc.get(0) instanceof Constant kl) || !((Constant) tc.get(0)).production().sort().equals(Sorts.KLabel())) - // TODO: remove check once the java backend is no longer supported. - return super.apply(tc); // don't do anything if the label is not a token KLabel (in case of variable or casted variable) - String klvalue = kl.value(); - try { klvalue = StringUtil.unescapeKoreKLabel(kl.value()); } catch (IllegalArgumentException e) { /* ignore */ } // if possible, unescape - Set prods = mutable(mod.productionsFor().get(KLabel(klvalue)) - .getOrElse(Set$.MODULE$::emptyInstance).toSet()); - Set sol = new HashSet<>(); - Term t = new PushTopAmbiguityUp2().apply(tc.get(1)); - Stream uppedAmb = t instanceof Ambiguity ? ((Ambiguity) t).items().stream() : Lists.newArrayList(t).stream(); - Map>> flattKLists = uppedAmb - .map(KAppToTermConsVisitor::flattenKList) - .collect(Collectors.groupingBy(PStack::size)); - for (Production prd : prods) - for (PStack terms : flattKLists.getOrDefault(prd.arity(), Lists.newArrayList())) - sol.add(TermCons.apply(terms, prd, tc.location(), tc.source())); + @Override + public Either, Term> apply(TermCons tc) { + assert tc.production() != null : this.getClass() + ":" + " production not found." + tc; + if (tc.production().klabel().isDefined() + && tc.production().klabel().get().equals(KLabels.KAPP)) { + if (!(tc.get(0) instanceof Constant kl) + || !((Constant) tc.get(0)).production().sort().equals(Sorts.KLabel())) + // TODO: remove check once the java backend is no longer supported. + return super.apply( + tc); // don't do anything if the label is not a token KLabel (in case of variable or + // casted variable) + String klvalue = kl.value(); + try { + klvalue = StringUtil.unescapeKoreKLabel(kl.value()); + } catch (IllegalArgumentException e) { + /* ignore */ + } // if possible, unescape + Set prods = + mutable( + mod.productionsFor() + .get(KLabel(klvalue)) + .getOrElse(Set$.MODULE$::emptyInstance) + .toSet()); + Set sol = new HashSet<>(); + Term t = new PushTopAmbiguityUp2().apply(tc.get(1)); + Stream uppedAmb = + t instanceof Ambiguity + ? ((Ambiguity) t).items().stream() + : Lists.newArrayList(t).stream(); + Map>> flattKLists = + uppedAmb + .map(KAppToTermConsVisitor::flattenKList) + .collect(Collectors.groupingBy(PStack::size)); + for (Production prd : prods) + for (PStack terms : flattKLists.getOrDefault(prd.arity(), Lists.newArrayList())) + sol.add(TermCons.apply(terms, prd, tc.location(), tc.source())); - if (sol.size() == 0) { - String msg = "Could not find any suitable production for label " + kl.value(); - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, kl))); - } else if (sol.size() == 1) { - return super.apply(sol.iterator().next()); - } else - return super.apply(Ambiguity.apply(sol, tc.location(), tc.source())); - } - return super.apply(tc); + if (sol.size() == 0) { + String msg = "Could not find any suitable production for label " + kl.value(); + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, kl))); + } else if (sol.size() == 1) { + return super.apply(sol.iterator().next()); + } else return super.apply(Ambiguity.apply(sol, tc.location(), tc.source())); } + return super.apply(tc); + } - /** Recurse under #KList and flatten all the terms */ - private static PStack flattenKList(Term t) { - if (t instanceof Ambiguity) { - assert false : KAppToTermConsVisitor.class + " expected all ambiguities to already be pushed to the top:\n" + - " Source: " + ((Ambiguity) t).items().iterator().next().source().orElse(null) + "\n" + - " Location: " + ((Ambiguity) t).items().iterator().next().location().orElse(null); - } else if (t instanceof TermCons tc) { - if (tc.production().klabel().isDefined() && tc.production().klabel().get().equals(KLabels.KLIST)) - return flattenKList(tc.get(0)).plusAll(Lists.reverse(Lists.newArrayList(flattenKList(tc.get(1))))); - else if (tc.production().klabel().isDefined() && tc.production().klabel().get().equals(KLabels.EMPTYKLIST)) - return ConsPStack.empty(); - } - return ConsPStack.singleton(t); + /** Recurse under #KList and flatten all the terms */ + private static PStack flattenKList(Term t) { + if (t instanceof Ambiguity) { + assert false + : KAppToTermConsVisitor.class + + " expected all ambiguities to already be pushed to the top:\n" + + " Source: " + + ((Ambiguity) t).items().iterator().next().source().orElse(null) + + "\n" + + " Location: " + + ((Ambiguity) t).items().iterator().next().location().orElse(null); + } else if (t instanceof TermCons tc) { + if (tc.production().klabel().isDefined() + && tc.production().klabel().get().equals(KLabels.KLIST)) + return flattenKList(tc.get(0)) + .plusAll(Lists.reverse(Lists.newArrayList(flattenKList(tc.get(1))))); + else if (tc.production().klabel().isDefined() + && tc.production().klabel().get().equals(KLabels.EMPTYKLIST)) return ConsPStack.empty(); } + return ConsPStack.singleton(t); + } - // push ambiguities top so we can get easy access to KList - private static class PushTopAmbiguityUp2 extends SafeTransformer { - @Override - public Term apply(TermCons tc) { - if (tc.production().klabel().isDefined() && tc.production().klabel().get().head().equals(KLabels.KLIST)) { - Term v0 = super.apply(tc.get(0)); - Term v1 = super.apply(tc.get(1)); - Set t0 = v0 instanceof Ambiguity ? ((Ambiguity) v0).items() : Sets.newHashSet(v0); - Set t1 = v1 instanceof Ambiguity ? ((Ambiguity) v1).items() : Sets.newHashSet(v1); - Set rez = Sets.newHashSet(); - for (Term t00 : t0) - for (Term t11 : t1) - rez.add(TermCons.apply(ConsPStack.singleton(t00).plus(t11), tc.production(), tc.location(), tc.source())); - return Ambiguity.apply(rez, tc.location(), tc.source()); - } - return tc; - } + // push ambiguities top so we can get easy access to KList + private static class PushTopAmbiguityUp2 extends SafeTransformer { + @Override + public Term apply(TermCons tc) { + if (tc.production().klabel().isDefined() + && tc.production().klabel().get().head().equals(KLabels.KLIST)) { + Term v0 = super.apply(tc.get(0)); + Term v1 = super.apply(tc.get(1)); + Set t0 = v0 instanceof Ambiguity ? ((Ambiguity) v0).items() : Sets.newHashSet(v0); + Set t1 = v1 instanceof Ambiguity ? ((Ambiguity) v1).items() : Sets.newHashSet(v1); + Set rez = Sets.newHashSet(); + for (Term t00 : t0) + for (Term t11 : t1) + rez.add( + TermCons.apply( + ConsPStack.singleton(t00).plus(t11), + tc.production(), + tc.location(), + tc.source())); + return Ambiguity.apply(rez, tc.location(), tc.source()); + } + return tc; } + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PriorityVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PriorityVisitor.java index e4a58d21b6d..152420684b3 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PriorityVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PriorityVisitor.java @@ -1,14 +1,17 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; + import com.google.common.collect.Sets; +import java.util.HashSet; import org.kframework.Collections; import org.kframework.POSet; import org.kframework.attributes.Att; import org.kframework.definition.NonTerminal; import org.kframework.definition.Tag; -import org.kframework.parser.SetsTransformerWithErrors; import org.kframework.parser.Ambiguity; +import org.kframework.parser.SetsTransformerWithErrors; import org.kframework.parser.Term; import org.kframework.parser.TermCons; import org.kframework.utils.StringUtil; @@ -19,207 +22,258 @@ import scala.util.Left; import scala.util.Right; -import java.util.HashSet; +/** Apply the priority and associativity filters. */ +public class PriorityVisitor extends SetsTransformerWithErrors { -import static org.kframework.Collections.*; + private final POSet priorities; + private final Set> leftAssoc; + private final Set> rightAssoc; -/** - * Apply the priority and associativity filters. - */ -public class PriorityVisitor extends SetsTransformerWithErrors { + public PriorityVisitor( + POSet priorities, Set> leftAssoc, Set> rightAssoc) { + super(); + this.priorities = priorities; + this.leftAssoc = leftAssoc; + this.rightAssoc = rightAssoc; + } - private final POSet priorities; - private final Set> leftAssoc; - private final Set> rightAssoc; - public PriorityVisitor(POSet priorities, Set> leftAssoc, Set> rightAssoc) { - super(); - this.priorities = priorities; - this.leftAssoc = leftAssoc; - this.rightAssoc = rightAssoc; - } + @Override + public Either, Term> apply(Ambiguity amb) { + // if the ambiguity has rewrites at the top, prefer them, and eliminate the rest + scala.collection.Set rewrites = + amb.items().stream() + .filter( + o -> + o instanceof TermCons + && ((TermCons) o).production().klabel().isDefined() + && ((TermCons) o).production().klabel().get().name().equals("#KRewrite")) + .collect(Collections.toSet()); + if (rewrites.size() == 1) return apply(rewrites.head()); + if (rewrites.size() != 0 && rewrites.size() != amb.items().size()) + amb = Ambiguity.apply(mutable(rewrites)); - @Override - public Either, Term> apply(Ambiguity amb) { - // if the ambiguity has rewrites at the top, prefer them, and eliminate the rest - scala.collection.Set rewrites = amb.items().stream().filter(o -> - o instanceof TermCons && - ((TermCons) o).production().klabel().isDefined() && - ((TermCons) o).production().klabel().get().name().equals("#KRewrite")).collect(Collections.toSet()); - if (rewrites.size() == 1) - return apply(rewrites.head()); - if (rewrites.size() != 0 && rewrites.size() != amb.items().size()) - amb = Ambiguity.apply(mutable(rewrites)); - - // if the ambiguity has KSeq at the top, prefer them, and eliminate the rest - rewrites = amb.items().stream().filter(o -> - o instanceof TermCons && - ((TermCons) o).production().klabel().isDefined() && - ((TermCons) o).production().klabel().get().name().equals("#KSequence")).collect(Collections.toSet()); - if (rewrites.size() == 1) - return apply(rewrites.head()); - if (rewrites.size() != 0 && rewrites.size() != amb.items().size()) - amb = Ambiguity.apply(mutable(rewrites)); - - // if the ambiguity has let at the top, prefer them, and eliminate the rest - rewrites = amb.items().stream().filter(o -> - o instanceof TermCons && - ((TermCons) o).production().klabel().isDefined() && - ((TermCons) o).production().klabel().get().name().equals("#let")).collect(Collections.toSet()); - if (rewrites.size() == 1) - return apply(rewrites.head()); - if (rewrites.size() != 0 && rewrites.size() != amb.items().size()) - amb = Ambiguity.apply(mutable(rewrites)); - - return super.apply(amb); - } + // if the ambiguity has KSeq at the top, prefer them, and eliminate the rest + rewrites = + amb.items().stream() + .filter( + o -> + o instanceof TermCons + && ((TermCons) o).production().klabel().isDefined() + && ((TermCons) o).production().klabel().get().name().equals("#KSequence")) + .collect(Collections.toSet()); + if (rewrites.size() == 1) return apply(rewrites.head()); + if (rewrites.size() != 0 && rewrites.size() != amb.items().size()) + amb = Ambiguity.apply(mutable(rewrites)); - @Override - public Either, Term> apply(TermCons tc) { - assert tc.production() != null : this.getClass() + ":" + " production not found." + tc; - if (!tc.production().isSyntacticSubsort()) { - // match only on the outermost elements - if (tc.production().att().contains(Att.APPLY_PRIORITY())) { - String[] pieces = StringUtil.splitOneDimensionalAtt(tc.production().att().get(Att.APPLY_PRIORITY())); - java.util.Set applyAt = new HashSet<>(); - for (String piece : pieces) { - try { - int i = Integer.parseInt(piece.trim()); - applyAt.add(i); - } catch (NumberFormatException e) { - throw KEMException.innerParserError("Invalid applyPriority attribute value: " + piece, e, tc.production().source().orElse(null), tc.production().location().orElse(null)); - } - } - for (int i = 0, j = 0; i < tc.production().items().size(); i++) { - if (tc.production().items().apply(i) instanceof NonTerminal) { - j++; - if (applyAt.contains(j)) { - PriorityVisitor2.Side side; - if (i == 0) { - side = PriorityVisitor2.Side.LEFT; - } else if (i == tc.production().items().size() - 1) { - side = PriorityVisitor2.Side.RIGHT; - } else { - side = PriorityVisitor2.Side.MIDDLE; - } - Either, Term> rez = - new PriorityVisitor2(tc, side, priorities, leftAssoc, rightAssoc).apply(tc.get(j-1)); - if (rez.isLeft()) - return rez; - tc = tc.with(j-1, rez.right().get()); - } - } + // if the ambiguity has let at the top, prefer them, and eliminate the rest + rewrites = + amb.items().stream() + .filter( + o -> + o instanceof TermCons + && ((TermCons) o).production().klabel().isDefined() + && ((TermCons) o).production().klabel().get().name().equals("#let")) + .collect(Collections.toSet()); + if (rewrites.size() == 1) return apply(rewrites.head()); + if (rewrites.size() != 0 && rewrites.size() != amb.items().size()) + amb = Ambiguity.apply(mutable(rewrites)); + + return super.apply(amb); + } + + @Override + public Either, Term> apply(TermCons tc) { + assert tc.production() != null : this.getClass() + ":" + " production not found." + tc; + if (!tc.production().isSyntacticSubsort()) { + // match only on the outermost elements + if (tc.production().att().contains(Att.APPLY_PRIORITY())) { + String[] pieces = + StringUtil.splitOneDimensionalAtt(tc.production().att().get(Att.APPLY_PRIORITY())); + java.util.Set applyAt = new HashSet<>(); + for (String piece : pieces) { + try { + int i = Integer.parseInt(piece.trim()); + applyAt.add(i); + } catch (NumberFormatException e) { + throw KEMException.innerParserError( + "Invalid applyPriority attribute value: " + piece, + e, + tc.production().source().orElse(null), + tc.production().location().orElse(null)); + } + } + for (int i = 0, j = 0; i < tc.production().items().size(); i++) { + if (tc.production().items().apply(i) instanceof NonTerminal) { + j++; + if (applyAt.contains(j)) { + PriorityVisitor2.Side side; + if (i == 0) { + side = PriorityVisitor2.Side.LEFT; + } else if (i == tc.production().items().size() - 1) { + side = PriorityVisitor2.Side.RIGHT; + } else { + side = PriorityVisitor2.Side.MIDDLE; } - } else { - if (tc.production().items().apply(0) instanceof NonTerminal) { - Either, Term> rez = - new PriorityVisitor2(tc, PriorityVisitor2.Side.LEFT, priorities, leftAssoc, rightAssoc).apply(tc.get(0)); - if (rez.isLeft()) - return rez; - tc = tc.with(0, rez.right().get()); - } - if (tc.production().items().apply(tc.production().items().size() - 1) instanceof NonTerminal) { - int last = tc.items().size() - 1; - Either, Term> rez = - new PriorityVisitor2(tc, PriorityVisitor2.Side.RIGHT, priorities, leftAssoc, rightAssoc).apply(tc.get(last)); - if (rez.isLeft()) - return rez; - tc = tc.with(last, rez.right().get()); - } + Either, Term> rez = + new PriorityVisitor2(tc, side, priorities, leftAssoc, rightAssoc) + .apply(tc.get(j - 1)); + if (rez.isLeft()) return rez; + tc = tc.with(j - 1, rez.right().get()); } + } + } + } else { + if (tc.production().items().apply(0) instanceof NonTerminal) { + Either, Term> rez = + new PriorityVisitor2( + tc, PriorityVisitor2.Side.LEFT, priorities, leftAssoc, rightAssoc) + .apply(tc.get(0)); + if (rez.isLeft()) return rez; + tc = tc.with(0, rez.right().get()); } - return super.apply(tc); + if (tc.production().items().apply(tc.production().items().size() - 1) + instanceof NonTerminal) { + int last = tc.items().size() - 1; + Either, Term> rez = + new PriorityVisitor2( + tc, PriorityVisitor2.Side.RIGHT, priorities, leftAssoc, rightAssoc) + .apply(tc.get(last)); + if (rez.isLeft()) return rez; + tc = tc.with(last, rez.right().get()); + } + } } + return super.apply(tc); + } - private static class PriorityVisitor2 extends SetsTransformerWithErrors { - /** - * Specifies whether the current node is the left most or the right most child of the parent. - * This is useful because associativity can be checked at the same time with priorities. - */ - public enum Side {LEFT, RIGHT, MIDDLE} - private final TermCons parent; - private final Side side; - private final POSet priorities; - private final Set> leftAssoc; - private final Set> rigthAssoc; - - public PriorityVisitor2(TermCons parent, Side side, POSet priorities, Set> leftAssoc, Set> rightAssoc) { - this.parent = parent; - this.side = side; - this.priorities = priorities; - this.leftAssoc = leftAssoc; - this.rigthAssoc = rightAssoc; - } + private static class PriorityVisitor2 extends SetsTransformerWithErrors { + /** + * Specifies whether the current node is the left most or the right most child of the parent. + * This is useful because associativity can be checked at the same time with priorities. + */ + public enum Side { + LEFT, + RIGHT, + MIDDLE + } - private final static java.util.Set rewriteExceptions, kseqExceptions, letExceptions; - - static { - rewriteExceptions = new HashSet<>(); - rewriteExceptions.add("#ruleRequires"); - rewriteExceptions.add("#ruleEnsures"); - rewriteExceptions.add("#ruleRequiresEnsures"); - rewriteExceptions.add("#KRewrite"); - rewriteExceptions.add("#withConfig"); - rewriteExceptions.add("#KList"); - kseqExceptions = new HashSet<>(); - kseqExceptions.add("#ruleRequires"); - kseqExceptions.add("#ruleEnsures"); - kseqExceptions.add("#ruleRequiresEnsures"); - kseqExceptions.add("#KRewrite"); - kseqExceptions.add("#KSequence"); - kseqExceptions.add("#KList"); - letExceptions = new HashSet<>(); - letExceptions.add("#ruleRequires"); - letExceptions.add("#ruleEnsures"); - letExceptions.add("#ruleRequiresEnsures"); - letExceptions.add("#KRewrite"); - letExceptions.add("#KSequence"); - letExceptions.add("#let"); - letExceptions.add("#KList"); - } + private final TermCons parent; + private final Side side; + private final POSet priorities; + private final Set> leftAssoc; + private final Set> rigthAssoc; - public Either, Term> apply(TermCons tc) { - Tag parentLabel = new Tag(parent.production().parseLabel().name()); - Tag localLabel = new Tag(tc.production().parseLabel().name()); - if (!parent.production().isSyntacticSubsort() && parent.production().klabel().isDefined()) { - if (!rewriteExceptions.contains(parentLabel.name()) && localLabel.name().equals("#KRewrite")) { - String msg = "Rewrite is not allowed to be an immediate child of " + parent.production().parseLabel() + - " Use parentheses: (x)=>(y) to set the proper scope of the operations."; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - if (!kseqExceptions.contains(parentLabel.name()) && localLabel.name().equals("#KSequence")) { - String msg = "~> is not allowed to be an immediate child of " + parent.production().parseLabel() + - " Use parentheses: (x)~>(y) to set the proper scope of the operations."; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - if (!letExceptions.contains(parentLabel.name()) && localLabel.name().equals("#let")) { - String msg = "#let is not allowed to be an immediate child of " + parent.production().parseLabel() + - " Use parentheses: #let x = y #in (z) to set the proper scope of the operations."; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - if ((parentLabel.name().equals("#SyntacticCast") || parentLabel.name().startsWith("#SemanticCastTo")) && - tc.production().items().apply(tc.production().items().size() - 1) instanceof NonTerminal) { - String msg = parent.production().klabel().get() + " is not allowed to be an immediate child of cast." + - " Use parentheses: (x):Sort to set the proper scope of the operations."; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - } - if (priorities.lessThan(parentLabel, localLabel)) { - String msg = "Priority filter exception. Cannot use " + localLabel + " as an immediate child of " + - parentLabel + ". Consider using parentheses around " + localLabel; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - if (leftAssoc.contains(new Tuple2<>(parentLabel, localLabel)) && Side.RIGHT == side) { - String msg = "Associativity filter exception. Cannot use " + localLabel + " as an immediate right child of " + - parentLabel + ". Consider using parentheses around " + localLabel; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - if (rigthAssoc.contains(new Tuple2<>(parentLabel, localLabel)) && Side.LEFT == side) { - String msg = "Associativity filter exception. Cannot use " + localLabel + " as an immediate left child of " + - parentLabel + ". Consider using parentheses around " + localLabel; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } + public PriorityVisitor2( + TermCons parent, + Side side, + POSet priorities, + Set> leftAssoc, + Set> rightAssoc) { + this.parent = parent; + this.side = side; + this.priorities = priorities; + this.leftAssoc = leftAssoc; + this.rigthAssoc = rightAssoc; + } + + private static final java.util.Set rewriteExceptions, kseqExceptions, letExceptions; - return Right.apply(tc); + static { + rewriteExceptions = new HashSet<>(); + rewriteExceptions.add("#ruleRequires"); + rewriteExceptions.add("#ruleEnsures"); + rewriteExceptions.add("#ruleRequiresEnsures"); + rewriteExceptions.add("#KRewrite"); + rewriteExceptions.add("#withConfig"); + rewriteExceptions.add("#KList"); + kseqExceptions = new HashSet<>(); + kseqExceptions.add("#ruleRequires"); + kseqExceptions.add("#ruleEnsures"); + kseqExceptions.add("#ruleRequiresEnsures"); + kseqExceptions.add("#KRewrite"); + kseqExceptions.add("#KSequence"); + kseqExceptions.add("#KList"); + letExceptions = new HashSet<>(); + letExceptions.add("#ruleRequires"); + letExceptions.add("#ruleEnsures"); + letExceptions.add("#ruleRequiresEnsures"); + letExceptions.add("#KRewrite"); + letExceptions.add("#KSequence"); + letExceptions.add("#let"); + letExceptions.add("#KList"); + } + + public Either, Term> apply(TermCons tc) { + Tag parentLabel = new Tag(parent.production().parseLabel().name()); + Tag localLabel = new Tag(tc.production().parseLabel().name()); + if (!parent.production().isSyntacticSubsort() && parent.production().klabel().isDefined()) { + if (!rewriteExceptions.contains(parentLabel.name()) + && localLabel.name().equals("#KRewrite")) { + String msg = + "Rewrite is not allowed to be an immediate child of " + + parent.production().parseLabel() + + " Use parentheses: (x)=>(y) to set the proper scope of the operations."; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); } + if (!kseqExceptions.contains(parentLabel.name()) + && localLabel.name().equals("#KSequence")) { + String msg = + "~> is not allowed to be an immediate child of " + + parent.production().parseLabel() + + " Use parentheses: (x)~>(y) to set the proper scope of the operations."; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + if (!letExceptions.contains(parentLabel.name()) && localLabel.name().equals("#let")) { + String msg = + "#let is not allowed to be an immediate child of " + + parent.production().parseLabel() + + " Use parentheses: #let x = y #in (z) to set the proper scope of the" + + " operations."; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + if ((parentLabel.name().equals("#SyntacticCast") + || parentLabel.name().startsWith("#SemanticCastTo")) + && tc.production().items().apply(tc.production().items().size() - 1) + instanceof NonTerminal) { + String msg = + parent.production().klabel().get() + + " is not allowed to be an immediate child of cast." + + " Use parentheses: (x):Sort to set the proper scope of the operations."; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + } + if (priorities.lessThan(parentLabel, localLabel)) { + String msg = + "Priority filter exception. Cannot use " + + localLabel + + " as an immediate child of " + + parentLabel + + ". Consider using parentheses around " + + localLabel; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + if (leftAssoc.contains(new Tuple2<>(parentLabel, localLabel)) && Side.RIGHT == side) { + String msg = + "Associativity filter exception. Cannot use " + + localLabel + + " as an immediate right child of " + + parentLabel + + ". Consider using parentheses around " + + localLabel; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + if (rigthAssoc.contains(new Tuple2<>(parentLabel, localLabel)) && Side.LEFT == side) { + String msg = + "Associativity filter exception. Cannot use " + + localLabel + + " as an immediate left child of " + + parentLabel + + ". Consider using parentheses around " + + localLabel; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + + return Right.apply(tc); } + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushAmbiguitiesDownAndPreferAvoid.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushAmbiguitiesDownAndPreferAvoid.java index 9782997580e..c90eb84d5a2 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushAmbiguitiesDownAndPreferAvoid.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushAmbiguitiesDownAndPreferAvoid.java @@ -1,6 +1,9 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; import org.kframework.POSet; import org.kframework.attributes.Att; import org.kframework.definition.Production; @@ -10,124 +13,121 @@ import org.kframework.parser.Term; import org.kframework.parser.TermCons; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Created by dwightguth on 5/3/17. - */ +/** Created by dwightguth on 5/3/17. */ public class PushAmbiguitiesDownAndPreferAvoid extends SafeTransformer { - private final POSet overloads; - private final boolean justPush; + private final POSet overloads; + private final boolean justPush; - public PushAmbiguitiesDownAndPreferAvoid() { - this.overloads = null; - this.justPush = true; - } - - public PushAmbiguitiesDownAndPreferAvoid(POSet overloads) { - this.overloads = overloads; - this.justPush = false; - } + public PushAmbiguitiesDownAndPreferAvoid() { + this.overloads = null; + this.justPush = true; + } - public Term preferAvoid(Ambiguity amb) { - List prefer = new ArrayList<>(); - List avoid = new ArrayList<>(); - for (Term t : amb.items()) { - if (t instanceof ProductionReference) { - if (((ProductionReference) t).production().att().contains(Att.PREFER())) { - prefer.add(t); - } else if (((ProductionReference) t).production().att().contains(Att.AVOID())) { - avoid.add(t); - } - } - } - Term result = amb; + public PushAmbiguitiesDownAndPreferAvoid(POSet overloads) { + this.overloads = overloads; + this.justPush = false; + } - if (!prefer.isEmpty()) { - if (prefer.size() == 1) { - result = prefer.get(0); - } else { - result = amb.replaceChildren(prefer); - } - } else if (!avoid.isEmpty()) { - if (avoid.size() < amb.items().size()) { - amb.items().removeAll(avoid); - if (amb.items().size() == 1) - result = amb.items().iterator().next(); - } + public Term preferAvoid(Ambiguity amb) { + List prefer = new ArrayList<>(); + List avoid = new ArrayList<>(); + for (Term t : amb.items()) { + if (t instanceof ProductionReference) { + if (((ProductionReference) t).production().att().contains(Att.PREFER())) { + prefer.add(t); + } else if (((ProductionReference) t).production().att().contains(Att.AVOID())) { + avoid.add(t); } + } + } + Term result = amb; - return result; + if (!prefer.isEmpty()) { + if (prefer.size() == 1) { + result = prefer.get(0); + } else { + result = amb.replaceChildren(prefer); + } + } else if (!avoid.isEmpty()) { + if (avoid.size() < amb.items().size()) { + amb.items().removeAll(avoid); + if (amb.items().size() == 1) result = amb.items().iterator().next(); + } } - @Override - public Term apply(Ambiguity a) { - if (a.items().size() == 1) - return apply(a.items().iterator().next()); - Production prod = null; - int arity = 0; + return result; + } - if (!justPush) { - Term withoutOverloads = new RemoveOverloads(overloads).apply(a); - if (!(withoutOverloads instanceof Ambiguity)) { - return super.apply(withoutOverloads); - } - Term preferred = preferAvoid((Ambiguity)withoutOverloads); - if (!(preferred instanceof Ambiguity)) { - return super.apply(preferred); - } - a = (Ambiguity)preferred; - } + @Override + public Term apply(Ambiguity a) { + if (a.items().size() == 1) return apply(a.items().iterator().next()); + Production prod = null; + int arity = 0; + + if (!justPush) { + Term withoutOverloads = new RemoveOverloads(overloads).apply(a); + if (!(withoutOverloads instanceof Ambiguity)) { + return super.apply(withoutOverloads); + } + Term preferred = preferAvoid((Ambiguity) withoutOverloads); + if (!(preferred instanceof Ambiguity)) { + return super.apply(preferred); + } + a = (Ambiguity) preferred; + } - a = (Ambiguity)super.apply(a); - for (Term t : a.items()) { - if (!(t instanceof ProductionReference ref)) { - return a; - } - if (prod == null) { - prod = ref.production(); - if (ref instanceof TermCons) { - arity = ((TermCons) ref).items().size(); - } - } else if (!prod.equals(ref.production())) { - return a; - } + a = (Ambiguity) super.apply(a); + for (Term t : a.items()) { + if (!(t instanceof ProductionReference ref)) { + return a; + } + if (prod == null) { + prod = ref.production(); + if (ref instanceof TermCons) { + arity = ((TermCons) ref).items().size(); } - if (arity == 0) - return a; - boolean[] same = new boolean[arity]; - for (int i = 0; i < arity; i++) { - boolean sameAtIdx = true; - Term sameTerm = null; - for (Term t : a.items()) { - TermCons tc = (TermCons)t; - if (sameTerm == null) { - sameTerm = tc.get(i); - } else if (!sameTerm.equals(tc.get(i))) { - sameAtIdx = false; - } - } - same[i] = sameAtIdx; + } else if (!prod.equals(ref.production())) { + return a; + } + } + if (arity == 0) return a; + boolean[] same = new boolean[arity]; + for (int i = 0; i < arity; i++) { + boolean sameAtIdx = true; + Term sameTerm = null; + for (Term t : a.items()) { + TermCons tc = (TermCons) t; + if (sameTerm == null) { + sameTerm = tc.get(i); + } else if (!sameTerm.equals(tc.get(i))) { + sameAtIdx = false; } - TermCons first = (TermCons)a.items().iterator().next(); - for (int i = 0; i < arity; i++) { - final int idx = i; - boolean candidate = true; - for (int j = 0; j < arity; j++) { - if (i == j) - continue; - if (!same[j]) { - candidate = false; - break; - } - } - if (candidate) { - return apply(first.with(i, new Ambiguity(a.items().stream().map(t -> (TermCons)t).map(t -> t.get(idx)).collect(Collectors.toSet())))); - } + } + same[i] = sameAtIdx; + } + TermCons first = (TermCons) a.items().iterator().next(); + for (int i = 0; i < arity; i++) { + final int idx = i; + boolean candidate = true; + for (int j = 0; j < arity; j++) { + if (i == j) continue; + if (!same[j]) { + candidate = false; + break; } - return a; + } + if (candidate) { + return apply( + first.with( + i, + new Ambiguity( + a.items().stream() + .map(t -> (TermCons) t) + .map(t -> t.get(idx)) + .collect(Collectors.toSet())))); + } } + return a; + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushTopAmbiguityUp.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushTopAmbiguityUp.java index c75479b4690..8f59be9393b 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushTopAmbiguityUp.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/PushTopAmbiguityUp.java @@ -1,6 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import java.util.HashSet; +import java.util.Set; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; import org.kframework.parser.Ambiguity; @@ -8,41 +10,39 @@ import org.kframework.parser.Term; import org.kframework.parser.TermCons; -import java.util.HashSet; -import java.util.Set; - public class PushTopAmbiguityUp extends SafeTransformer { - @Override - public Term apply(TermCons tc) { - if (tc.production().sort().equals(Sorts.RuleContent())) { - Term t = new PushTopAmbiguityUp2().apply(tc.get(0)); - if (t instanceof Ambiguity old) { - Set newTerms = new HashSet<>(); - for (Term child : old.items()) { - Term newTerm = tc.with(0, child); - newTerms.add(newTerm); - } - return Ambiguity.apply(newTerms); - } + @Override + public Term apply(TermCons tc) { + if (tc.production().sort().equals(Sorts.RuleContent())) { + Term t = new PushTopAmbiguityUp2().apply(tc.get(0)); + if (t instanceof Ambiguity old) { + Set newTerms = new HashSet<>(); + for (Term child : old.items()) { + Term newTerm = tc.with(0, child); + newTerms.add(newTerm); } - return super.apply(tc); + return Ambiguity.apply(newTerms); + } } + return super.apply(tc); + } - private class PushTopAmbiguityUp2 extends SafeTransformer { - @Override - public Term apply(TermCons tc) { - if (tc.production().klabel().isDefined() && tc.production().klabel().get().head().equals(KLabels.KREWRITE)) { - Term t = tc.get(0); - if (t instanceof Ambiguity old) { - Set newTerms = new HashSet<>(); - for (Term child : old.items()) { - Term newTerm = tc.with(0, child); - newTerms.add(newTerm); - } - return Ambiguity.apply(newTerms); - } - } - return super.apply(tc); + private class PushTopAmbiguityUp2 extends SafeTransformer { + @Override + public Term apply(TermCons tc) { + if (tc.production().klabel().isDefined() + && tc.production().klabel().get().head().equals(KLabels.KREWRITE)) { + Term t = tc.get(0); + if (t instanceof Ambiguity old) { + Set newTerms = new HashSet<>(); + for (Term child : old.items()) { + Term newTerm = tc.with(0, child); + newTerms.add(newTerm); + } + return Ambiguity.apply(newTerms); } + } + return super.apply(tc); } + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveBracketVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveBracketVisitor.java index 0ef450bd3f6..1d914cb360c 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveBracketVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveBracketVisitor.java @@ -7,14 +7,13 @@ import org.kframework.parser.TermCons; public class RemoveBracketVisitor extends SafeTransformer { - @Override - public Term apply(TermCons tc) { - if (tc.production().att().contains(Att.BRACKET()) || - tc.production().klabel().get().name().equals("#SyntacticCast") || - tc.production().klabel().get().name().equals("#InnerCast")) - { - return apply(tc.get(0)); - } - return super.apply(tc); + @Override + public Term apply(TermCons tc) { + if (tc.production().att().contains(Att.BRACKET()) + || tc.production().klabel().get().name().equals("#SyntacticCast") + || tc.production().klabel().get().name().equals("#InnerCast")) { + return apply(tc.get(0)); } + return super.apply(tc); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveOverloads.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveOverloads.java index 7f0868b4faf..7cd8328d09c 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveOverloads.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/RemoveOverloads.java @@ -1,6 +1,9 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; import org.kframework.POSet; import org.kframework.definition.Production; import org.kframework.parser.Ambiguity; @@ -8,26 +11,26 @@ import org.kframework.parser.Term; import org.kframework.parser.TermCons; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; - public record RemoveOverloads(POSet overloads) { - public Term apply(Ambiguity a) { - Set productions = new HashSet<>(); - for (Term t : a.items()) { - if (t instanceof TermCons tc) { - productions.add(tc.production()); - } else { - return a; - } - } - Set candidates = overloads.minimal(productions); - Ambiguity result = Ambiguity.apply(a.items().stream().filter(t -> candidates.contains(((ProductionReference) t).production())).collect(Collectors.toSet())); - if (result.items().size() == 1) { - return result.items().iterator().next(); - } - return result; + public Term apply(Ambiguity a) { + Set productions = new HashSet<>(); + for (Term t : a.items()) { + if (t instanceof TermCons tc) { + productions.add(tc.production()); + } else { + return a; + } + } + Set candidates = overloads.minimal(productions); + Ambiguity result = + Ambiguity.apply( + a.items().stream() + .filter(t -> candidates.contains(((ProductionReference) t).production())) + .collect(Collectors.toSet())); + if (result.items().size() == 1) { + return result.items().iterator().next(); } + return result; + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/ResolveOverloadedTerminators.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/ResolveOverloadedTerminators.java index 37d1da30d83..f1d68d055fb 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/ResolveOverloadedTerminators.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/ResolveOverloadedTerminators.java @@ -1,7 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; + import com.google.common.collect.Sets; +import java.util.Set; +import java.util.stream.Collectors; import org.kframework.POSet; import org.kframework.attributes.Att; import org.kframework.definition.Production; @@ -9,37 +13,37 @@ import org.kframework.parser.Term; import org.kframework.parser.TermCons; import org.kframework.utils.errorsystem.KEMException; - -import java.util.Set; -import java.util.stream.Collectors; - import scala.util.Either; import scala.util.Left; -import static org.kframework.Collections.*; - public class ResolveOverloadedTerminators extends SetsTransformerWithErrors { - private final POSet overloads; - - public ResolveOverloadedTerminators(POSet overloads) { - this.overloads = overloads; - } - - @Override - public Either, Term> apply(TermCons tc) { - if (overloads.elements().contains(tc.production()) && tc.items().isEmpty()) { - Set candidates = stream(overloads.elements()).filter(p -> p.klabel().isDefined() && p.klabelAtt().equals(tc.production().klabelAtt()) && overloads.lessThanEq(p, tc.production())).collect(Collectors.toSet()); - candidates = overloads.minimal(candidates); - if (candidates.size() != 1) { - String msg = "Overloaded term does not have a least sort. Possible sorts: " + candidates; - return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); - } - Production prod = candidates.iterator().next(); - prod = prod.withAtt(prod.att() - .add(Att.ORIGINAL_PRD(), Production.class, tc.production())); - return super.apply(TermCons.apply(tc.items(), prod, tc.location(), tc.source())); - } - return super.apply(tc); + private final POSet overloads; + + public ResolveOverloadedTerminators(POSet overloads) { + this.overloads = overloads; + } + + @Override + public Either, Term> apply(TermCons tc) { + if (overloads.elements().contains(tc.production()) && tc.items().isEmpty()) { + Set candidates = + stream(overloads.elements()) + .filter( + p -> + p.klabel().isDefined() + && p.klabelAtt().equals(tc.production().klabelAtt()) + && overloads.lessThanEq(p, tc.production())) + .collect(Collectors.toSet()); + candidates = overloads.minimal(candidates); + if (candidates.size() != 1) { + String msg = "Overloaded term does not have a least sort. Possible sorts: " + candidates; + return Left.apply(Sets.newHashSet(KEMException.innerParserError(msg, tc))); + } + Production prod = candidates.iterator().next(); + prod = prod.withAtt(prod.att().add(Att.ORIGINAL_PRD(), Production.class, tc.production())); + return super.apply(TermCons.apply(tc.items(), prod, tc.location(), tc.source())); } + return super.apply(tc); + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TreeCleanerVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TreeCleanerVisitor.java index 040260b987c..344d3059a68 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TreeCleanerVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TreeCleanerVisitor.java @@ -1,23 +1,20 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; -import org.kframework.parser.SafeTransformer; import org.kframework.parser.Ambiguity; +import org.kframework.parser.SafeTransformer; import org.kframework.parser.Term; -import org.kframework.utils.errorsystem.KEMException; -/** - * Remove parsing artifacts such as single element ambiguities. - */ +/** Remove parsing artifacts such as single element ambiguities. */ public class TreeCleanerVisitor extends SafeTransformer { - @Override - public Term apply(Ambiguity amb) { - Term newTerm = super.apply(amb); - if (newTerm instanceof Ambiguity newAmb) { - if (newAmb.items().size() == 1) { - return newAmb.items().iterator().next(); - } - } - return newTerm; + @Override + public Term apply(Ambiguity amb) { + Term newTerm = super.apply(amb); + if (newTerm instanceof Ambiguity newAmb) { + if (newAmb.items().size() == 1) { + return newAmb.items().iterator().next(); + } } + return newTerm; + } } diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferenceVisitor.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferenceVisitor.java index 6af78b0bef0..94247730d49 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferenceVisitor.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferenceVisitor.java @@ -1,61 +1,52 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.kframework.builtin.Sorts; -import org.kframework.definition.Production; import org.kframework.definition.NonTerminal; +import org.kframework.definition.Production; import org.kframework.kore.Sort; import org.kframework.parser.Ambiguity; import org.kframework.parser.Constant; import org.kframework.parser.ProductionReference; +import org.kframework.parser.SetsTransformerWithErrors; import org.kframework.parser.Term; import org.kframework.parser.TermCons; -import org.kframework.parser.SetsTransformerWithErrors; import org.kframework.utils.errorsystem.KEMException; - import org.pcollections.ConsPStack; - import scala.util.Either; import scala.util.Left; import scala.util.Right; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - /** * Disambiguation transformer which performs type checking and variable type inference. * - * This class is responsible for most of the interaction at the K level, the overall driving of the disambiguation - * algorithm, and the pruning of ill-typed branches from the parse forest. All of the z3 code is managed by - * {@link TypeInferencer}. + *

This class is responsible for most of the interaction at the K level, the overall driving of + * the disambiguation algorithm, and the pruning of ill-typed branches from the parse forest. All of + * the z3 code is managed by {@link TypeInferencer}. * - * At a high level, the algorithm does the following: - * - * 1. Define all the sorts in z3 and the subsort relationship between sorts. - * 2. Declare all the variables and sort parameters in the term as z3 constants. - * 3. Assert that the sort parameters are not sort KLabel. - * 4. While preserving sharing, assert the constraints that determine whether the term is well-typed. - * 5. Add soft constraints indicating that we prefer larger solutions to smaller solutions. These serve as a heuristic - * only and do not exhaustively describe maximality. Their purpose is simply to cut the search space. - * 6. Check satisfiability. If the constraints cannot be satisfied, replay the constraints one at a time to determine - * the constraint at which the solution becomes unsatisfiable, and use the model of the last constraint to be - * satisfied to generate a type error. Otherwise: - * 7. Assert that the variables are not less than or equal to the model of the first solution, and check for another - * solution. Repeat this in a loop until the constraints become unsatisfied. - * 8. Filter out all models which are strictly less than some other model we have obtained. - * 9. For each remaining model, substitute the sorts of the variables into the term and trim out the branches of the - * parse forest for which that solution is not well typed. - * 10. Disjunct the substituted solutions together and return them. + *

At a high level, the algorithm does the following: * + *

1. Define all the sorts in z3 and the subsort relationship between sorts. 2. Declare all the + * variables and sort parameters in the term as z3 constants. 3. Assert that the sort parameters are + * not sort KLabel. 4. While preserving sharing, assert the constraints that determine whether the + * term is well-typed. 5. Add soft constraints indicating that we prefer larger solutions to smaller + * solutions. These serve as a heuristic only and do not exhaustively describe maximality. Their + * purpose is simply to cut the search space. 6. Check satisfiability. If the constraints cannot be + * satisfied, replay the constraints one at a time to determine the constraint at which the solution + * becomes unsatisfiable, and use the model of the last constraint to be satisfied to generate a + * type error. Otherwise: 7. Assert that the variables are not less than or equal to the model of + * the first solution, and check for another solution. Repeat this in a loop until the constraints + * become unsatisfied. 8. Filter out all models which are strictly less than some other model we + * have obtained. 9. For each remaining model, substitute the sorts of the variables into the term + * and trim out the branches of the parse forest for which that solution is not well typed. 10. + * Disjunct the substituted solutions together and return them. */ public class TypeInferenceVisitor extends SetsTransformerWithErrors { private final TypeInferencer inferencer; @@ -65,14 +56,18 @@ public class TypeInferenceVisitor extends SetsTransformerWithErrors, Term> apply(Term t) { Term loc = t; if (loc instanceof Ambiguity) { - loc = ((Ambiguity)loc).items().iterator().next(); + loc = ((Ambiguity) loc).items().iterator().next(); } // add constraints to inferencer inferencer.push(t, topSort, isAnywhere); @@ -95,28 +90,30 @@ public Either, Term> apply(Term t) { return Right.apply(t); } switch (inferencer.status()) { - case SATISFIABLE -> { - // there is at least one solution, so compute it and pop the soft constraints - inferencer.computeModel(); - inferencer.pop(); - } - case UNKNOWN -> { - // constraints could not be solved, so error - inferencer.pop(); - throw KEMException.internalError("Could not solve sort constraints.", t); - } - case UNSATISFIABLE -> { - // no solutions exist. This is a type error, so ask the inferencer for an error message and return - inferencer.pop(); - Set kex = inferencer.error(); - return Left.apply(kex); - } + case SATISFIABLE -> { + // there is at least one solution, so compute it and pop the soft constraints + inferencer.computeModel(); + inferencer.pop(); + } + case UNKNOWN -> { + // constraints could not be solved, so error + inferencer.pop(); + throw KEMException.internalError("Could not solve sort constraints.", t); + } + case UNSATISFIABLE -> { + // no solutions exist. This is a type error, so ask the inferencer for an error message + // and return + inferencer.pop(); + Set kex = inferencer.error(); + return Left.apply(kex); + } } boolean hasAnotherSolution = true; Set> models = new HashSet<>(); boolean once = true; do { - // compute the last solution except the first time through the loop, when it was already done + // compute the last solution except the first time through the loop, when it was already + // done if (!once) { inferencer.computeModel(); } @@ -125,35 +122,36 @@ public Either, Term> apply(Term t) { do { inferencer.pushGreater(); switch (inferencer.status()) { - case SATISFIABLE -> { - // is not maximal, keep going - isMaximal = false; - inferencer.computeModel(); - inferencer.pop(); - } - case UNKNOWN -> - // constraints coiuld not be solved, so error - throw KEMException.internalError("Could not solve sortconstraints.", t); - case UNSATISFIABLE -> { - isMaximal = true; - inferencer.pop(); - } + case SATISFIABLE -> { + // is not maximal, keep going + isMaximal = false; + inferencer.computeModel(); + inferencer.pop(); + } + case UNKNOWN -> + // constraints coiuld not be solved, so error + throw KEMException.internalError("Could not solve sortconstraints.", t); + case UNSATISFIABLE -> { + isMaximal = true; + inferencer.pop(); + } } } while (!isMaximal); models.add(inferencer.getModel()); // assert that we don't want any solutions less than this one inferencer.pushNotModel(); - hasAnotherSolution = switch (inferencer.status()) { - case SATISFIABLE -> - // found another solution, keep going - true; - case UNKNOWN -> - // constraints could not be solved, so error - throw KEMException.internalError("Could not solve sort constraints.", t); - case UNSATISFIABLE -> - // no more solutions, terminate loop - false; - }; + hasAnotherSolution = + switch (inferencer.status()) { + case SATISFIABLE -> + // found another solution, keep going + true; + case UNKNOWN -> + // constraints could not be solved, so error + throw KEMException.internalError("Could not solve sort constraints.", t); + case UNSATISFIABLE -> + // no more solutions, terminate loop + false; + }; } while (hasAnotherSolution); // remove all models that are not maximal Set candidates = new HashSet<>(); @@ -184,24 +182,41 @@ public Either, Term> apply(Term t) { /** * A transformer which takes a particular type inference solution and applies it to a given term. * - * Essentially, for each term in the parse forest, we compute the actual sort of the term from the model, and compare - * it to the expected sort. If it is not well typed, we remove that branch of the parse forest entirely. We also, - * depending on the flags passed to the parent class, might add casts to the term around variables. + *

Essentially, for each term in the parse forest, we compute the actual sort of the term from + * the model, and compare it to the expected sort. If it is not well typed, we remove that branch + * of the parse forest entirely. We also, depending on the flags passed to the parent class, might + * add casts to the term around variables. */ public class TypeCheckVisitor extends SetsTransformerWithErrors { private Sort expectedSort; private boolean hasCastAlready = false, hasCheckAlready = false; + public TypeCheckVisitor(Sort topSort) { this.expectedSort = topSort; } - private Either, Term> typeError(ProductionReference pr, Sort expectedSort, Sort actualSort) { + private Either, Term> typeError( + ProductionReference pr, Sort expectedSort, Sort actualSort) { String msg; if (pr instanceof Constant) { - msg = "Unexpected sort " + actualSort + " for term " + ((Constant)pr).value() + ". Expected " + expectedSort + "."; + msg = + "Unexpected sort " + + actualSort + + " for term " + + ((Constant) pr).value() + + ". Expected " + + expectedSort + + "."; } else { - msg = "Unexpected sort " + actualSort + " for term parsed as production " + pr.production() + ". Expected " + expectedSort + "."; + msg = + "Unexpected sort " + + actualSort + + " for term parsed as production " + + pr.production() + + ". Expected " + + expectedSort + + "."; } return Left.apply(Collections.singleton(KEMException.innerParserError(msg, pr))); } @@ -211,23 +226,29 @@ public Either, Term> apply(Term term) { if (term instanceof Ambiguity amb) { return super.apply(amb); } - ProductionReference pr = (ProductionReference)term; - if (pr instanceof Constant && (pr.production().sort().equals(Sorts.KVariable()) || pr.production().sort().equals(Sorts.KConfigVar()))) { - // this is a variable, so check that its inferred sort is less than or equal to the expected sort + ProductionReference pr = (ProductionReference) term; + if (pr instanceof Constant + && (pr.production().sort().equals(Sorts.KVariable()) + || pr.production().sort().equals(Sorts.KConfigVar()))) { + // this is a variable, so check that its inferred sort is less than or equal to the expected + // sort Sort inferred = inferencer.getArgs(pr).apply(0); - if (!inferencer.module().subsorts().lessThanEq(inferred, expectedSort) && !expectedSort.equals(Sorts.KVariable())) { + if (!inferencer.module().subsorts().lessThanEq(inferred, expectedSort) + && !expectedSort.equals(Sorts.KVariable())) { // this variable is not well typed at this location, so prune this branch return typeError(pr, expectedSort, inferred); } // well typed, so add a cast and return - return wrapTermWithCast((Constant)pr, inferred); + return wrapTermWithCast((Constant) pr, inferred); } // compute the instantiated production with its sort parameters Production substituted = pr.production().substitute(inferencer.getArgs(pr)); Sort actualSort = substituted.sort(); boolean isExactSort = hasCastAlready && !hasCheckAlready; // check type: inner casts and syntactic casts indicate type equality, everything else is <= - if ((isExactSort && !actualSort.equals(expectedSort)) || (!isExactSort && !inferencer.module().subsorts().lessThanEq(actualSort, expectedSort))) { + if ((isExactSort && !actualSort.equals(expectedSort)) + || (!isExactSort + && !inferencer.module().subsorts().lessThanEq(actualSort, expectedSort))) { // not well typed, so prune this branch return typeError(pr, expectedSort, actualSort); } @@ -239,12 +260,13 @@ public Either, Term> apply(Term term) { boolean wasCast = hasCastAlready; boolean wasCheck = hasCheckAlready; // compute whether this is a cast already - if (substituted.klabel().isDefined() && substituted.klabel().get().name().startsWith("#SemanticCastTo")) { + if (substituted.klabel().isDefined() + && substituted.klabel().get().name().startsWith("#SemanticCastTo")) { hasCheckAlready = true; hasCastAlready = true; - } else if (substituted.klabel().isDefined() && - (substituted.klabel().get().name().equals("#SyntacticCast") || - substituted.klabel().get().name().equals("#InnerCast"))) { + } else if (substituted.klabel().isDefined() + && (substituted.klabel().get().name().equals("#SyntacticCast") + || substituted.klabel().get().name().equals("#InnerCast"))) { hasCastAlready = true; hasCheckAlready = false; } else { @@ -261,8 +283,7 @@ public Either, Term> apply(Term term) { expectedSort = oldExpected; hasCastAlready = wasCast; hasCheckAlready = wasCheck; - if (rez.isLeft()) - return rez; + if (rez.isLeft()) return rez; // apply result of visiting child to the term. tc = tc.with(j, rez.right().get()); j++; @@ -277,10 +298,21 @@ private Either, Term> wrapTermWithCast(Constant c, Sort declar Production cast; if (inferSortChecks && !hasCheckAlready) { // strictly typing variables and one does not already exist, so add :Sort - cast = inferencer.module().productionsFor().apply(KLabel("#SemanticCastTo" + declared.toString())).head(); - } else if (inferCasts && !hasCastAlready && inferencer.module().productionsFor().contains(KLabel("#SyntacticCast"))) { + cast = + inferencer + .module() + .productionsFor() + .apply(KLabel("#SemanticCastTo" + declared.toString())) + .head(); + } else if (inferCasts + && !hasCastAlready + && inferencer.module().productionsFor().contains(KLabel("#SyntacticCast"))) { // casting variables and one doeds not already exist, so add ::Sort - cast = stream(inferencer.module().productionsFor().apply(KLabel("#SyntacticCast"))).filter(p -> p.sort().equals(declared)).findAny().get(); + cast = + stream(inferencer.module().productionsFor().apply(KLabel("#SyntacticCast"))) + .filter(p -> p.sort().equals(declared)) + .findAny() + .get(); } else { // unparsing or cast already exists, so do nothing cast = null; diff --git a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferencer.java b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferencer.java index e373279f727..21d22822985 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferencer.java +++ b/kernel/src/main/java/org/kframework/parser/inner/disambiguation/TypeInferencer.java @@ -1,10 +1,27 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import org.kframework.Collections; import org.kframework.POSet; import org.kframework.attributes.Att; -import org.kframework.Collections; -import org.kframework.TopologicalSort; import org.kframework.attributes.Location; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; @@ -22,35 +39,16 @@ import org.kframework.parser.inner.RuleGrammarGenerator; import org.kframework.utils.OS; import org.kframework.utils.errorsystem.KEMException; - +import scala.Tuple2; import scala.collection.Seq; import scala.collection.Set; -import scala.Tuple2; - -import java.io.BufferedReader; -import java.io.File; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.PrintStream; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.kframework.kore.KORE.*; -import static org.kframework.Collections.*; /** * Class to manage communication with z3 for the purposes of type inference. This class is driven by - * {@link TypeInferenceVisitor} and handles all the communication to/from z3 as well as construction of constraints. + * {@link TypeInferenceVisitor} and handles all the communication to/from z3 as well as construction + * of constraints. * - * For a description of the algorithm, see the companion class's javadoc. + *

For a description of the algorithm, see the companion class's javadoc. */ public class TypeInferencer implements AutoCloseable { @@ -69,10 +67,10 @@ public enum Status { private final Module mod; private final java.util.Set sorts; - // logic QF_DT is best if it exists as it will be faster than ALL. However, some z3 versions do not have this logic. + // logic QF_DT is best if it exists as it will be faster than ALL. However, some z3 versions do + // not have this logic. // Fortunately, z3 ignores unknown logics. - private static final String PRELUDE1 = - "(set-logic QF_DT)\n"; + private static final String PRELUDE1 = "(set-logic QF_DT)\n"; private final boolean destroyOnReset; @@ -89,22 +87,24 @@ private void initProcess() { /** * Create a new z3 process and write the sorts and subsort relation to it. + * * @param mod the module to create an inferencer for. */ public TypeInferencer(Module mod, boolean debug) { initProcess(); println("(get-info :version)"); try { - String version = output.readLine(); - version = version.substring("(:version \"".length()); - version = version.substring(0, version.indexOf('"')); - String[] parts = version.split("\\."); - // example of version string: - // "4.8.8 - build hashcode ad55a1f1c617" - int major = Integer.valueOf(parts[0]); - int minor = Integer.valueOf(parts[1]); - int patch = Integer.valueOf(parts[2].split(" ")[0]); - destroyOnReset = major < 4 || (major == 4 && minor < 6) || (major == 4 && minor == 8 && patch == 9); + String version = output.readLine(); + version = version.substring("(:version \"".length()); + version = version.substring(0, version.indexOf('"')); + String[] parts = version.split("\\."); + // example of version string: + // "4.8.8 - build hashcode ad55a1f1c617" + int major = Integer.valueOf(parts[0]); + int minor = Integer.valueOf(parts[1]); + int patch = Integer.valueOf(parts[2].split(" ")[0]); + destroyOnReset = + major < 4 || (major == 4 && minor < 6) || (major == 4 && minor == 8 && patch == 9); } catch (IOException e) { throw KEMException.internalError("Could not read from z3 process", e); } @@ -115,13 +115,19 @@ public TypeInferencer(Module mod, boolean debug) { push(mod); } - // returns whether a particular sort should be written to z3 and thus be a possible sort for variables. + // returns whether a particular sort should be written to z3 and thus be a possible sort for + // variables. private boolean isRealSort(SortHead head) { if (head.params() > 0) { return true; } Sort s = Sort(head); - return !RuleGrammarGenerator.isParserSort(s) || s.equals(Sorts.K()) || s.equals(Sorts.KItem()) || s.equals(Sorts.KLabel()) || s.equals(Sorts.RuleTag()) || s.isNat(); + return !RuleGrammarGenerator.isParserSort(s) + || s.equals(Sorts.K()) + || s.equals(Sorts.KItem()) + || s.equals(Sorts.KLabel()) + || s.equals(Sorts.RuleTag()) + || s.isNat(); } public Module module() { @@ -130,6 +136,7 @@ public Module module() { /** * Writes the prelude for a particular module. + * * @param mod */ private void push(Module mod) { @@ -152,7 +159,8 @@ private void push(Module mod) { } private void makeSubsorts(Module mod, String name, POSet relations) { - // map from each sort to an integer representing the topological sorting of the sorts. higher numbers mean greater + // map from each sort to an integer representing the topological sorting of the sorts. higher + // numbers mean greater // sorts Map ordinals = new HashMap<>(); int i = 0; @@ -165,7 +173,10 @@ private void makeSubsorts(Module mod, String name, POSet relations) { } // provide fixed interpretation of subsort relation println("(define-fun " + name + " ((s1 Sort) (s2 Sort)) Bool (or"); - for (Tuple2> relation : stream(relations.relations()).sorted(Comparator.comparing(t -> -ordinals.getOrDefault(t._1().head(), 0))).collect(Collectors.toList())) { + for (Tuple2> relation : + stream(relations.relations()) + .sorted(Comparator.comparing(t -> -ordinals.getOrDefault(t._1().head(), 0))) + .collect(Collectors.toList())) { if (!isRealSort(relation._1().head())) { continue; } @@ -200,7 +211,8 @@ private void makeSubsorts(Module mod, String name, POSet relations) { private final List variables = new ArrayList<>(); // list of names for sort parameters only in z3 private final List parameters = new ArrayList<>(); - // array mapping from integer id of terms to the list of names of their variable or sort parameters in z3 + // array mapping from integer id of terms to the list of names of their variable or sort + // parameters in z3 private final List> variablesById = new ArrayList<>(); // array mapping from integer id of terms to the expected sorts they have appeared under so far private final List> cacheById = new ArrayList<>(); @@ -211,6 +223,7 @@ private void makeSubsorts(Module mod, String name, POSet relations) { private static class LocalizedError extends RuntimeException { private final Term loc; + LocalizedError(String message, Term loc) { super(message); this.loc = loc; @@ -222,8 +235,9 @@ public Term getLocation() { } /** - * Replays a list of {@link Constraint} one at a time and throws an exception with the error message explaining - * why the constraints are not satisfied. + * Replays a list of {@link Constraint} one at a time and throws an exception with the error + * message explaining why the constraints are not satisfied. + * * @param constraints */ private void replayConstraints(List constraints) { @@ -235,36 +249,48 @@ private void replayConstraints(List constraints) { status = null; Status status = status(); switch (status) { - case SATISFIABLE -> { - println("(pop)"); - print("(assert (and "); - print(constraint.smt); - println("))"); - } - case UNKNOWN -> throw KEMException.internalError("Could not solve sort constraints.", currentTerm); - case UNSATISFIABLE -> { - println("(pop)"); - computeStatus(); - if (constraint.name != null) { - Sort actualSort = computeValue(constraint.name); - Sort expectedSort = eval(constraint.expectedSort, constraint.expectedParams); - throw new LocalizedError("Unexpected sort " + actualSort + " for variable " + constraint.loc.value() + ". Expected: " + expectedSort, constraint.loc); - } else { - Sort actualSort = eval(constraint.actualSort, constraint.actualParams); - Sort expectedSort = eval(constraint.expectedSort, constraint.expectedParams); - throw new LocalizedError("Unexpected sort " + actualSort + " for term parsed as production " + constraint.actualParams.get().production() + ". Expected: " + expectedSort, constraint.actualParams.get()); + case SATISFIABLE -> { + println("(pop)"); + print("(assert (and "); + print(constraint.smt); + println("))"); + } + case UNKNOWN -> throw KEMException.internalError( + "Could not solve sort constraints.", currentTerm); + case UNSATISFIABLE -> { + println("(pop)"); + computeStatus(); + if (constraint.name != null) { + Sort actualSort = computeValue(constraint.name); + Sort expectedSort = eval(constraint.expectedSort, constraint.expectedParams); + throw new LocalizedError( + "Unexpected sort " + + actualSort + + " for variable " + + constraint.loc.value() + + ". Expected: " + + expectedSort, + constraint.loc); + } else { + Sort actualSort = eval(constraint.actualSort, constraint.actualParams); + Sort expectedSort = eval(constraint.expectedSort, constraint.expectedParams); + throw new LocalizedError( + "Unexpected sort " + + actualSort + + " for term parsed as production " + + constraint.actualParams.get().production() + + ". Expected: " + + expectedSort, + constraint.actualParams.get()); + } } - } } } } - /** - * Asserts that none of the sort parameters are of the KLabel sort. - */ + /** Asserts that none of the sort parameters are of the KLabel sort. */ private void assertNotKLabel() { - if (!sorts.contains(Sorts.KLabel().head())) - return; + if (!sorts.contains(Sorts.KLabel().head())) return; for (String param : parameters) { print("(distinct |" + param + "| "); printSort(Sorts.KLabel()); @@ -274,6 +300,7 @@ private void assertNotKLabel() { /** * Uses z3 to compute the error message associated with a badly typed term. + * * @return */ private KEMException push() { @@ -286,7 +313,7 @@ private KEMException push() { for (String var : variables) { println("(declare-const |" + var + "| Sort)"); } - //assert sort parameters are not sort KLabel. + // assert sort parameters are not sort KLabel. print("(assert (and true "); assertNotKLabel(); println("))"); @@ -303,6 +330,7 @@ private KEMException push() { /** * write constraints to z3 for a term. + * * @param t The term to compute constraints for. * @param topSort The expected sort at the top of the term. * @param isAnywhere Whether the term is an anywhere rule. @@ -311,14 +339,14 @@ public void push(Term t, Sort topSort, boolean isAnywhere) { currentTerm = t; currentTopSort = topSort; this.isAnywhere = isAnywhere; - level+=2; + level += 2; println("(push)"); // compute constraints in non-incremental mode ExpectedSortsVisitor viz = new ExpectedSortsVisitor(topSort, isAnywhere, false); String id = viz.apply(t); if (variables.isEmpty()) { - // there are no variables. so return as there is nothing to infer. - return; + // there are no variables. so return as there is nothing to infer. + return; } // declare variables and sort parameters for (String var : variables) { @@ -346,6 +374,7 @@ public void push(Term t, Sort topSort, boolean isAnywhere) { /** * Returns the top term on the lhs of a rule, if one exists. + * * @param t * @return */ @@ -354,40 +383,47 @@ private static Optional getFunction(Term t) { return Optional.empty(); } while (child.production().att().contains(Att.BRACKET())) { - if (((TermCons)child).get(0) instanceof Ambiguity) { + if (((TermCons) child).get(0) instanceof Ambiguity) { return Optional.empty(); } - child = (ProductionReference)((TermCons)child).get(0); + child = (ProductionReference) ((TermCons) child).get(0); } - if (child.production().klabel().isDefined() && child.production().klabel().get().head().equals(KLabels.KREWRITE)) { - if (((TermCons)child).get(0) instanceof Ambiguity) { + if (child.production().klabel().isDefined() + && child.production().klabel().get().head().equals(KLabels.KREWRITE)) { + if (((TermCons) child).get(0) instanceof Ambiguity) { return Optional.empty(); } - child = (ProductionReference)((TermCons)child).get(0); + child = (ProductionReference) ((TermCons) child).get(0); } while (child.production().att().contains(Att.BRACKET())) { - if (((TermCons)child).get(0) instanceof Ambiguity) { + if (((TermCons) child).get(0) instanceof Ambiguity) { return Optional.empty(); } - child = (ProductionReference)((TermCons)child).get(0); + child = (ProductionReference) ((TermCons) child).get(0); } return Optional.of(child); } /** * Returns true if a rule is a function or anywhere rule. + * * @param t * @param isAnywhere * @return */ private static boolean isFunction(Term t, boolean isAnywhere) { - return isAnywhere || - getFunction(t).filter(pr -> pr.production().att().contains(Att.FUNCTION()) - || ExpandMacros.isMacro(pr.production())).isPresent(); + return isAnywhere + || getFunction(t) + .filter( + pr -> + pr.production().att().contains(Att.FUNCTION()) + || ExpandMacros.isMacro(pr.production())) + .isPresent(); } /** * Returns return sort of a function or anywhere rule. + * * @param t * @return */ @@ -397,27 +433,26 @@ private static Sort getFunctionSort(Term t) { /** * Returns the declared of a cast. + * * @param tc * @return */ private static Sort getSortOfCast(TermCons tc) { switch (tc.production().klabel().get().name()) { - case "#SyntacticCast": - case "#OuterCast": - return tc.production().sort(); - case "#InnerCast": - return ((NonTerminal)tc.production().items().apply(1)).sort(); - default: - if (tc.production().klabel().get().name().startsWith("#SemanticCastTo")) { + case "#SyntacticCast": + case "#OuterCast": return tc.production().sort(); - } - throw new AssertionError("Unexpected cast type"); + case "#InnerCast": + return ((NonTerminal) tc.production().items().apply(1)).sort(); + default: + if (tc.production().klabel().get().name().startsWith("#SemanticCastTo")) { + return tc.production().sort(); + } + throw new AssertionError("Unexpected cast type"); } } - /** - * A z3 constraint to be replayed later. - */ + /** A z3 constraint to be replayed later. */ public static class Constraint { public final String smt; public final String name; @@ -429,13 +464,19 @@ public static class Constraint { /** * Creates an upper bound constraint on a variable. + * * @param smt The smtlib of the constraint * @param name The name of the variable * @param loc The variable * @param expectedSort The upper bound on the variable. * @param expectedParams The term that provided that upper bound. */ - public Constraint(String smt, String name, Constant loc, Sort expectedSort, Optional expectedParams) { + public Constraint( + String smt, + String name, + Constant loc, + Sort expectedSort, + Optional expectedParams) { this.smt = smt; this.name = name; this.loc = loc; @@ -447,13 +488,19 @@ public Constraint(String smt, String name, Constant loc, Sort expectedSort, Opti /** * Creates a constraint that an actual sort is less than or equal to an expected sort. + * * @param smt The smtlib of the constraint * @param actualSort The actual sort of the term. * @param actualParams The term * @param expectedSort The expected sort of the term. * @param expectedParams The term that provided that expected sort. */ - public Constraint(String smt, Sort actualSort, Optional actualParams, Sort expectedSort, Optional expectedParams) { + public Constraint( + String smt, + Sort actualSort, + Optional actualParams, + Sort expectedSort, + Optional expectedParams) { this.smt = smt; this.name = null; this.loc = null; @@ -465,6 +512,7 @@ public Constraint(String smt, Sort actualSort, Optional act /** * Returns true if a constraint is an upper bound on a variable. + * * @return */ public boolean isVar() { @@ -473,8 +521,8 @@ public boolean isVar() { } /** - * Computes the smtlib constraints for a term by traversing it and creating a set of declarations that capture the - * sort constraints. + * Computes the smtlib constraints for a term by traversing it and creating a set of declarations + * that capture the sort constraints. */ public class ExpectedSortsVisitor { private Sort expectedSort; @@ -490,10 +538,10 @@ public class ExpectedSortsVisitor { private final Map> ambCache = new IdentityHashMap<>(); /** - * * @param topSort Expected sort at top of term. * @param isAnywhere true if the term is an anywhere rule. - * @param isIncremental true if we should compute the constraints as a list of {@link Constraint} + * @param isIncremental true if we should compute the constraints as a list of {@link + * Constraint} */ ExpectedSortsVisitor(Sort topSort, boolean isAnywhere, boolean isIncremental) { this.expectedSort = topSort; @@ -502,16 +550,18 @@ public class ExpectedSortsVisitor { } /** - * Generate constraints for a term and accumulate them either in sb if in non-incremental mode, or in constraints - * if in incremental model. + * Generate constraints for a term and accumulate them either in sb if in non-incremental mode, + * or in constraints if in incremental model. + * * @param t The term to generate constraints for. - * @return the name of the function generated by this term in non-incremental mode that captures the constraints of - * this term. + * @return the name of the function generated by this term in non-incremental mode that captures + * the constraints of this term. */ public String apply(Term t) { if (t instanceof Ambiguity amb) { if (isIncremental) { - // we are error checking an ill typed term, so we pick just one branch of the ambiguity and explain why it is + // we are error checking an ill typed term, so we pick just one branch of the ambiguity + // and explain why it is // ill typed. return apply(amb.items().iterator().next()); } @@ -521,7 +571,8 @@ public String apply(Term t) { int id = contexts.computeIfAbsent(expected, expected2 -> ambId); boolean cached = id != ambId; if (!cached) { - // if this is the first time reaching this ambiguity node with this expected sort, define a new function + // if this is the first time reaching this ambiguity node with this expected sort, define + // a new function // with a disjunction of each of the children of the ambiguity. ambId++; List ids = new ArrayList<>(); @@ -537,13 +588,15 @@ public String apply(Term t) { // return name of created or cached function return "amb" + id; } - ProductionReference pr = (ProductionReference)t; + ProductionReference pr = (ProductionReference) t; List ids = new ArrayList<>(); - boolean isTopSort = expectedSort.equals(Sorts.RuleContent()) || expectedSort.name().equals("#RuleBody"); + boolean isTopSort = + expectedSort.equals(Sorts.RuleContent()) || expectedSort.name().equals("#RuleBody"); int id = nextId; boolean shared = pr.id().isPresent() && variablesById.size() > pr.id().get(); if (!shared) { - // if this is the first time reaching this term, initialize data structures with the variables associated with + // if this is the first time reaching this term, initialize data structures with the + // variables associated with // this term. nextId++; variablesById.add(new ArrayList<>()); @@ -572,14 +625,16 @@ public String apply(Term t) { isStrictEquality = false; // compute expected sort and whether this is a cast if (tc.production().klabel().isDefined() - && (tc.production().klabel().get().name().equals("#SyntacticCast") - || tc.production().klabel().get().name().startsWith("#SemanticCastTo") - || tc.production().klabel().get().name().equals("#InnerCast"))) { + && (tc.production().klabel().get().name().equals("#SyntacticCast") + || tc.production().klabel().get().name().startsWith("#SemanticCastTo") + || tc.production().klabel().get().name().equals("#InnerCast"))) { expectedSort = getSortOfCast(tc); - isStrictEquality = tc.production().klabel().get().name().equals("#SyntacticCast") - || tc.production().klabel().get().name().equals("#InnerCast"); + isStrictEquality = + tc.production().klabel().get().name().equals("#SyntacticCast") + || tc.production().klabel().get().name().equals("#InnerCast"); if (tc.get(0) instanceof Constant child) { - if (child.production().sort().equals(Sorts.KVariable()) || child.production().sort().equals(Sorts.KConfigVar())) { + if (child.production().sort().equals(Sorts.KVariable()) + || child.production().sort().equals(Sorts.KConfigVar())) { isStrictEquality = true; } } @@ -589,7 +644,8 @@ public String apply(Term t) { } else { expectedSort = nt.sort(); } - // recurse and add name of function generated by child to the current children of this constraint. + // recurse and add name of function generated by child to the current children of this + // constraint. ids.add(apply(tc.get(j))); j++; } @@ -602,15 +658,24 @@ public String apply(Term t) { String expected = printSort(expectedSort, expectedParams, false).replace("|", ""); boolean cached = !cacheById.get(id).add(expected); if (!isIncremental && (!shared || !cached)) { - // if we are in non-incremental mode and this is the first time reaching this term under this expected sort, - // define a new function with a conjunction of each of the children of the term and the constraints of the + // if we are in non-incremental mode and this is the first time reaching this term under + // this expected sort, + // define a new function with a conjunction of each of the children of the term and the + // constraints of the // current term. - sb.append("(define-fun |constraint").append(id).append("_").append(expected).append("| () Bool (and true "); + sb.append("(define-fun |constraint") + .append(id) + .append("_") + .append(expected) + .append("| () Bool (and true "); } if (isIncremental || !shared || !cached) { - // if we are in incremental mode or this is the first time reaching this term under this expected sort, + // if we are in incremental mode or this is the first time reaching this term under this + // expected sort, // compute the local constraints of this term and add them to the current constraint. - if (pr instanceof Constant c && (pr.production().sort().equals(Sorts.KVariable()) || pr.production().sort().equals(Sorts.KConfigVar()))) { + if (pr instanceof Constant c + && (pr.production().sort().equals(Sorts.KVariable()) + || pr.production().sort().equals(Sorts.KConfigVar()))) { String name; boolean oldStrictEquality = isStrictEquality; if (!shared) { @@ -637,7 +702,7 @@ public String apply(Term t) { pushConstraint(pr.production().sort(), Optional.of(pr)); } } - if (!isIncremental && (!shared || !cached)) { + if (!isIncremental && (!shared || !cached)) { for (String i : ids) { sb.append(i).append(" "); } @@ -653,11 +718,13 @@ boolean isAnonVar(Constant var) { /** * Add a constraint that an actual sort is less than an expected sort. + * * @param actualSort * @param actualParams */ private void pushConstraint(Sort actualSort, Optional actualParams) { - if (mod.subsorts().lessThanEq(actualSort, Sorts.KBott()) || mod.subsorts().lessThan(Sorts.K(), actualSort)) { + if (mod.subsorts().lessThanEq(actualSort, Sorts.KBott()) + || mod.subsorts().lessThan(Sorts.K(), actualSort)) { return; } if (isBadNatSort(actualSort)) { @@ -683,6 +750,7 @@ private void pushConstraint(Sort actualSort, Optional actua /** * Add a constraint that a variable is less than an expected sort. + * * @param name * @param loc */ @@ -694,7 +762,7 @@ private void pushConstraint(String name, Constant loc) { } sb.append("|").append(name).append("| "); if (mod.subsorts().lessThan(Sorts.K(), expectedSort)) { - expectedSort = Sorts.K(); + expectedSort = Sorts.K(); } sb.append(printSort(expectedSort, expectedParams, isIncremental)); sb.append(") "); @@ -711,7 +779,8 @@ private void saveConstraint(String name, Constant loc) { } private void saveConstraint(Sort actualSort, Optional actualParams) { - constraints.add(new Constraint(sb.toString(), actualSort, actualParams, expectedSort, expectedParams)); + constraints.add( + new Constraint(sb.toString(), actualSort, actualParams, expectedSort, expectedParams)); sb = new StringBuilder(); } @@ -725,6 +794,7 @@ private boolean isBadNatSort(Sort actualSort) { if (actualSort.isNat() && !mod.definedSorts().contains(actualSort.head())) return true; return stream(actualSort.params()).anyMatch(this::isBadNatSort); } + private String printSort(Sort s, Optional t, boolean isIncremental) { Map params = new HashMap<>(); if (t.isPresent()) { @@ -732,7 +802,7 @@ private String printSort(Sort s, Optional t, boolean isIncr int id = t.get().id().get(); List names = variablesById.get(id); Seq formalParams = t.get().production().params(); - assert(names.size() == formalParams.size()); + assert (names.size() == formalParams.size()); for (int i = 0; i < names.size(); i++) { params.put(formalParams.apply(i), names.get(i)); } @@ -775,6 +845,7 @@ private void printSort(Sort s) { /** * Check satisfiability of current assertions and return status. + * * @return */ private Status computeStatus() { @@ -784,14 +855,20 @@ private Status computeStatus() { do { result = output.readLine(); if (result == null) { - throw KEMException.internalError("Unexpected EOF reached while waiting for response from z3.", currentTerm); + throw KEMException.internalError( + "Unexpected EOF reached while waiting for response from z3.", currentTerm); } - } while (!result.equals("sat") && !result.equals("unsat") && !result.equals("unknown") && !result.equals("timeout") && !result.startsWith("(error")); + } while (!result.equals("sat") + && !result.equals("unsat") + && !result.equals("unknown") + && !result.equals("timeout") + && !result.startsWith("(error")); return switch (result) { case "sat" -> Status.SATISFIABLE; case "unsat" -> Status.UNSATISFIABLE; case "unknown", "timeout" -> Status.UNKNOWN; - default -> throw KEMException.internalError("Unexpected result from z3: " + result, currentTerm); + default -> throw KEMException.internalError( + "Unexpected result from z3: " + result, currentTerm); }; } catch (IOException e) { throw KEMException.internalError("Could not read from z3 process", e, currentTerm); @@ -800,11 +877,12 @@ private Status computeStatus() { /** * Check satisfiability of current assertions and return status, cached if called multiple times. + * * @return */ public Status status() { if (status == null) { - status = computeStatus(); + status = computeStatus(); } return status; } @@ -904,8 +982,7 @@ private Sort readSort(boolean trim) { result = result.substring(startIdx, endIdx); } Sort r = new SmtSortParser(new StringReader(result)).Sort(); - if (debug) - sb.append("; ").append(r).append("\n"); + if (debug) sb.append("; ").append(r).append("\n"); return r; } catch (IOException e) { throw KEMException.internalError("Could not read from z3 process", e, currentTerm); @@ -925,8 +1002,7 @@ public void close() { } private void reset() { - if (level > 0) - return; + if (level > 0) return; if (debug) { System.err.print(sb.toString()); sb = new StringBuilder(); @@ -950,11 +1026,19 @@ private void reset() { private static String locStr(ProductionReference pr) { String suffix = ""; if (pr.production().klabel().isDefined()) { - suffix = "_" + pr.production().klabel().get().name().replace("|",""); + suffix = "_" + pr.production().klabel().get().name().replace("|", ""); } if (pr.location().isPresent()) { Location l = pr.location().get(); - return "_" + l.startLine() + "_" + l.startColumn() + "_" + l.endLine() + "_" + l.endColumn() + suffix; + return "_" + + l.startLine() + + "_" + + l.startColumn() + + "_" + + l.endLine() + + "_" + + l.endColumn() + + suffix; } return pr.id().get() + suffix; } diff --git a/kernel/src/main/java/org/kframework/parser/inner/kernel/EarleyParser.java b/kernel/src/main/java/org/kframework/parser/inner/kernel/EarleyParser.java index dd8995f655f..bea1beea752 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/kernel/EarleyParser.java +++ b/kernel/src/main/java/org/kframework/parser/inner/kernel/EarleyParser.java @@ -1,7 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.kernel; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + import com.google.common.primitives.Ints; +import java.util.*; +import java.util.stream.Collectors; import org.apache.commons.codec.binary.StringUtils; import org.jetbrains.annotations.NotNull; import org.kframework.attributes.Att; @@ -25,32 +30,27 @@ import org.pcollections.ConsPStack; import org.pcollections.PStack; -import java.util.*; -import java.util.stream.Collectors; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - /** - * A parser for general context-free grammars based on the Earley recognizer algorithm found in - * Jay Earley's paper - * "An efficient context-free parsing algorithm" - * with some adaptations from Elizabeth Scott's paper - * "SPPF-Style Parsing from Earley Recognizers". - * and a minor fix relating to nullability taken from Aycock and Horspool's - * "Practical Earley Parsing" + * A parser for general context-free grammars based on the Earley recognizer algorithm found in Jay + * Earley's paper "An efficient context-free + * parsing algorithm" with some adaptations from Elizabeth Scott's paper "SPPF-Style Parsing from Earley + * Recognizers". and a minor fix relating to nullability taken from Aycock and Horspool's "Practical Earley Parsing" * - * The algorithm is not _quite_ the one described in section 5 of Scott's paper. For one thing, we use a single-token - * lookahead during prediction to cut down on the number of states we need to process. For another, we don't use quite - * the same approach for constructing parse forests. Finally, there was an issue with Scott's implementation of nullable - * non-terminals, and so we implement the prediction step from Aycock and Horspool's implementation when predicting a - * nullable non-terminal. Due to the difference in the parse forests, this algorithm is unbounded-polynomial-order in - * space usage. It would be theoretically possible to modify the way we generate parse forests to more closely follow - * Scott's paper, which would give us a parser which uses cubic space, but this would require us to modify the Term type - * rather substantially in order to binarize the TermCons nodes so that each has at most two children. This would be a - * change that requires a much more substantial rewriting of the algorithm we use to process parse forests. It is - * definitely worth considering however as it would dramatically improve the worst-case space usage of the algorithm on - * ambiguous sentences. + *

The algorithm is not _quite_ the one described in section 5 of Scott's paper. For one thing, + * we use a single-token lookahead during prediction to cut down on the number of states we need to + * process. For another, we don't use quite the same approach for constructing parse forests. + * Finally, there was an issue with Scott's implementation of nullable non-terminals, and so we + * implement the prediction step from Aycock and Horspool's implementation when predicting a + * nullable non-terminal. Due to the difference in the parse forests, this algorithm is + * unbounded-polynomial-order in space usage. It would be theoretically possible to modify the way + * we generate parse forests to more closely follow Scott's paper, which would give us a parser + * which uses cubic space, but this would require us to modify the Term type rather substantially in + * order to binarize the TermCons nodes so that each has at most two children. This would be a + * change that requires a much more substantial rewriting of the algorithm we use to process parse + * forests. It is definitely worth considering however as it would dramatically improve the + * worst-case space usage of the algorithm on ambiguous sentences. */ public class EarleyParser { @@ -66,9 +66,10 @@ private interface EarleyProductionItem { /** * @param nullable a {@link BitSet} where each index corresponds to a sort. - * @return true if this production item can be parsed as the empty string according to the BitSet, false otherwise. - * @apiNote Do not use this to check whether a sort or production is nullable. It exists solely to facilitate the - * code which computes nullability. + * @return true if this production item can be parsed as the empty string according to the + * BitSet, false otherwise. + * @apiNote Do not use this to check whether a sort or production is nullable. It exists solely + * to facilitate the code which computes nullability. */ boolean isNullable(BitSet nullable); } @@ -76,12 +77,16 @@ private interface EarleyProductionItem { /** * A single non-terminal in an {@link EarleyProduction}. * - * The sort is represented as an index within the `sorts` field. + *

The sort is represented as an index within the `sorts` field. */ - private record EarleyNonTerminal(int sort, List sorts) - implements EarleyProductionItem { - public boolean isNonTerminal() { return true; } - public boolean isNullable(BitSet nullable) { return nullable.get(sort); } + private record EarleyNonTerminal(int sort, List sorts) implements EarleyProductionItem { + public boolean isNonTerminal() { + return true; + } + + public boolean isNullable(BitSet nullable) { + return nullable.get(sort); + } public String toString() { return sorts.get(sort).toString(); @@ -91,13 +96,18 @@ public String toString() { /** * A single terminal in an {@link EarleyProduction}. * - * The terminal is represented by a particular token kind as informed by the provided {@link Scanner}. - * Token 0 is always the EOF token, which should appear only in the production used by the start state of the parser. + *

The terminal is represented by a particular token kind as informed by the provided {@link + * Scanner}. Token 0 is always the EOF token, which should appear only in the production used by + * the start state of the parser. */ - private record EarleyTerminal(Scanner scanner, int kind) - implements EarleyProductionItem { - public boolean isNonTerminal() { return false; } - public boolean isNullable(BitSet ignored) { return false; } + private record EarleyTerminal(Scanner scanner, int kind) implements EarleyProductionItem { + public boolean isNonTerminal() { + return false; + } + + public boolean isNullable(BitSet ignored) { + return false; + } public String toString() { if (kind == 0) { @@ -107,21 +117,21 @@ public String toString() { } } - /** - * A single production as represented by the parser. - */ + /** A single production as represented by the parser. */ private static final class EarleyProduction { /** - * @param index the index of the production within the `productions` field. Index 0 is reserved for the production - * `syntax ENTRY ::= STARTSYMBOL "EOF", where ENTRY is sort 0, STARTSYMBOL is the start symbol of the - * parser, and "EOF" is the EOF token, token 0. - * @param prod The {@link Production} to use to construct a {@link org.kframework.parser.ProductionReference} from - * a completed parse state. Use null in the case of production 0. + * @param index the index of the production within the `productions` field. Index 0 is reserved + * for the production `syntax ENTRY ::= STARTSYMBOL "EOF", where ENTRY is sort 0, + * STARTSYMBOL is the start symbol of the parser, and "EOF" is the EOF token, token 0. + * @param prod The {@link Production} to use to construct a {@link + * org.kframework.parser.ProductionReference} from a completed parse state. Use null in the + * case of production 0. * @param sort The sort of the production, as an index in the `sorts` field. * @param items The production's production items. * @param sorts The list of all sorts used by the parser in canonical order. */ - public EarleyProduction(int index, Production prod, int sort, List items, List sorts) { + public EarleyProduction( + int index, Production prod, int sort, List items, List sorts) { this.index = index; this.prod = prod; this.sort = sort; @@ -142,8 +152,13 @@ public EarleyProduction(int index, Production prod, int sort, ListThis class is only used to facilitate nullability computations. However, conceptually, the + * `prod` and `item` fields of an {@link EarleyState} also represent an LR(0) parsing item. */ private static final class LRItem { public LRItem(EarleyProduction prod, int item) { @@ -218,15 +233,16 @@ public String toString() { } /** - * An Earley parser parse state. Consists of an inlined LR(0) item (see {@link LRItem}) and an index within the - * sentence being parsed where the parse state began. + * An Earley parser parse state. Consists of an inlined LR(0) item (see {@link LRItem}) and an + * index within the sentence being parsed where the parse state began. * - * Each parse state also has a parse tree associated with it, in the form of a Set> object. - * Each element in the set represents a single possible parse at this state, with one element in the PStack for each - * non-terminal left of the "dot" on the right-hand-side of the production. + *

Each parse state also has a parse tree associated with it, in the form of a + * Set> object. Each element in the set represents a single possible parse at this + * state, with one element in the PStack for each non-terminal left of the "dot" on the + * right-hand-side of the production. * - * Additionally, we compute the value `ntItem` which corresponds to the number of non-terminals left of the "dot" in - * the LR(0) item this state corresponds to. + *

Additionally, we compute the value `ntItem` which corresponds to the number of non-terminals + * left of the "dot" in the LR(0) item this state corresponds to. */ private static final class EarleyState { public EarleyState(EarleyProduction prod, int item, int start) { @@ -274,9 +290,9 @@ public Set> parseTree() { } /** - * A wrapper around a {@link Set} representing the parse trees that can be parsed for a particular non-terminal - * over a particular range of the input. This information is deduplicated across multiple parse states in order to - * preserve sharing in the resulting parse forest. + * A wrapper around a {@link Set} representing the parse trees that can be parsed for a + * particular non-terminal over a particular range of the input. This information is deduplicated + * across multiple parse states in order to preserve sharing in the resulting parse forest. */ private static final class CompleteParseTreeNode { Set derivations; @@ -287,8 +303,8 @@ public CompleteParseTreeNode() { } /** - * Compute the CompleteParseTreeNode for a non-terminal and an input range from a parse tree that is - * part of an {@link EarleyState} which has parsed an entire production. + * Compute the CompleteParseTreeNode for a non-terminal and an input range from a parse tree that + * is part of an {@link EarleyState} which has parsed an entire production. * * @param parses The set of parses to add new derivations to. * @param parseTree The parse tree of the {@link EarleyState} being processed. @@ -297,7 +313,13 @@ public CompleteParseTreeNode() { * @param end The end-index of the input range that was parsed. * @param data The {@link ParserMetadata} about the current sentence being parsed. */ - private static void wrapState(Set parses, Set> parseTree, EarleyProduction eprod, int start, int end, ParserMetadata data) { + private static void wrapState( + Set parses, + Set> parseTree, + EarleyProduction eprod, + int start, + int end, + ParserMetadata data) { byte[] utf8Input = StringUtils.getBytesUtf8(data.input); for (PStack children : parseTree) { @@ -308,7 +330,7 @@ private static void wrapState(Set parses, Set> parseTree, Ear int startLoc = data.words[start].startLoc; int endLoc; if (start != end) { - endLoc = data.words[end-1].endLoc; + endLoc = data.words[end - 1].endLoc; } else { endLoc = data.words[end].endLoc; } @@ -323,7 +345,8 @@ private static void wrapState(Set parses, Set> parseTree, Ear // Note that startLoc and endLoc refer to indices into the UTF-8 encoded byte array String value = StringUtils.newStringUtf8(Arrays.copyOfRange(utf8Input, startLoc, endLoc)); if (eprod.isMInt()) { - // it's an MInt token, so make sure to add the correct bit-length to the production before creating the + // it's an MInt token, so make sure to add the correct bit-length to the production before + // creating the // Constant int index = value.indexOf('p'); if (index == -1) { @@ -348,23 +371,26 @@ private static void wrapState(Set parses, Set> parseTree, Ear /** * A set of {@link EarleyState EarleyStates}. * - * Each set corresponds to a particular end-index within the sentence being parsed, and contains all states that end - * at that index. Being a set, duplicate states are combined. For the purposes of deduplication, we only consider the - * production, start index, and "dot" of a state. We use a list of mappings from states to themselves in order to - * deduplicate states. When a state is re-added, the parse tree is merged with the one already in the set. + *

Each set corresponds to a particular end-index within the sentence being parsed, and + * contains all states that end at that index. Being a set, duplicate states are combined. For the + * purposes of deduplication, we only consider the production, start index, and "dot" of a state. + * We use a list of mappings from states to themselves in order to deduplicate states. When a + * state is re-added, the parse tree is merged with the one already in the set. * - * Each set also stores a 2D array of {@link CompleteParseTreeNode CompleteParseTreeNodes} which are used to - * deduplicate the parse trees from parse states that have finished processing a production. This implements the - * invariant that a tuple (S, i, j) for a particular sort, start-index, and end-index must exist only once in the - * parse forest. + *

Each set also stores a 2D array of {@link CompleteParseTreeNode CompleteParseTreeNodes} + * which are used to deduplicate the parse trees from parse states that have finished processing a + * production. This implements the invariant that a tuple (S, i, j) for a particular sort, + * start-index, and end-index must exist only once in the parse forest. * - * Finally, each set also stores a mapping from sorts to lists of states that is used by the complete function of - * the parser in order to identify which states need to be advanced past a particular non-terminal when a production - * is completed (i.e., the "dot" reaches the end of the production). + *

Finally, each set also stores a mapping from sorts to lists of states that is used by the + * complete function of the parser in order to identify which states need to be advanced past a + * particular non-terminal when a production is completed (i.e., the "dot" reaches the end of the + * production). * - * EarleySet implements a concurrent iterator for states. i.e., as long as states are only ever added to the end of - * the list, it is possible to iterate over the entire set one element at a time even if elements are added during - * the iteration process. This invariant is preserved by the code. + *

EarleySet implements a concurrent iterator for states. i.e., as long as states are only ever + * added to the end of the list, it is possible to iterate over the entire set one element at a + * time even if elements are added during the iteration process. This invariant is preserved by + * the code. */ private static final class EarleySet implements Iterable { private final List states = new ArrayList<>(); @@ -381,7 +407,7 @@ private static final class EarleySet implements Iterable { public EarleySet(int index, int nsorts) { this.index = index; this.nsorts = nsorts; - membership = new ArrayList<>(index+1); + membership = new ArrayList<>(index + 1); for (int i = 0; i <= index; i++) { membership.add(new HashMap<>()); } @@ -397,6 +423,7 @@ public Iterator iterator() { private class EarleySetIterator implements Iterator { int idx = 0; + public boolean hasNext() { return idx < states.size(); } @@ -408,6 +435,7 @@ public EarleyState next() { /** * Obtain the parse tree associated with a tuple (S, i, j) of sort, start-index, and end-index. + * * @param sort The sort that was just parsed. * @param start The start-index that the production was parsed from. * @return The unique parse tree node associated with that sort, start-index, and end-index. @@ -415,7 +443,7 @@ public EarleyState next() { private Set completedParses(int sort, int start) { CompleteParseTreeNode[][] nodes = completedParseTrees; if (nodes == null) { - nodes = new CompleteParseTreeNode[index+1][nsorts]; + nodes = new CompleteParseTreeNode[index + 1][nsorts]; completedParseTrees = nodes; } CompleteParseTreeNode node = nodes[start][sort]; @@ -464,8 +492,9 @@ public void add(EarleyState state, ParserMetadata data) { states.add(state); // compute metadata about new state membership.get(state.start).put(state, state); - if (state.item != state.prod.items.size() && state.prod.items.get(state.item).isNonTerminal()) { - EarleyNonTerminal nt = (EarleyNonTerminal)state.prod.items.get(state.item); + if (state.item != state.prod.items.size() + && state.prod.items.get(state.item).isNonTerminal()) { + EarleyNonTerminal nt = (EarleyNonTerminal) state.prod.items.get(state.item); completor.get(nt.sort).add(state); } else if (state.item == state.prod.items.size()) { // if the state is complete, add the proper derivations to the CompleteParseTreeNode @@ -489,9 +518,7 @@ public List completor(int sort) { return completor.get(sort); } - /** - * Finalize the set by cleaning up, after all states have been added to it. - */ + /** Finalize the set by cleaning up, after all states have been added to it. */ public void finish() { membership = null; completedParseTrees = null; @@ -499,8 +526,8 @@ public void finish() { } /** - * Metadata about the state of the sentence being parsed. We collect this all in a single place in order to simplify - * the type signatures of many methods. + * Metadata about the state of the sentence being parsed. We collect this all in a single place in + * order to simplify the type signatures of many methods. */ public static class ParserMetadata { /** @@ -510,16 +537,18 @@ public static class ParserMetadata { * @param startLine The line the sentence started on. * @param startColumn The column the sentence started on. */ - public ParserMetadata(String input, Scanner scanner, Source source, int startLine, int startColumn) { + public ParserMetadata( + String input, Scanner scanner, Source source, int startLine, int startColumn) { // compute location info byte[] utf8 = StringUtils.getBytesUtf8(input); - int[] lines = new int[utf8.length+1]; - int[] columns = new int[utf8.length+1]; + int[] lines = new int[utf8.length + 1]; + int[] columns = new int[utf8.length + 1]; int l = startLine; int c = startColumn; int length = input.codePointCount(0, input.length()); - for (int offset = 0, utf8offset = 0, codepoint, numBytes; offset < length; offset += Character.charCount(codepoint), - utf8offset += numBytes) { + for (int offset = 0, utf8offset = 0, codepoint, numBytes; + offset < length; + offset += Character.charCount(codepoint), utf8offset += numBytes) { codepoint = input.codePointAt(offset); numBytes = StringUtils.getBytesUtf8(new String(Character.toChars(codepoint))).length; for (int i = 0; i < numBytes; i++) { @@ -528,30 +557,32 @@ public ParserMetadata(String input, Scanner scanner, Source source, int startLin } switch (input.codePointAt(offset)) { - case '\r' : - if (offset+1 < input.length()) { - if (input.charAt(offset+1) == '\n') { - lines[offset+1] = l; - columns[offset+1] = c + 1; + case '\r': + if (offset + 1 < input.length()) { + if (input.charAt(offset + 1) == '\n') { + lines[offset + 1] = l; + columns[offset + 1] = c + 1; offset++; utf8offset++; } } - case '\n' : - case '\u000B' : - case '\u000C' : - case '\u0085' : - case '\u2028' : - case '\u2029' : - l++; c = 1; break; - default : + case '\n': + case '\u000B': + case '\u000C': + case '\u0085': + case '\u2028': + case '\u2029': + l++; + c = 1; + break; + default: c++; } } lines[utf8.length] = l; columns[utf8.length] = c; - //initialize + // initialize this.words = scanner.tokenize(input, source, lines, columns); this.lines = lines; this.columns = columns; @@ -597,7 +628,7 @@ public EarleyParser(Module m, Scanner scanner, Sort startSymbol, boolean partial productions = getProductions(m, scanner, startSymbol); predictor = getPredictor(); - //compute nullability + // compute nullability Set nullable = new HashSet<>(); List> callers = getCallers(); this.nullable = new BitSet(sorts.size()); @@ -605,7 +636,7 @@ public EarleyParser(Module m, Scanner scanner, Sort startSymbol, boolean partial markNullable(new LRItem(prod, 0), nullable, callers); } - //compute first set + // compute first set first = computeFirstSet(); } @@ -618,7 +649,8 @@ private Map getSorts(Module m) { sorts.put(nullSort, 1); sortList.add(nullSort); int i = 2; - // some weirdness that turns out to be necessary due to how we implement MInt in RuleGrammarGenerator + // some weirdness that turns out to be necessary due to how we implement MInt in + // RuleGrammarGenerator for (SortHead sortHead : iterable(m.definedInstantiations().keySet())) { Sort nonsenseSort = Sort(sortHead.name(), Seq(Sorts.K())); if (!m.allSorts().contains(nonsenseSort)) { @@ -636,7 +668,15 @@ private Map getSorts(Module m) { private List getProductions(Module m, Scanner scanner, Sort startSymbol) { final List productions; productions = new ArrayList<>(m.productions().size()); - productions.add(new EarleyProduction(0, null, 0, Arrays.asList(new EarleyNonTerminal(sorts.get(startSymbol), sortList), new EarleyTerminal(scanner, 0)), sortList)); + productions.add( + new EarleyProduction( + 0, + null, + 0, + Arrays.asList( + new EarleyNonTerminal(sorts.get(startSymbol), sortList), + new EarleyTerminal(scanner, 0)), + sortList)); int index = 1; for (Production prod : iterable(m.productions())) { if (prod.params().size() != 0) { @@ -656,22 +696,22 @@ private List getProductions(Module m, Scanner scanner, Sort st if (original.isPresent()) { prodToUse = original.get(); } - productions.add(new EarleyProduction(index++, prodToUse, sorts.get(prod.sort()), items, sortList)); - + productions.add( + new EarleyProduction(index++, prodToUse, sorts.get(prod.sort()), items, sortList)); } return productions; } private EarleyProductionItem toEarley(ProductionItem item, Scanner scanner) { if (item instanceof NonTerminal) { - Integer sort = sorts.get(((NonTerminal)item).sort()); + Integer sort = sorts.get(((NonTerminal) item).sort()); // sort may be null because private module imports may cause sort declarations to be missing if (sort == null) { sort = 1; // , a sort with no productions } return new EarleyNonTerminal(sort, sortList); } else { - return new EarleyTerminal(scanner, scanner.resolve((TerminalLike)item)); + return new EarleyTerminal(scanner, scanner.resolve((TerminalLike) item)); } } @@ -709,13 +749,13 @@ private void markNullable(LRItem state, Set nullable, List> nullable.add(state); if (state.item < state.prod.items.size()) { if (state.prod.items.get(state.item).isNullable(this.nullable)) { - markNullable(new LRItem(state.prod, state.item+1), nullable, callers); + markNullable(new LRItem(state.prod, state.item + 1), nullable, callers); } } else { this.nullable.set(state.prod.sort); for (LRItem s : callers.get(state.prod.sort)) { if (nullable.contains(s)) { - markNullable(new LRItem(s.prod, s.item+1), nullable, callers); + markNullable(new LRItem(s.prod, s.item + 1), nullable, callers); } } } @@ -733,13 +773,13 @@ private BitSet[] computeFirstSet() { do { dirty = false; for (int sort = 0; sort < sorts.size(); sort++) { -production: + production: for (EarleyProduction prod : predictor.get(sort)) { if (!prod.items.isEmpty()) { for (int i = 0; i < prod.items.size(); i++) { EarleyProductionItem item = prod.items.get(i); if (item.isNonTerminal()) { - EarleyNonTerminal nt = (EarleyNonTerminal)item; + EarleyNonTerminal nt = (EarleyNonTerminal) item; BitSet old = new BitSet(arraySize); BitSet curr = first[sort]; old.or(curr); @@ -749,7 +789,7 @@ private BitSet[] computeFirstSet() { continue production; } } else if (once) { - EarleyTerminal t = (EarleyTerminal)item; + EarleyTerminal t = (EarleyTerminal) item; dirty = dirty || !first[sort].get(t.kind); first[sort].set(t.kind); continue production; @@ -782,6 +822,7 @@ private BitSet[] computeFirstSet() { /** * Parse a sentence according to the grammar represented by this parser. + * * @param input The sentence to parse. * @param source The {@link Source} representing the file the string comes from. * @param startLine The line the sentence starts on. @@ -809,10 +850,11 @@ public Term parse(String input, Source source, int startLine, int startColumn) { for (int k = 0; k < data.words.length; k++) { // for each position in the tokenized sentence, compute S[k] and Q EarleySet Q = Qprime; - Qprime = new EarleySet(k+1, sorts.size()); + Qprime = new EarleySet(k + 1, sorts.size()); // loop through S[k] and process each state, predicting and completing it for (EarleyState state : S.get(k)) { - if (state.item != state.prod.items.size() && state.prod.items.get(state.item).isNonTerminal()) { + if (state.item != state.prod.items.size() + && state.prod.items.get(state.item).isNonTerminal()) { // state is ready to process a non-terminal, therefore predict predict(S, Q, state, k, data); } else { @@ -828,42 +870,51 @@ public Term parse(String input, Source source, int startLine, int startColumn) { scan(S, Qprime, state, k, data); } - // this loop condition is a bit tricky because we want to stop at the exact loop iteration that parsing failed - // in order to generate the correct error message. Nominally speaking, parsing succeeds if after all loop - // iterations, S[data.words.length] contains the state (productions.get(0), 2, 0). However, if S[k+1] is empty and - // Q is empty at this point, then Qprime must also be empty. Thus, if k+1==data.words.length, S[data.words.length] - // is empty, which means it's a parse error. And if k+1 list.get(0)).collect(Collectors.toSet())); + return Ambiguity.apply( + S.get(data.words.length).states.get(0).parseTree().stream() + .map(list -> list.get(0)) + .collect(Collectors.toSet())); } // We are only interested in displaying states that span the entire input // when a parse error occurs; such states have a start-index of 0. private Set spanningStates(EarleySet parses) { - return parses.states.stream() - .filter(state -> state.start == 0) - .collect(Collectors.toSet()); + return parses.states.stream().filter(state -> state.start == 0).collect(Collectors.toSet()); } // We heuristically identify the best state-set for producing diagnostics as the // most recent such set that includes a _spanning state_; i.e. one with a start // index of zero. private Set bestDiagnosticStates(List S, int k) { - for(int i = k; i >= 0; --i) { + for (int i = k; i >= 0; --i) { Set candidate = spanningStates(S.get(i)); - if(!candidate.isEmpty()) { + if (!candidate.isEmpty()) { return candidate; } } @@ -872,26 +923,26 @@ private Set bestDiagnosticStates(List S, int k) { } private String partialParseTreesDiagnostic(Set spanningStates) { - if(spanningStates.isEmpty()) { + if (spanningStates.isEmpty()) { return "No top-level production could apply to this input."; } StringBuilder msg = new StringBuilder(); - for(EarleyState state : spanningStates) { + for (EarleyState state : spanningStates) { msg.append(" Attempting to apply production:\n ").append(state.prod).append("\n"); - for(PStack possibleTree : state.parseTree()) { - var cleanedChildren = possibleTree - .stream() + for (PStack possibleTree : state.parseTree()) { + var cleanedChildren = + possibleTree.stream() .map(term -> new TreeCleanerVisitor().apply(term)) .collect(Collectors.toList()); - if(state.prod.prod.klabel().isDefined()) { + if (state.prod.prod.klabel().isDefined()) { var term = TermCons.apply(ConsPStack.from(cleanedChildren), state.prod.prod); msg.append(" produced partial term:\n ").append(term).append("\n"); } else { msg.append(" produced partial term with no KLabel, and children:\n"); - for(var child : cleanedChildren) { + for (var child : cleanedChildren) { msg.append(" ").append(child).append("\n"); } } @@ -904,7 +955,8 @@ private String partialParseTreesDiagnostic(Set spanningStates) { /** * @param data The {@link ParserMetadata} about the sentence being parsed * @param S The set of {@link EarleyState}s for each end-index in the input - * @param k The end-index at which a parse error occurred. In other words, the index just prior to the first token that + * @param k The end-index at which a parse error occurred. In other words, the index just prior to + * the first token that */ private void parseError(ParserMetadata data, List S, int k) { int startLine, startColumn, endLine, endColumn; @@ -920,18 +972,18 @@ private void parseError(ParserMetadata data, List S, int k) { endLine = data.lines[t.endLoc]; endColumn = data.columns[t.endLoc]; } - String msg = data.words.length-1 == k ? - "Parse error: unexpected end of file" : - "Parse error: unexpected token '" + data.words[k].value + "'"; + String msg = + data.words.length - 1 == k + ? "Parse error: unexpected end of file" + : "Parse error: unexpected token '" + data.words[k].value + "'"; if (k != 0) { msg = msg + " following token '" + data.words[k - 1].value + "'."; } else { msg = msg + "."; } - Location loc = new Location(startLine, startColumn, - endLine, endColumn); + Location loc = new Location(startLine, startColumn, endLine, endColumn); - if(partialParseDebug) { + if (partialParseDebug) { msg += " Additional parsing diagnostic information:\n"; msg += partialParseTreesDiagnostic(bestDiagnosticStates(S, k)); } @@ -940,6 +992,7 @@ private void parseError(ParserMetadata data, List S, int k) { } private static final Set> EMPTY_PARSE_TREE = new HashSet<>(); + static { EMPTY_PARSE_TREE.add(ConsPStack.empty()); } @@ -953,8 +1006,9 @@ private void parseError(ParserMetadata data, List S, int k) { * @param k the current end-index being parsed * @param data The {@link ParserMetadata} about the sentence being parsed */ - private void predict(List S, EarleySet Q, EarleyState state, int k, ParserMetadata data) { - EarleyNonTerminal nt = (EarleyNonTerminal)state.prod.items.get(state.item); + private void predict( + List S, EarleySet Q, EarleyState state, int k, ParserMetadata data) { + EarleyNonTerminal nt = (EarleyNonTerminal) state.prod.items.get(state.item); // first, use lookahead to check if we need to predict this sort at all if (nullable.get(nt.sort) || first[nt.sort].get(data.words[k].kind)) { List prods = predictor.get(nt.sort); @@ -962,7 +1016,7 @@ private void predict(List S, EarleySet Q, EarleyState state, int k, P // for each production for the sort being predicted, add it to the appropriate set if (next.items.size() != 0 && !next.items.get(0).isNonTerminal()) { // if it's a terminal, add it to be scanned only if the next token matches - EarleyTerminal t = (EarleyTerminal)next.items.get(0); + EarleyTerminal t = (EarleyTerminal) next.items.get(0); if (t.kind == data.words[k].kind) { // if it matches, add (next, 0, k) to Q EarleyState nextState = new EarleyState(next, 0, k); @@ -978,7 +1032,7 @@ private void predict(List S, EarleySet Q, EarleyState state, int k, P if (nullable.get(nt.sort)) { // non-terminal is nullable, so complete the state by advancing past the nullable sort. // see Aycock and Horspool - EarleyState nextState = new EarleyState(state.prod, state.item+1, state.start); + EarleyState nextState = new EarleyState(state.prod, state.item + 1, state.start); nextState.parseTree = new HashSet<>(); wrapAndAppend(nt.sort, k, nextState, state, S.get(k)); addStateToSet(S, Q, state, nextState, k, data); @@ -994,16 +1048,18 @@ private void predict(List S, EarleySet Q, EarleyState state, int k, P * @param k the current end-index being parsed * @param data The {@link ParserMetadata} about the sentence being parsed */ - private void scan(List S, EarleySet Qprime, EarleyState state, int k, ParserMetadata data) { + private void scan( + List S, EarleySet Qprime, EarleyState state, int k, ParserMetadata data) { // construct next state - EarleyState nextState = new EarleyState(state.prod, state.item+1, state.start); + EarleyState nextState = new EarleyState(state.prod, state.item + 1, state.start); nextState.parseTree = state.parseTree; - addStateToSet(S, Qprime, state, nextState, k+1, data); + addStateToSet(S, Qprime, state, nextState, k + 1, data); } /** - * Add a state to either S or Q depending on whether the next production item to parse is a terminal or a - * non-terminal. May be added to neither if the next state expects a terminal not found next in the input. + * Add a state to either S or Q depending on whether the next production item to parse is a + * terminal or a non-terminal. May be added to neither if the next state expects a terminal not + * found next in the input. * * @param S The {@link EarleySet EarleySets} for completion and prediction. * @param Q The {@link EarleySet} for scanning @@ -1012,10 +1068,17 @@ private void scan(List S, EarleySet Qprime, EarleyState state, int k, * @param k the current end-index being parsed. * @param data The {@link ParserMetadata} about the sentence being parsed. */ - private void addStateToSet(List S, EarleySet Q, EarleyState state, EarleyState nextState, int k, ParserMetadata data) { + private void addStateToSet( + List S, + EarleySet Q, + EarleyState state, + EarleyState nextState, + int k, + ParserMetadata data) { // if the next item in the state is a terminal, scan it and possibly add it to Q' - if (state.item+1 != state.prod.items.size() && !state.prod.items.get(state.item+1).isNonTerminal()) { - EarleyTerminal t = (EarleyTerminal) state.prod.items.get(state.item+1); + if (state.item + 1 != state.prod.items.size() + && !state.prod.items.get(state.item + 1).isNonTerminal()) { + EarleyTerminal t = (EarleyTerminal) state.prod.items.get(state.item + 1); if (t.kind == data.words[k].kind) { Q.add(nextState, data); } @@ -1034,10 +1097,13 @@ private void addStateToSet(List S, EarleySet Q, EarleyState state, Ea * @param k the current end-index being parsed * @param data The {@link ParserMetadata} about the sentence being parsed */ - private void complete(List S, EarleySet Q, EarleyState state, int k, ParserMetadata data) { - // this state is nullable, therefore we need to compute its parse tree since it was not given one yet + private void complete( + List S, EarleySet Q, EarleyState state, int k, ParserMetadata data) { + // this state is nullable, therefore we need to compute its parse tree since it was not given + // one yet List completedStates = S.get(state.start).completor(state.prod.sort); - // for each state in S[state.start] that is waiting on the non-terminal corresponding to state.prod.sort + // for each state in S[state.start] that is waiting on the non-terminal corresponding to + // state.prod.sort for (EarleyState completed : completedStates) { // construct next state EarleyState nextState = new EarleyState(completed.prod, completed.item + 1, completed.start); @@ -1049,16 +1115,18 @@ private void complete(List S, EarleySet Q, EarleyState state, int k, } /** - * Construct the new parse tree for a state during the "complete" step, or after a nullable non-terminal in the - * "predict" step. + * Construct the new parse tree for a state during the "complete" step, or after a nullable + * non-terminal in the "predict" step. * * @param sort The sort that was just parsed. * @param start The start-index of the state being processed. * @param nextState The {@link EarleyState} to add the parse tree derivations to. - * @param completed The {@link EarleyState} containing the parse tree prior to processing this non-terminal. + * @param completed The {@link EarleyState} containing the parse tree prior to processing this + * non-terminal. * @param end The {@link EarleySet} representing the end-index being processed by the parser. */ - private void wrapAndAppend(int sort, int start, EarleyState nextState, EarleyState completed, EarleySet end) { + private void wrapAndAppend( + int sort, int start, EarleyState nextState, EarleyState completed, EarleySet end) { Term newTerm = Ambiguity.apply(end.completedParses(sort, start)); for (PStack terms : completed.parseTree()) { nextState.parseTree.add(terms.plus(newTerm)); diff --git a/kernel/src/main/java/org/kframework/parser/inner/kernel/KSyntax2Bison.java b/kernel/src/main/java/org/kframework/parser/inner/kernel/KSyntax2Bison.java index 83ce516a63e..ca34c3e4284 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/kernel/KSyntax2Bison.java +++ b/kernel/src/main/java/org/kframework/parser/inner/kernel/KSyntax2Bison.java @@ -1,10 +1,26 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.kernel; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.mutable.MutableInt; import org.kframework.Collections; -import org.kframework.TopologicalSort; import org.kframework.attributes.Att; import org.kframework.backend.kore.ModuleToKORE; import org.kframework.definition.Module; @@ -18,39 +34,29 @@ import org.kframework.definition.TerminalLike; import org.kframework.kore.KLabel; import org.kframework.kore.Sort; -import org.kframework.parser.inner.RuleGrammarGenerator; import org.kframework.utils.StringUtil; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KException.ExceptionType; import org.kframework.utils.errorsystem.KExceptionManager; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - import scala.Tuple2; -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - public class KSyntax2Bison { - private static void computeSide(int idx, Production prod, List items, Module module, scala.collection.Set> assoc, Map, Integer> ordinals, Set>> nts, MutableInt nextOrdinal) { + private static void computeSide( + int idx, + Production prod, + List items, + Module module, + scala.collection.Set> assoc, + Map, Integer> ordinals, + Set>> nts, + MutableInt nextOrdinal) { NonTerminal nt = (NonTerminal) items.get(idx); Tag parent = new Tag(prod.klabel().get().name()); Set prods = new HashSet<>(); - for (Tag child : iterable(module.priorities().relations().get(parent).getOrElse(() -> Collections.Set()))) { + for (Tag child : + iterable( + module.priorities().relations().get(parent).getOrElse(() -> Collections.Set()))) { prods.add(child); } for (Tuple2 entry : iterable(assoc)) { @@ -69,7 +75,8 @@ private static void computeSide(int idx, Production prod, List i ordinals.put(prods, nextOrdinal.intValue()); nextOrdinal.increment(); } - items.set(idx, NonTerminal(Sort(nt.sort().name() + "#" + ordinal, nt.sort().params()), nt.name())); + items.set( + idx, NonTerminal(Sort(nt.sort().name() + "#" + ordinal, nt.sort().params()), nt.name())); nts.add(Tuple2.apply(nt.sort(), prods)); } @@ -86,9 +93,23 @@ public static Module transformByPriorityAndAssociativity(Module module) { computeSide(0, prod, items, module, module.rightAssoc(), ordinals, nts, nextOrdinal); } if (items.size() > 1 && items.get(items.size() - 1) instanceof NonTerminal) { - computeSide(items.size()-1, prod, items, module, module.leftAssoc(), ordinals, nts, nextOrdinal); + computeSide( + items.size() - 1, + prod, + items, + module, + module.leftAssoc(), + ordinals, + nts, + nextOrdinal); } - sentences.add(Production(prod.klabel(), prod.params(), prod.sort(), immutable(items), prod.att().add(Att.ORIGINAL_PRD(), Production.class, prod))); + sentences.add( + Production( + prod.klabel(), + prod.params(), + prod.sort(), + immutable(items), + prod.att().add(Att.ORIGINAL_PRD(), Production.class, prod))); } else { sentences.add(prod.withAtt(prod.att().add(Att.ORIGINAL_PRD(), Production.class, prod))); } @@ -101,13 +122,25 @@ public static Module transformByPriorityAndAssociativity(Module module) { worklist.addAll(nts); while (!worklist.isEmpty()) { Tuple2> item = worklist.poll(); - for (Production prod : iterable(module.productionsForSort().get(item._1().head()).getOrElse(() -> Collections.Seq()))) { + for (Production prod : + iterable( + module + .productionsForSort() + .get(item._1().head()) + .getOrElse(() -> Collections.Seq()))) { int ordinal = ordinals.get(item._2()); Sort newNT = Sort(item._1().name() + "#" + ordinal, item._1().params()); if (prod.isSubsort()) { worklist.offer(Tuple2.apply(prod.getSubsortSort(), item._2())); - sentences.add(Production(prod.klabel(), prod.params(), newNT, Seq(NonTerminal(prod.getSubsortSort(), prod.nonterminals().apply(0).name())), prod.att())); - } else if (prod.klabel().isEmpty() || !item._2().contains(new Tag(prod.klabel().get().name()))) { + sentences.add( + Production( + prod.klabel(), + prod.params(), + newNT, + Seq(NonTerminal(prod.getSubsortSort(), prod.nonterminals().apply(0).name())), + prod.att())); + } else if (prod.klabel().isEmpty() + || !item._2().contains(new Tag(prod.klabel().get().name()))) { sentences.add(Production(prod.klabel(), prod.params(), newNT, prod.items(), prod.att())); } } @@ -115,55 +148,73 @@ public static Module transformByPriorityAndAssociativity(Module module) { return Module(module.name(), module.imports(), immutable(sentences), module.att()); } - public static void writeParser(Module module, Module disambModule, Scanner scanner, Sort start, File path, boolean glr, long stackDepth, KExceptionManager kem) { + public static void writeParser( + Module module, + Module disambModule, + Scanner scanner, + Sort start, + File path, + boolean glr, + long stackDepth, + KExceptionManager kem) { if (module.att().contains(Att.NOT_LR1_MODULES())) { - kem.registerInnerParserWarning(ExceptionType.NON_LR_GRAMMAR, "Skipping modules " + module.att().get(Att.NOT_LR1_MODULES()) + " tagged as " + Att.NOT_LR1() + " which are not supported by Bison."); + kem.registerInnerParserWarning( + ExceptionType.NON_LR_GRAMMAR, + "Skipping modules " + + module.att().get(Att.NOT_LR1_MODULES()) + + " tagged as " + + Att.NOT_LR1() + + " which are not supported by Bison."); } module = transformByPriorityAndAssociativity(module); StringBuilder bison = new StringBuilder(); - bison.append("%{\n" + - "#include \n" + - "#include \n" + - "#include \"node.h\"\n" + - "#include \"parser.tab.h\"\n" + - "int yylex(YYSTYPE *, YYLTYPE *, void *);\n" + - "void yyerror(YYLTYPE *, void *, const char *);\n" + - "char *enquote(char *);\n" + - "char *injSymbol(char *, char *);\n" + - "YYSTYPE mergeAmb(YYSTYPE x0, YYSTYPE x1);\n" + - "node *result;\n" + - "extern char *filename;\n" + - "# define YYMAXDEPTH " + stackDepth + "\n" + - "# define YYLLOC_DEFAULT(Cur, Rhs, N) \\\n" + - "do \\\n" + - " if (N) \\\n" + - " { \\\n" + - " (Cur).filename = YYRHSLOC(Rhs, 1).filename; \\\n" + - " (Cur).first_line = YYRHSLOC(Rhs, 1).first_line; \\\n" + - " (Cur).first_column = YYRHSLOC(Rhs, 1).first_column; \\\n" + - " (Cur).last_line = YYRHSLOC(Rhs, N).last_line; \\\n" + - " (Cur).last_column = YYRHSLOC(Rhs, N).last_column; \\\n" + - " } \\\n" + - " else \\\n" + - " { \\\n" + - " (Cur).filename = YYRHSLOC(Rhs, 0).filename; \\\n" + - " (Cur).first_line = (Cur).last_line = \\\n" + - " YYRHSLOC(Rhs, 0).last_line; \\\n" + - " (Cur).first_column = (Cur).last_column = \\\n" + - " YYRHSLOC(Rhs, 0).last_column; \\\n" + - " } \\\n" + - "while (0)\n" + - "%}\n\n"); + bison.append( + "%{\n" + + "#include \n" + + "#include \n" + + "#include \"node.h\"\n" + + "#include \"parser.tab.h\"\n" + + "int yylex(YYSTYPE *, YYLTYPE *, void *);\n" + + "void yyerror(YYLTYPE *, void *, const char *);\n" + + "char *enquote(char *);\n" + + "char *injSymbol(char *, char *);\n" + + "YYSTYPE mergeAmb(YYSTYPE x0, YYSTYPE x1);\n" + + "node *result;\n" + + "extern char *filename;\n" + + "# define YYMAXDEPTH " + + stackDepth + + "\n" + + "# define YYLLOC_DEFAULT(Cur, Rhs, N) \\\n" + + "do \\\n" + + " if (N) \\\n" + + " { \\\n" + + " (Cur).filename = YYRHSLOC(Rhs, 1).filename; \\\n" + + " (Cur).first_line = YYRHSLOC(Rhs, 1).first_line; \\\n" + + " (Cur).first_column = YYRHSLOC(Rhs, 1).first_column; \\\n" + + " (Cur).last_line = YYRHSLOC(Rhs, N).last_line; \\\n" + + " (Cur).last_column = YYRHSLOC(Rhs, N).last_column; \\\n" + + " } \\\n" + + " else \\\n" + + " { \\\n" + + " (Cur).filename = YYRHSLOC(Rhs, 0).filename; \\\n" + + " (Cur).first_line = (Cur).last_line = \\\n" + + " YYRHSLOC(Rhs, 0).last_line; \\\n" + + " (Cur).first_column = (Cur).last_column = \\\n" + + " YYRHSLOC(Rhs, 0).last_column; \\\n" + + " } \\\n" + + "while (0)\n" + + "%}\n\n"); bison.append("%define api.value.type {union value_type}\n"); bison.append("%define api.pure\n"); bison.append("%define lr.type ielr\n"); bison.append("%lex-param {void *scanner} \n"); bison.append("%parse-param {void *scanner} \n"); bison.append("%locations\n"); - bison.append("%initial-action {\n" + - " @$.filename = filename;\n" + - " @$.first_line = @$.first_column = @$.last_line = @$.last_column = 1;\n" + - "}\n"); + bison.append( + "%initial-action {\n" + + " @$.filename = filename;\n" + + " @$.first_line = @$.first_column = @$.last_line = @$.last_column = 1;\n" + + "}\n"); if (glr) { bison.append("%glr-parser\n"); } @@ -172,15 +223,17 @@ public static void writeParser(Module module, Module disambModule, Scanner scann TerminalLike tok = scanner.getTokenByKind(kind); String val; if (tok instanceof Terminal) { - val = ((Terminal)tok).value(); + val = ((Terminal) tok).value(); } else { - val = ((RegexTerminal)tok).regex(); + val = ((RegexTerminal) tok).regex(); } - bison.append("%token TOK_" + kind + " " + (kind+1) + " " + StringUtil.enquoteCString(val) + "\n"); + bison.append( + "%token TOK_" + kind + " " + (kind + 1) + " " + StringUtil.enquoteCString(val) + "\n"); } - //compute sorts reachable from start symbol - Map> prods = stream(module.productions()).collect(Collectors.groupingBy(p -> p.sort())); + // compute sorts reachable from start symbol + Map> prods = + stream(module.productions()).collect(Collectors.groupingBy(p -> p.sort())); Set reachableSorts = new HashSet<>(); Deque workList = new ArrayDeque<>(); workList.offer(start); @@ -208,7 +261,8 @@ public static void writeParser(Module module, Module disambModule, Scanner scann encode(start, bison); bison.append(" { result = $1.nterm; } ;\n"); for (Sort sort : reachableSorts) { - List prodsForSort = Optional.ofNullable(prods.get(sort)).orElse(java.util.Collections.emptyList()); + List prodsForSort = + Optional.ofNullable(prods.get(sort)).orElse(java.util.Collections.emptyList()); if (!prodsForSort.isEmpty()) { encode(sort, bison); bison.append(":\n"); @@ -222,10 +276,13 @@ public static void writeParser(Module module, Module disambModule, Scanner scann } } bison.append("\n%%\n"); - bison.append("\n" + - "void yyerror (YYLTYPE *loc, void *scanner, const char *s) {\n" + - " fprintf (stderr, \"%s:%d:%d:%d:%d:%s\\n\", loc->filename, loc->first_line, loc->first_column, loc->last_line, loc->last_column, s);\n" + - "}\n"); + bison.append( + "\n" + + "void yyerror (YYLTYPE *loc, void *scanner, const char *s) {\n" + + " fprintf (stderr, \"%s:%d:%d:%d:%d:%s\\n" + + "\", loc->filename, loc->first_line, loc->first_column, loc->last_line," + + " loc->last_column, s);\n" + + "}\n"); try { FileUtils.write(path, bison); } catch (IOException e) { @@ -237,7 +294,8 @@ public static void writeParser(Module module, Module disambModule, Scanner scann private static void encode(Sort sort, StringBuilder sb) { sb.append("Sort"); - StringUtil.encodeStringToAlphanumeric(sb, sort.name(), StringUtil.asciiReadableEncodingDefault, identChar, "_"); + StringUtil.encodeStringToAlphanumeric( + sb, sort.name(), StringUtil.asciiReadableEncodingDefault, identChar, "_"); sb.append("_"); String conn = ""; for (Sort param : iterable(sort.params())) { @@ -248,12 +306,21 @@ private static void encode(Sort sort, StringBuilder sb) { sb.append("_"); } - private static void appendOverloadCondition(StringBuilder bison, Module module, Production greater, Production lesser, List nts) { + private static void appendOverloadCondition( + StringBuilder bison, + Module module, + Production greater, + Production lesser, + List nts) { bison.append("true"); for (int i = 0; i < nts.size(); i++) { - boolean hasSameSort = lesser.nonterminals().apply(i).sort().equals(greater.nonterminals().apply(i).sort()); + boolean hasSameSort = + lesser.nonterminals().apply(i).sort().equals(greater.nonterminals().apply(i).sort()); if (!hasSameSort) { - bison.append(" && strncmp($").append(nts.get(i)).append(".nterm->symbol, \"inj{\", 4) == 0 && (false"); + bison + .append(" && strncmp($") + .append(nts.get(i)) + .append(".nterm->symbol, \"inj{\", 4) == 0 && (false"); Sort greaterSort = lesser.nonterminals().apply(i).sort(); for (Sort lesserSort : iterable(module.subsorts().elements())) { if (module.subsorts().lessThanEq(lesserSort, greaterSort)) { @@ -267,67 +334,95 @@ private static void appendOverloadCondition(StringBuilder bison, Module module, } } - private static void appendOverloadChecks(StringBuilder bison, Module module, Module disambModule, Production greater, List nts, boolean hasLocation) { + private static void appendOverloadChecks( + StringBuilder bison, + Module module, + Module disambModule, + Production greater, + List nts, + boolean hasLocation) { for (Production lesser : iterable(disambModule.overloads().sortedElements())) { if (disambModule.overloads().lessThan(lesser, greater)) { bison.append(" if ("); appendOverloadCondition(bison, module, greater, lesser, nts); - bison.append(") {\n" + - " n->symbol =\""); + bison.append(") {\n" + " n->symbol =\""); encodeKore(lesser.klabel().get(), bison); - bison.append("\";\n" + - " n->sort = \""); + bison.append("\";\n" + " n->sort = \""); encodeKore(lesser.sort(), bison); - boolean hasLesserLocation = module.sortAttributesFor().get(lesser.sort().head()).getOrElse(() -> Att.empty()).contains(Att.LOCATIONS()); - bison.append("\";\n" + - " n->hasLocation = " + (hasLesserLocation ? "1" : "0") + ";\n"); + boolean hasLesserLocation = + module + .sortAttributesFor() + .get(lesser.sort().head()) + .getOrElse(() -> Att.empty()) + .contains(Att.LOCATIONS()); + bison.append("\";\n" + " n->hasLocation = " + (hasLesserLocation ? "1" : "0") + ";\n"); for (int i = 0; i < nts.size(); i++) { - boolean hasSameSort = lesser.nonterminals().apply(i).sort().equals(greater.nonterminals().apply(i).sort()); + boolean hasSameSort = + lesser.nonterminals().apply(i).sort().equals(greater.nonterminals().apply(i).sort()); if (hasSameSort) { - bison.append( - " n->children[").append(i).append("] = $").append(nts.get(i)).append(".nterm;\n"); + bison + .append(" n->children[") + .append(i) + .append("] = $") + .append(nts.get(i)) + .append(".nterm;\n"); } else { - bison.append( - " {\n" + - " node *origChild = $").append(nts.get(i)).append(".nterm;\n" + - " char *lesserSort = \""); + bison + .append(" {\n" + " node *origChild = $") + .append(nts.get(i)) + .append(".nterm;\n" + " char *lesserSort = \""); encodeKore(lesser.nonterminals().apply(i).sort(), bison); - bison.append("\";\n" + - " if (strcmp(origChild->children[0]->sort, lesserSort) == 0) {\n" + - " n->children[").append(i).append("] = origChild->children[0];\n" + - " } else {\n" + - " node *inj = malloc(sizeof(node) + sizeof(node *));\n" + - " inj->symbol = injSymbol(origChild->children[0]->sort, lesserSort);\n" + - " inj->str = false;\n" + - " inj->location = origChild->location;\n" + - " inj->nchildren = 1;\n" + - " inj->sort = lesserSort;\n" + - " inj->hasLocation = origChild->hasLocation;\n" + - " inj->children[0] = origChild->children[0];\n" + - " n->children[").append(i).append("] = inj;\n" + - " }\n" + - " }\n"); + bison + .append( + "\";\n" + + " if (strcmp(origChild->children[0]->sort, lesserSort) == 0) {\n" + + " n->children[") + .append(i) + .append( + "] = origChild->children[0];\n" + + " } else {\n" + + " node *inj = malloc(sizeof(node) + sizeof(node *));\n" + + " inj->symbol = injSymbol(origChild->children[0]->sort," + + " lesserSort);\n" + + " inj->str = false;\n" + + " inj->location = origChild->location;\n" + + " inj->nchildren = 1;\n" + + " inj->sort = lesserSort;\n" + + " inj->hasLocation = origChild->hasLocation;\n" + + " inj->children[0] = origChild->children[0];\n" + + " n->children[") + .append(i) + .append("] = inj;\n" + " }\n" + " }\n"); } } bison.append( - " node *n2 = malloc(sizeof(node) + sizeof(node *));\n" + - " n2->str = false;\n" + - " n2->location = @$;\n" + - " n2->nchildren = 1;\n" + - " n2->sort = \""); + " node *n2 = malloc(sizeof(node) + sizeof(node *));\n" + + " n2->str = false;\n" + + " n2->location = @$;\n" + + " n2->nchildren = 1;\n" + + " n2->sort = \""); encodeKore(greater.sort(), bison); - bison.append("\";\n" + - " n2->hasLocation = " + (hasLocation ? "1" : "0") + ";\n" + - " n2->symbol = injSymbol(n->sort, n2->sort);\n" + - " n2->children[0] = n;\n" + - " value_type result = {.nterm = n2};\n" + - " $$ = result;\n" + - " } else"); + bison.append( + "\";\n" + + " n2->hasLocation = " + + (hasLocation ? "1" : "0") + + ";\n" + + " n2->symbol = injSymbol(n->sort, n2->sort);\n" + + " n2->children[0] = n;\n" + + " value_type result = {.nterm = n2};\n" + + " $$ = result;\n" + + " } else"); } } } - private static void processProduction(Production prod, Module module, Module disambModule, Scanner scanner, StringBuilder bison, boolean glr) { + private static void processProduction( + Production prod, + Module module, + Module disambModule, + Scanner scanner, + StringBuilder bison, + boolean glr) { int i = 1; List nts = new ArrayList<>(); for (ProductionItem item : iterable(prod.items())) { @@ -336,8 +431,8 @@ private static void processProduction(Production prod, Module module, Module dis bison.append(" "); nts.add(i); } else { - TerminalLike t = (TerminalLike)item; - if (!(t instanceof Terminal && ((Terminal)t).value().equals(""))) { + TerminalLike t = (TerminalLike) item; + if (!(t instanceof Terminal && ((Terminal) t).value().equals(""))) { bison.append("TOK_" + scanner.resolve(t) + " "); } else { i--; @@ -352,13 +447,30 @@ private static void processProduction(Production prod, Module module, Module dis // list prod = prod.att().getOptional(Att.ORIGINAL_PRD(), Production.class).orElse(prod); } - boolean hasLocation = module.sortAttributesFor().get(prod.sort().head()).getOrElse(() -> Att.empty()).contains(Att.LOCATIONS()); + boolean hasLocation = + module + .sortAttributesFor() + .get(prod.sort().head()) + .getOrElse(() -> Att.empty()) + .contains(Att.LOCATIONS()); if (prod.att().contains(Att.TOKEN()) && !prod.isSubsort()) { - bison.append("{\n" + - " node *n = malloc(sizeof(node));\n" + - " n->symbol = "); - boolean isString = module.sortAttributesFor().get(prod.sort().head()).getOrElse(() -> Att.empty()).getOptional(Att.HOOK()).orElse("").equals("STRING.String"); - boolean isBytes = module.sortAttributesFor().get(prod.sort().head()).getOrElse(() -> Att.empty()).getOptional(Att.HOOK()).orElse("").equals("BYTES.Bytes"); + bison.append("{\n" + " node *n = malloc(sizeof(node));\n" + " n->symbol = "); + boolean isString = + module + .sortAttributesFor() + .get(prod.sort().head()) + .getOrElse(() -> Att.empty()) + .getOptional(Att.HOOK()) + .orElse("") + .equals("STRING.String"); + boolean isBytes = + module + .sortAttributesFor() + .get(prod.sort().head()) + .getOrElse(() -> Att.empty()) + .getOptional(Att.HOOK()) + .orElse("") + .equals("BYTES.Bytes"); if (!isString && !isBytes) { bison.append("enquote("); } @@ -369,130 +481,136 @@ private static void processProduction(Production prod, Module module, Module dis if (!isString && !isBytes) { bison.append(")"); } - bison.append(";\n" + - " n->str = true;\n" + - " n->location = @$;\n" + - " n->hasLocation = 0;\n" + - " n->nchildren = 0;\n" + - " node *n2 = malloc(sizeof(node) + sizeof(node *));\n" + - " n2->symbol = \"\\\\dv{"); + bison.append( + ";\n" + + " n->str = true;\n" + + " n->location = @$;\n" + + " n->hasLocation = 0;\n" + + " n->nchildren = 0;\n" + + " node *n2 = malloc(sizeof(node) + sizeof(node *));\n" + + " n2->symbol = \"\\\\dv{"); encodeKore(prod.sort(), bison); - bison.append("}\";\n" + - " n2->sort = \""); + bison.append("}\";\n" + " n2->sort = \""); encodeKore(prod.sort(), bison); - bison.append("\";\n" + - " n2->str = false;\n" + - " n2->location = @$;\n" + - " n2->hasLocation = " + (hasLocation ? "1" : "0") + ";\n" + - " n2->nchildren = 1;\n" + - " n2->children[0] = n;\n" + - " value_type result = {.nterm = n2};\n" + - " $$ = result;\n" + - "}\n"); - } else if (!prod.att().contains(Att.TOKEN()) && prod.isSubsort() && !prod.att().contains(Att.NOT_INJECTION())) { - bison.append("{\n" + - " node *n = malloc(sizeof(node) + sizeof(node *));\n" + - " n->str = false;\n" + - " n->location = @$;\n" + - " n->hasLocation = " + (hasLocation ? "1" : "0") + ";\n" + - " n->nchildren = 1;\n" + - " n->sort = \""); + bison.append( + "\";\n" + + " n2->str = false;\n" + + " n2->location = @$;\n" + + " n2->hasLocation = " + + (hasLocation ? "1" : "0") + + ";\n" + + " n2->nchildren = 1;\n" + + " n2->children[0] = n;\n" + + " value_type result = {.nterm = n2};\n" + + " $$ = result;\n" + + "}\n"); + } else if (!prod.att().contains(Att.TOKEN()) + && prod.isSubsort() + && !prod.att().contains(Att.NOT_INJECTION())) { + bison.append( + "{\n" + + " node *n = malloc(sizeof(node) + sizeof(node *));\n" + + " n->str = false;\n" + + " n->location = @$;\n" + + " n->hasLocation = " + + (hasLocation ? "1" : "0") + + ";\n" + + " n->nchildren = 1;\n" + + " n->sort = \""); encodeKore(prod.sort(), bison); - bison.append("\";\n" + - " if (!$1.nterm->str && strncmp($1.nterm->symbol, \"inj{\", 4) == 0) {\n" + - " char *childSort = $1.nterm->children[0]->sort;\n" + - " n->symbol = injSymbol(childSort, n->sort);\n" + - " n->children[0] = $1.nterm->children[0];\n" + - " } else {\n" + - " n->symbol = \"inj{"); + bison.append( + "\";\n" + + " if (!$1.nterm->str && strncmp($1.nterm->symbol, \"inj{\", 4) == 0) {\n" + + " char *childSort = $1.nterm->children[0]->sort;\n" + + " n->symbol = injSymbol(childSort, n->sort);\n" + + " n->children[0] = $1.nterm->children[0];\n" + + " } else {\n" + + " n->symbol = \"inj{"); encodeKore(prod.getSubsortSort(), bison); bison.append(", "); encodeKore(prod.sort(), bison); - bison.append("}\";\n" + - " n->children[0] = $1.nterm;\n" + - " }\n"); + bison.append("}\";\n" + " n->children[0] = $1.nterm;\n" + " }\n"); if (prod.att().contains(Att.USER_LIST_TERMINATOR())) { KLabel nil = KLabel(prod.att().get(Att.USER_LIST_TERMINATOR())); KLabel cons = KLabel(prod.att().get(Att.USER_LIST())); - bison.append( - " node *n2 = malloc(sizeof(node));\n" + - " n2->symbol = \""); + bison.append(" node *n2 = malloc(sizeof(node));\n" + " n2->symbol = \""); encodeKore(nil, bison); - bison.append("\";\n" + - " n2->str = false;\n" + - " n2->location = @$;\n" + - " n2->hasLocation = 0;\n" + - " n2->nchildren = 0;\n" + - " n2->sort = \""); + bison.append( + "\";\n" + + " n2->str = false;\n" + + " n2->location = @$;\n" + + " n2->hasLocation = 0;\n" + + " n2->nchildren = 0;\n" + + " n2->sort = \""); encodeKore(prod.sort(), bison); - bison.append("\";\n" + - " node *n3 = malloc(sizeof(node) + 2*sizeof(node *));\n" + - " n3->symbol = \""); + bison.append( + "\";\n" + + " node *n3 = malloc(sizeof(node) + 2*sizeof(node *));\n" + + " n3->symbol = \""); encodeKore(cons, bison); - bison.append("\";\n" + - " n3->str = false;\n" + - " n3->location = @$;\n" + - " n3->hasLocation = " + (hasLocation ? "1" : "0") + ";\n" + - " n3->nchildren = 2;\n" + - " n3->children[0] = n2;\n" + - " n3->children[1] = $1.nterm;\n" + - " n3->sort = \""); + bison.append( + "\";\n" + + " n3->str = false;\n" + + " n3->location = @$;\n" + + " n3->hasLocation = " + + (hasLocation ? "1" : "0") + + ";\n" + + " n3->nchildren = 2;\n" + + " n3->children[0] = n2;\n" + + " n3->children[1] = $1.nterm;\n" + + " n3->sort = \""); encodeKore(prod.sort(), bison); - bison.append("\";\n" + - " value_type result = {.nterm = n3};\n" + - " $$ = result;\n" + - "}\n"); + bison.append( + "\";\n" + " value_type result = {.nterm = n3};\n" + " $$ = result;\n" + "}\n"); } else { - bison.append(" value_type result = {.nterm = n};\n" + - " $$ = result;\n" + - "}\n"); + bison.append(" value_type result = {.nterm = n};\n" + " $$ = result;\n" + "}\n"); } } else if (prod.att().contains(Att.TOKEN()) && prod.isSubsort()) { - bison.append("{\n" + - " node *n = malloc(sizeof(node) + sizeof(node *));\n" + - " n->symbol = \"\\\\dv{"); + bison.append( + "{\n" + + " node *n = malloc(sizeof(node) + sizeof(node *));\n" + + " n->symbol = \"\\\\dv{"); encodeKore(prod.sort(), bison); - bison.append("}\";\n" + - " n->sort = \""); + bison.append("}\";\n" + " n->sort = \""); encodeKore(prod.sort(), bison); - bison.append("\";\n" + - " n->str = false;\n" + - " n->location = @$;\n" + - " n->hasLocation = " + (hasLocation ? "1" : "0") + ";\n" + - " n->nchildren = 1;\n" + - " n->children[0] = $1.nterm->children[0];\n" + - " value_type result = {.nterm = n};\n" + - " $$ = result;\n" + - "}\n"); + bison.append( + "\";\n" + + " n->str = false;\n" + + " n->location = @$;\n" + + " n->hasLocation = " + + (hasLocation ? "1" : "0") + + ";\n" + + " n->nchildren = 1;\n" + + " n->children[0] = $1.nterm->children[0];\n" + + " value_type result = {.nterm = n};\n" + + " $$ = result;\n" + + "}\n"); } else if (prod.klabel().isDefined()) { - bison.append("{\n" + - " node *n = malloc(sizeof(node) + sizeof(node *)*").append(nts.size()).append(");\n" + - " n->str = false;\n" + - " n->location = @$;\n" + - " n->nchildren = ").append(nts.size()).append(";\n"); + bison + .append("{\n" + " node *n = malloc(sizeof(node) + sizeof(node *)*") + .append(nts.size()) + .append(");\n" + " n->str = false;\n" + " n->location = @$;\n" + " n->nchildren = ") + .append(nts.size()) + .append(";\n"); appendOverloadChecks(bison, module, disambModule, prod, nts, hasLocation); - bison.append("{\n" + - " n->symbol = \""); + bison.append("{\n" + " n->symbol = \""); encodeKore(prod.klabel().get(), bison); - bison.append("\";\n" + - " n->sort = \""); + bison.append("\";\n" + " n->sort = \""); encodeKore(prod.sort(), bison); - bison.append("\";\n" + - " n->hasLocation = " + (hasLocation ? "1" : "0") + ";\n"); + bison.append("\";\n" + " n->hasLocation = " + (hasLocation ? "1" : "0") + ";\n"); for (i = 0; i < nts.size(); i++) { - bison.append( - " n->children[").append(i).append("] = $").append(nts.get(i)).append(".nterm;\n"); + bison + .append(" n->children[") + .append(i) + .append("] = $") + .append(nts.get(i)) + .append(".nterm;\n"); } bison.append( - " value_type result = {.nterm = n};\n" + - " $$ = result;\n" + - " }\n" + - "}\n"); + " value_type result = {.nterm = n};\n" + " $$ = result;\n" + " }\n" + "}\n"); } else if (prod.att().contains(Att.BRACKET())) { - bison.append("{\n" + - " $$ = $").append(nts.get(0)).append(";\n" + - "}\n"); + bison.append("{\n" + " $$ = $").append(nts.get(0)).append(";\n" + "}\n"); } if (glr) { bison.append("%merge "); diff --git a/kernel/src/main/java/org/kframework/parser/inner/kernel/Scanner.java b/kernel/src/main/java/org/kframework/parser/inner/kernel/Scanner.java index 9a9185ef256..c9ad59fb189 100644 --- a/kernel/src/main/java/org/kframework/parser/inner/kernel/Scanner.java +++ b/kernel/src/main/java/org/kframework/parser/inner/kernel/Scanner.java @@ -1,8 +1,22 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.kernel; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.*; +import java.util.concurrent.Semaphore; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.kframework.attributes.Att; @@ -24,457 +38,486 @@ import org.kframework.utils.errorsystem.KEMException; import scala.Tuple2; -import java.io.File; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; -import java.nio.file.StandardCopyOption; -import java.nio.file.Files; -import java.util.*; -import java.util.concurrent.Semaphore; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; - -import static org.kframework.kore.KORE.*; -import static org.kframework.Collections.*; - -/** - * Created by dwightguth on 7/21/16. - */ +/** Created by dwightguth on 7/21/16. */ public class Scanner implements AutoCloseable { - private final Map> tokens; - private final File scanner; - private final Module module; - private GlobalOptions go = new GlobalOptions(); - - public static final String COMPILER = OS.current().equals(OS.OSX) ? "clang" : "gcc"; - - public Map> getTokens() { - return Collections.unmodifiableMap(tokens); - } - - public static Map> getTokens(Module module) { - Map tokens = new TreeMap<>(); - Set terminals = new HashSet<>(); - for (Production p : iterable(module.productions())) { - for (ProductionItem pi : iterable(p.items())) { - if (pi instanceof TerminalLike lx) { - if (tokens.containsKey(lx)) { - int prec; - if (p.att().contains(Att.PREC())) { - prec = Integer.valueOf(p.att().getOptional(Att.PREC()).get()); - } else if (lx instanceof Terminal) { - prec = Integer.MAX_VALUE; - } else { - prec = 0; - } - if (prec != tokens.get(lx)) { - throw KEMException.compilerError("Inconsistent token precedence detected.", p); - } - } else if (lx instanceof Terminal && terminals.contains(((Terminal) lx).value())) { - tokens.put(lx, Integer.MAX_VALUE); - } else { - if (lx instanceof Terminal) { - terminals.add(((Terminal) lx).value()); - tokens.put(lx, Integer.MAX_VALUE); - } else { - int prec; - if (p.att().contains(Att.PREC())) { - prec = Integer.valueOf(p.att().getOptional(Att.PREC()).get()); - } else { - prec = 0; - } - tokens.put(lx, prec); - } - } - } + private final Map> tokens; + private final File scanner; + private final Module module; + private GlobalOptions go = new GlobalOptions(); + + public static final String COMPILER = OS.current().equals(OS.OSX) ? "clang" : "gcc"; + + public Map> getTokens() { + return Collections.unmodifiableMap(tokens); + } + + public static Map> getTokens(Module module) { + Map tokens = new TreeMap<>(); + Set terminals = new HashSet<>(); + for (Production p : iterable(module.productions())) { + for (ProductionItem pi : iterable(p.items())) { + if (pi instanceof TerminalLike lx) { + if (tokens.containsKey(lx)) { + int prec; + if (p.att().contains(Att.PREC())) { + prec = Integer.valueOf(p.att().getOptional(Att.PREC()).get()); + } else if (lx instanceof Terminal) { + prec = Integer.MAX_VALUE; + } else { + prec = 0; } + if (prec != tokens.get(lx)) { + throw KEMException.compilerError("Inconsistent token precedence detected.", p); + } + } else if (lx instanceof Terminal && terminals.contains(((Terminal) lx).value())) { + tokens.put(lx, Integer.MAX_VALUE); + } else { + if (lx instanceof Terminal) { + terminals.add(((Terminal) lx).value()); + tokens.put(lx, Integer.MAX_VALUE); + } else { + int prec; + if (p.att().contains(Att.PREC())) { + prec = Integer.valueOf(p.att().getOptional(Att.PREC()).get()); + } else { + prec = 0; + } + tokens.put(lx, prec); + } + } } - - Map> finalTokens = new HashMap<>(); - // token 0 is EOF, so start at index 1 - int idx = 1; - for (TerminalLike t : tokens.keySet()) { - finalTokens.put(t, Tuple2.apply(idx++, tokens.get(t))); - } - - return finalTokens; - } - - - public Scanner(ParseInModule module, GlobalOptions go) { - this.go = go; - this.tokens = getTokens(module.getParsingModule()); - this.module = module.seedModule(); - this.scanner = getScanner(); + } } - public Scanner(ParseInModule module) { - this.tokens = getTokens(module.getParsingModule()); - this.module = module.seedModule(); - this.scanner = getScanner(); + Map> finalTokens = new HashMap<>(); + // token 0 is EOF, so start at index 1 + int idx = 1; + for (TerminalLike t : tokens.keySet()) { + finalTokens.put(t, Tuple2.apply(idx++, tokens.get(t))); } - public Scanner(ParseInModule module, GlobalOptions go, File scanner) { - this.go = go; - this.tokens = getTokens(module.getParsingModule()); - this.module = module.seedModule(); - this.scanner = scanner; + return finalTokens; + } + + public Scanner(ParseInModule module, GlobalOptions go) { + this.go = go; + this.tokens = getTokens(module.getParsingModule()); + this.module = module.seedModule(); + this.scanner = getScanner(); + } + + public Scanner(ParseInModule module) { + this.tokens = getTokens(module.getParsingModule()); + this.module = module.seedModule(); + this.scanner = getScanner(); + } + + public Scanner(ParseInModule module, GlobalOptions go, File scanner) { + this.go = go; + this.tokens = getTokens(module.getParsingModule()); + this.module = module.seedModule(); + this.scanner = scanner; + } + + public void serialize(File output) { + try { + Files.copy(scanner.toPath(), output.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + throw KEMException.criticalError("Could not write to " + output, e); } - - public void serialize(File output) { - try { - Files.copy(scanner.toPath(), output.toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - throw KEMException.criticalError("Could not write to " + output, e); - } - } - - public Module getModule() { - return module; + } + + public Module getModule() { + return module; + } + + public Set kinds() { + return tokens.values().stream().map(v -> v._1()).collect(Collectors.toSet()); + } + + // debugging method + public TerminalLike getTokenByKind(int kind) { + return tokens.entrySet().stream() + .filter(e -> e.getValue()._1() == kind) + .findAny() + .get() + .getKey(); + } + + public void appendScanner( + StringBuilder flex, BiConsumer writeAction) { + if (this.module.allSorts().contains(Sorts.Layout())) { + flex.append(this.module.layout() + " ;\n"); } - - public Set kinds() { - return tokens.values().stream().map(v -> v._1()).collect(Collectors.toSet()); + List ordered = + tokens.keySet().stream() + .sorted((t1, t2) -> tokens.get(t2)._2() - tokens.get(t1)._2()) + .collect(Collectors.toList()); + for (TerminalLike key : ordered) { + if (key instanceof Terminal t) { + flex.append(StringUtil.enquoteCString(t.value())); + } else { + RegexTerminal t = (RegexTerminal) key; + flex.append(t.regex()); + } + writeAction.accept(flex, key); } - - // debugging method - public TerminalLike getTokenByKind(int kind) { - return tokens.entrySet().stream().filter(e -> e.getValue()._1() == kind).findAny().get().getKey(); + } + + public void writeStandaloneScanner(File path) { + StringBuilder flex = new StringBuilder(); + flex.append( + "%{\n" + + "#include \"node.h\"\n" + + "#include \"parser.tab.h\"\n" + + "char *filename;\n" + + "#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno; \\\n" + + " yylloc->first_column = yycolumn; yylloc->last_column = yycolumn + yyleng - 1;" + + " \\\n" + + " yycolumn += yyleng; \\\n" + + " yylloc->filename = filename;\n" + + "#define ECHO do {\\\n" + + " fprintf (stderr, \"%d:%d:%d:%d:syntax error: unexpected %s\\n" + + "\", yylloc->first_line, yylloc->first_column, yylloc->last_line," + + " yylloc->last_column, yytext);\\\n" + + " exit(1);\\\n" + + "} while (0)\n" + + "void line_marker(char *, void *);\n" + + "%}\n\n" + + "%option reentrant bison-bridge\n" + + "%option bison-locations\n" + + "%option noyywrap\n" + + "%option yylineno\n"); + for (SyntaxLexical ident : iterable(module.lexicalIdentifiers())) { + flex.append(ident.name()); + flex.append(" "); + flex.append(ident.regex()); + flex.append("\n"); } - - public void appendScanner(StringBuilder flex, BiConsumer writeAction) { - if (this.module.allSorts().contains(Sorts.Layout())) { - flex.append(this.module.layout() + " ;\n"); - } - List ordered = tokens.keySet().stream().sorted((t1, t2) -> tokens.get(t2)._2() - tokens.get(t1)._2()).collect(Collectors.toList()); - for (TerminalLike key : ordered) { - if (key instanceof Terminal t) { - flex.append(StringUtil.enquoteCString(t.value())); - } else { - RegexTerminal t = (RegexTerminal) key; - flex.append(t.regex()); - } - writeAction.accept(flex, key); - } + flex.append("%%\n\n"); + if (module.productionsForSort().contains(Sorts.LineMarker().head())) { + stream(module.productionsForSort().apply(Sorts.LineMarker().head())) + .forEach( + prod -> { + if (prod.items().size() != 1 + || !(prod.items().apply(0) instanceof RegexTerminal terminal)) { + throw KEMException.compilerError( + "Productions of sort `#LineMarker` must be exactly one `RegexTerminal`.", + prod); + } + String regex = terminal.regex(); + flex.append(regex).append(" line_marker(yytext, yyscanner);\n"); + }); } - - public void writeStandaloneScanner(File path) { - StringBuilder flex = new StringBuilder(); - flex.append("%{\n" + - "#include \"node.h\"\n" + - "#include \"parser.tab.h\"\n" + - "char *filename;\n" + - "#define YY_USER_ACTION yylloc->first_line = yylloc->last_line = yylineno; \\\n" + - " yylloc->first_column = yycolumn; yylloc->last_column = yycolumn + yyleng - 1; \\\n" + - " yycolumn += yyleng; \\\n" + - " yylloc->filename = filename;\n" + - "#define ECHO do {\\\n" + - " fprintf (stderr, \"%d:%d:%d:%d:syntax error: unexpected %s\\n\", yylloc->first_line, yylloc->first_column, yylloc->last_line, yylloc->last_column, yytext);\\\n" + - " exit(1);\\\n" + - "} while (0)\n" + - "void line_marker(char *, void *);\n" + - "%}\n\n" + - "%option reentrant bison-bridge\n" + - "%option bison-locations\n" + - "%option noyywrap\n" + - "%option yylineno\n"); - for (SyntaxLexical ident : iterable(module.lexicalIdentifiers())) { - flex.append(ident.name()); - flex.append(" "); - flex.append(ident.regex()); - flex.append("\n"); - } - flex.append("%%\n\n"); - if (module.productionsForSort().contains(Sorts.LineMarker().head())) { - stream(module.productionsForSort().apply(Sorts.LineMarker().head())).forEach(prod -> { - if (prod.items().size() != 1 || !(prod.items().apply(0) instanceof RegexTerminal terminal)) { - throw KEMException.compilerError("Productions of sort `#LineMarker` must be exactly one `RegexTerminal`.", prod); - } - String regex = terminal.regex(); - flex.append(regex).append(" line_marker(yytext, yyscanner);\n"); - }); - } - appendScanner(flex, this::writeStandaloneAction); - try { - FileUtils.write(path, flex); - } catch (IOException e) { - throw KEMException.internalError("Failed to write file for scanner", e); - } + appendScanner(flex, this::writeStandaloneAction); + try { + FileUtils.write(path, flex); + } catch (IOException e) { + throw KEMException.internalError("Failed to write file for scanner", e); } - - public File getScanner() { - Stopwatch sw = new Stopwatch(go); - File scanner; - // tokenization - try { - File scannerSource = File.createTempFile("tmp-kompile-", ".l"); - scannerSource.deleteOnExit(); - StringBuilder flex = new StringBuilder(); - flex.append("%{\n" + - "#include\n" + - "#include\n" + - "#include \n" + - "#define ECHO do " + - " {" + - " long long start_pos = yytext - buffer;" + - " long long end_pos = start_pos + yyleng;" + - " fwrite(&start_pos, sizeof(start_pos), 1, stdout);" + - " fwrite(&end_pos, sizeof(end_pos), 1, stdout);" + - " int kind = -1;" + - " fwrite(&kind, sizeof(kind), 1, stdout);" + - " int len = strlen(yytext);" + - " fwrite(&len, sizeof(len), 1, stdout);" + - " fwrite(yytext, 1, len, stdout);" + - " } while (0) \n" + - "char *buffer;\n" + - "%}\n\n"); - for (SyntaxLexical ident : iterable(module.lexicalIdentifiers())) { - flex.append(ident.name()); - flex.append(" "); - flex.append(ident.regex()); - flex.append("\n"); - } - flex.append("%%\n\n"); - appendScanner(flex, this::writeAction); - //WIN32 fix for line terminator issue: https://sourceforge.net/p/mingw/mailman/message/11374534/ - flex.append("\n\n%%\n\n" + - "int main(int argc, char **argv) {\n" + - " freopen(NULL, \"rb\", stdin);\n" + - " freopen(NULL, \"wb\", stdout);\n" + - "# ifdef WIN32\n" + - " if ( -1 == _setmode( _fileno( stdout ), _O_BINARY ) ) {\n" + - " perror ( \"generated scanner: Cannot set BINARY mode for stdout\" );\n" + - " exit(1);\n" + - " }\n" + - " if ( -1 == _setmode( _fileno( stdin ), _O_BINARY ) ) {\n" + - " perror ( \"generated scanner: Cannot set BINARY mode for stdin\" );\n" + - " exit(1);\n" + - " }\n" + - "# endif /* WIN32 */\n" + - "\n" + - " while(1) {\n" + - " int length;\n" + - " size_t nread = fread(&length, sizeof(length), 1, stdin);\n" + - " if (nread < 1) exit(0);\n" + - " buffer = malloc(length + 2);\n" + - " buffer[length] = 0;\n" + - " buffer[length+1] = 0;\n" + - " fread(buffer, length, 1, stdin);\n" + - " YY_BUFFER_STATE bs = yy_scan_buffer(buffer, length + 2);\n" + - " yy_switch_to_buffer(bs);\n" + - " yylex();\n" + - " long long exit = -1;\n" + - " fwrite(&exit, sizeof(exit), 1, stdout);\n" + - " fwrite(&exit, sizeof(exit), 1, stdout);\n" + - " fwrite(&exit, sizeof(exit), 1, stdout);\n" + - " fflush(stdout);\n" + - " }\n" + - "}"); - FileUtils.write(scannerSource, flex); - File scannerCSource = File.createTempFile("tmp-kompile-", ".c"); - scannerCSource.deleteOnExit(); - ProcessBuilder pb = new ProcessBuilder("flex", "--nowarn", "--noyywrap", "-Ca", "-o", - scannerCSource.getAbsolutePath(), scannerSource.getAbsolutePath()); - pb.inheritIO(); - int exit = pb.start().waitFor(); - if (exit != 0) { - System.err.println(pb.command()); - throw KEMException.internalError( - "Flex returned nonzero exit code. See output for details. flex command: " + pb.command()); - } - scanner = File.createTempFile("tmp-kompile-", ""); - scanner.deleteOnExit(); - //Option -lfl unnecessary. Same effect achieved by --noyywrap above. - pb = new ProcessBuilder(COMPILER, scannerCSource.getAbsolutePath(), "-o", scanner.getAbsolutePath(), "-Wno-unused-result"); - pb.inheritIO(); - exit = pb.start().waitFor(); - scanner.setExecutable(true); - if (exit != 0) { - throw KEMException.internalError( - COMPILER + " returned nonzero exit code. See output for details. " + COMPILER + " command: " + pb.command()); - } - } catch (IOException | InterruptedException e) { - throw KEMException.internalError("Failed to write file for scanner", e); - } - sw.printIntermediate(" New scanner: " + module.name()); - return scanner; + } + + public File getScanner() { + Stopwatch sw = new Stopwatch(go); + File scanner; + // tokenization + try { + File scannerSource = File.createTempFile("tmp-kompile-", ".l"); + scannerSource.deleteOnExit(); + StringBuilder flex = new StringBuilder(); + flex.append( + "%{\n" + + "#include\n" + + "#include\n" + + "#include \n" + + "#define ECHO do " + + " {" + + " long long start_pos = yytext - buffer;" + + " long long end_pos = start_pos + yyleng;" + + " fwrite(&start_pos, sizeof(start_pos), 1, stdout);" + + " fwrite(&end_pos, sizeof(end_pos), 1, stdout);" + + " int kind = -1;" + + " fwrite(&kind, sizeof(kind), 1, stdout);" + + " int len = strlen(yytext);" + + " fwrite(&len, sizeof(len), 1, stdout);" + + " fwrite(yytext, 1, len, stdout);" + + " } while (0) \n" + + "char *buffer;\n" + + "%}\n\n"); + for (SyntaxLexical ident : iterable(module.lexicalIdentifiers())) { + flex.append(ident.name()); + flex.append(" "); + flex.append(ident.regex()); + flex.append("\n"); + } + flex.append("%%\n\n"); + appendScanner(flex, this::writeAction); + // WIN32 fix for line terminator issue: + // https://sourceforge.net/p/mingw/mailman/message/11374534/ + flex.append( + "\n\n%%\n\n" + + "int main(int argc, char **argv) {\n" + + " freopen(NULL, \"rb\", stdin);\n" + + " freopen(NULL, \"wb\", stdout);\n" + + "# ifdef WIN32\n" + + " if ( -1 == _setmode( _fileno( stdout ), _O_BINARY ) ) {\n" + + " perror ( \"generated scanner: Cannot set BINARY mode for stdout\" );\n" + + " exit(1);\n" + + " }\n" + + " if ( -1 == _setmode( _fileno( stdin ), _O_BINARY ) ) {\n" + + " perror ( \"generated scanner: Cannot set BINARY mode for stdin\" );\n" + + " exit(1);\n" + + " }\n" + + "# endif /* WIN32 */\n" + + "\n" + + " while(1) {\n" + + " int length;\n" + + " size_t nread = fread(&length, sizeof(length), 1, stdin);\n" + + " if (nread < 1) exit(0);\n" + + " buffer = malloc(length + 2);\n" + + " buffer[length] = 0;\n" + + " buffer[length+1] = 0;\n" + + " fread(buffer, length, 1, stdin);\n" + + " YY_BUFFER_STATE bs = yy_scan_buffer(buffer, length + 2);\n" + + " yy_switch_to_buffer(bs);\n" + + " yylex();\n" + + " long long exit = -1;\n" + + " fwrite(&exit, sizeof(exit), 1, stdout);\n" + + " fwrite(&exit, sizeof(exit), 1, stdout);\n" + + " fwrite(&exit, sizeof(exit), 1, stdout);\n" + + " fflush(stdout);\n" + + " }\n" + + "}"); + FileUtils.write(scannerSource, flex); + File scannerCSource = File.createTempFile("tmp-kompile-", ".c"); + scannerCSource.deleteOnExit(); + ProcessBuilder pb = + new ProcessBuilder( + "flex", + "--nowarn", + "--noyywrap", + "-Ca", + "-o", + scannerCSource.getAbsolutePath(), + scannerSource.getAbsolutePath()); + pb.inheritIO(); + int exit = pb.start().waitFor(); + if (exit != 0) { + System.err.println(pb.command()); + throw KEMException.internalError( + "Flex returned nonzero exit code. See output for details. flex command: " + + pb.command()); + } + scanner = File.createTempFile("tmp-kompile-", ""); + scanner.deleteOnExit(); + // Option -lfl unnecessary. Same effect achieved by --noyywrap above. + pb = + new ProcessBuilder( + COMPILER, + scannerCSource.getAbsolutePath(), + "-o", + scanner.getAbsolutePath(), + "-Wno-unused-result"); + pb.inheritIO(); + exit = pb.start().waitFor(); + scanner.setExecutable(true); + if (exit != 0) { + throw KEMException.internalError( + COMPILER + + " returned nonzero exit code. See output for details. " + + COMPILER + + " command: " + + pb.command()); + } + } catch (IOException | InterruptedException e) { + throw KEMException.internalError("Failed to write file for scanner", e); } - - private void writeAction(StringBuilder flex, TerminalLike key) { - flex.append(" {\n" + - " long long start_pos = yytext - buffer;\n" + - " long long end_pos = start_pos + yyleng;\n" + - " fwrite(&start_pos, sizeof(start_pos), 1, stdout);\n" + - " fwrite(&end_pos, sizeof(end_pos), 1, stdout);\n" + - " int kind = ").append(tokens.get(key)._1()).append(";\n" + - " fwrite(&kind, sizeof(kind), 1, stdout);\n" + - " int len = strlen(yytext);\n" + - " fwrite(&len, sizeof(len), 1, stdout);\n" + - " fwrite(yytext, 1, len, stdout);\n" + - " }\n"); + sw.printIntermediate(" New scanner: " + module.name()); + return scanner; + } + + private void writeAction(StringBuilder flex, TerminalLike key) { + flex.append( + " {\n" + + " long long start_pos = yytext - buffer;\n" + + " long long end_pos = start_pos + yyleng;\n" + + " fwrite(&start_pos, sizeof(start_pos), 1, stdout);\n" + + " fwrite(&end_pos, sizeof(end_pos), 1, stdout);\n" + + " int kind = ") + .append(tokens.get(key)._1()) + .append( + ";\n" + + " fwrite(&kind, sizeof(kind), 1, stdout);\n" + + " int len = strlen(yytext);\n" + + " fwrite(&len, sizeof(len), 1, stdout);\n" + + " fwrite(yytext, 1, len, stdout);\n" + + " }\n"); + } + + private void writeStandaloneAction(StringBuilder flex, TerminalLike key) { + flex.append(" {\n" + " int kind = ") + .append(tokens.get(key)._1() + 1) + .append( + ";\n" + + " *((char **)yylval) = malloc(strlen(yytext) + 1);\n" + + " strcpy(*((char **)yylval), yytext);\n" + + " return kind;\n" + + " }\n"); + } + + private int maxToken = -1; + + public int getMaxToken() { + int max = maxToken; + if (max == -1) { + for (Tuple2 val : tokens.values()) { + max = Integer.max(max, val._1()); + } + maxToken = max; } - - private void writeStandaloneAction(StringBuilder flex, TerminalLike key) { - flex.append(" {\n" + - " int kind = ").append(tokens.get(key)._1()+1).append(";\n" + - " *((char **)yylval) = malloc(strlen(yytext) + 1);\n" + - " strcpy(*((char **)yylval), yytext);\n" + - " return kind;\n" + - " }\n"); + return max; + } + + public int resolve(TerminalLike terminal) { + return tokens.get(terminal)._1(); + } + + public static class Token { + public final int kind; + public final String value; + public final int startLoc; + public final int endLoc; + + public Token(int kind, String value, long startLoc, long endLoc) { + this.kind = kind; + this.value = value; + assert startLoc < Integer.MAX_VALUE; + assert endLoc < Integer.MAX_VALUE; + this.startLoc = (int) startLoc; + this.endLoc = (int) endLoc; } - private int maxToken = -1; - - public int getMaxToken() { - int max = maxToken; - if (max == -1) { - for (Tuple2 val : tokens.values()) { - max = Integer.max(max, val._1()); - } - maxToken = max; - } - return max; + @Override + public String toString() { + return kind + ":" + value; } - - public int resolve(TerminalLike terminal) { - return tokens.get(terminal)._1(); + } + + @Override + public void close() { + synchronized (idleProcesses) { + for (Process p : idleProcesses.get(this)) { + p.destroy(); + cache.remove(p); + activeProcceses--; + } + idleProcesses.removeAll(this); } - - public static class Token { - public final int kind; - public final String value; - public final int startLoc; - public final int endLoc; - - public Token(int kind, String value, long startLoc, long endLoc) { - this.kind = kind; - this.value = value; - assert startLoc < Integer.MAX_VALUE; - assert endLoc < Integer.MAX_VALUE; - this.startLoc = (int)startLoc; - this.endLoc = (int)endLoc; - } - + } + + private static final int N_CPUS = Runtime.getRuntime().availableProcessors(); + private static final int N_PROCS = 512; + private static int activeProcceses = 0; + private static final Semaphore runningScanners = new Semaphore(N_PROCS); + private static final ListMultimap idleProcesses = ArrayListMultimap.create(); + private static final Map cache = + new LinkedHashMap() { @Override - public String toString() { - return kind + ":" + value; + protected boolean removeEldestEntry(Map.Entry entry) { + if (activeProcceses > N_PROCS) { + entry.getKey().destroy(); + idleProcesses.get(entry.getValue()).remove(entry.getKey()); + activeProcceses--; + return true; + } + return false; } - } - - @Override - public void close() { - synchronized(idleProcesses) { - for (Process p : idleProcesses.get(this)) { - p.destroy(); - cache.remove(p); - activeProcceses--; - } - idleProcesses.removeAll(this); + }; + + public Token[] tokenize(String input, Source source, int[] lines, int[] columns) { + try { + runningScanners.acquire(); + + Process process; + synchronized (idleProcesses) { + if (idleProcesses.get(this).size() > 0) { + List idleForThisScanner = idleProcesses.get(this); + process = idleForThisScanner.remove(idleForThisScanner.size() - 1); + cache.remove(process); + } else { + process = new ProcessBuilder(scanner.getAbsolutePath()).start(); + activeProcceses++; + // temporarily add it so that LinkedHashMap evicts the old entry + cache.put(process, this); + cache.remove(process); } + } + + byte[] buf = input.getBytes(StandardCharsets.UTF_8); + ByteBuffer size = ByteBuffer.allocate(4); + size.order(ByteOrder.nativeOrder()); + size.putInt(buf.length); + process.getOutputStream().write(size.array()); + process.getOutputStream().write(buf); + process.getOutputStream().flush(); + return readTokenizedOutput(process, source, lines, columns, input.length()); + } catch (IOException | InterruptedException e) { + throw KEMException.internalError("Failed to invoke scanner", e); + } finally { + runningScanners.release(); } - - private static final int N_CPUS = Runtime.getRuntime().availableProcessors(); - private static final int N_PROCS = 512; - private static int activeProcceses = 0; - private static final Semaphore runningScanners = new Semaphore(N_PROCS); - private static final ListMultimap idleProcesses = ArrayListMultimap.create(); - private static final Map cache = new LinkedHashMap() { - @Override - protected boolean removeEldestEntry(Map.Entry entry) { - if (activeProcceses > N_PROCS) { - entry.getKey().destroy(); - idleProcesses.get(entry.getValue()).remove(entry.getKey()); - activeProcceses--; - return true; - } - return false; + } + + private Token[] readTokenizedOutput( + Process process, Source source, int[] lines, int[] columns, int length) throws IOException { + List result = new ArrayList<>(); + boolean success = false; + try { + while (true) { + byte[] buf = new byte[24]; + IOUtils.readFully(process.getInputStream(), buf); + ByteBuffer byteBuf = ByteBuffer.wrap(buf); + byteBuf.order(ByteOrder.nativeOrder()); + long startLoc = byteBuf.getLong(); + if (startLoc < 0) { + break; } - }; - - public Token[] tokenize(String input, Source source, int[] lines, int[] columns) { - try { - runningScanners.acquire(); - - Process process; - synchronized (idleProcesses) { - if (idleProcesses.get(this).size() > 0) { - List idleForThisScanner = idleProcesses.get(this); - process = idleForThisScanner.remove(idleForThisScanner.size() - 1); - cache.remove(process); - } else { - process = new ProcessBuilder(scanner.getAbsolutePath()).start(); - activeProcceses++; - // temporarily add it so that LinkedHashMap evicts the old entry - cache.put(process, this); - cache.remove(process); - } - } - - byte[] buf = input.getBytes(StandardCharsets.UTF_8); - ByteBuffer size = ByteBuffer.allocate(4); - size.order(ByteOrder.nativeOrder()); - size.putInt(buf.length); - process.getOutputStream().write(size.array()); - process.getOutputStream().write(buf); - process.getOutputStream().flush(); - return readTokenizedOutput(process, source, lines, columns, input.length()); - } catch (IOException | InterruptedException e) { - throw KEMException.internalError("Failed to invoke scanner", e); - } finally { - runningScanners.release(); + long endLoc = byteBuf.getLong(); + int kind = byteBuf.getInt(); + int len = byteBuf.getInt(); + byte[] bytes = new byte[len]; + IOUtils.readFully(process.getInputStream(), bytes); + String value = new String(bytes, StandardCharsets.UTF_8); + Token t = new Token(kind, value, startLoc, endLoc); + if (kind == -1) { + String msg = "Scanner error: unexpected character sequence '" + value + "'."; + Location loc = + new Location( + lines[t.startLoc], columns[t.startLoc], lines[t.endLoc], columns[t.endLoc]); + throw KEMException.innerParserError(msg, source, loc); } - } - - private Token[] readTokenizedOutput(Process process, Source source, int[] lines, int[] columns, int length) throws IOException { - List result = new ArrayList<>(); - boolean success = false; - try { - while (true) { - byte[] buf = new byte[24]; - IOUtils.readFully(process.getInputStream(), buf); - ByteBuffer byteBuf = ByteBuffer.wrap(buf); - byteBuf.order(ByteOrder.nativeOrder()); - long startLoc = byteBuf.getLong(); - if (startLoc < 0) { - break; - } - long endLoc = byteBuf.getLong(); - int kind = byteBuf.getInt(); - int len = byteBuf.getInt(); - byte[] bytes = new byte[len]; - IOUtils.readFully(process.getInputStream(), bytes); - String value = new String(bytes, StandardCharsets.UTF_8); - Token t = new Token(kind, value, startLoc, endLoc); - if (kind == -1) { - String msg = "Scanner error: unexpected character sequence '" + value + "'."; - Location loc = new Location(lines[t.startLoc], columns[t.startLoc], - lines[t.endLoc], columns[t.endLoc]); - throw KEMException.innerParserError(msg, source, loc); - } - result.add(t); - } - success = true; - // add EOF token at end of token sequence - result.add(new Token(0, "", length, length)); - return result.toArray(new Token[result.size()]); - } finally { - if (success) { - synchronized (idleProcesses) { - cache.put(process, this); - idleProcesses.put(this, process); - } - } else { - // we aren't returning this process to the pool since something went wrong with it, - // so we have to clean up here and then make sure that the pool knows it can allocate a new process. - synchronized (idleProcesses) { - process.destroy(); - activeProcceses--; - } - } + result.add(t); + } + success = true; + // add EOF token at end of token sequence + result.add(new Token(0, "", length, length)); + return result.toArray(new Token[result.size()]); + } finally { + if (success) { + synchronized (idleProcesses) { + cache.put(process, this); + idleProcesses.put(this, process); + } + } else { + // we aren't returning this process to the pool since something went wrong with it, + // so we have to clean up here and then make sure that the pool knows it can allocate a new + // process. + synchronized (idleProcesses) { + process.destroy(); + activeProcceses--; } + } } - + } } diff --git a/kernel/src/main/java/org/kframework/parser/json/JsonParser.java b/kernel/src/main/java/org/kframework/parser/json/JsonParser.java index 83252ae20a1..1bf3e7c263f 100644 --- a/kernel/src/main/java/org/kframework/parser/json/JsonParser.java +++ b/kernel/src/main/java/org/kframework/parser/json/JsonParser.java @@ -1,11 +1,20 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.json; -import org.checkerframework.checker.nullness.Opt; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import javax.json.*; import org.kframework.attributes.Att; import org.kframework.attributes.Location; import org.kframework.attributes.Source; -import org.kframework.compile.ProcessGroupAttributes; import org.kframework.definition.Associativity; import org.kframework.definition.Bubble; import org.kframework.definition.Claim; @@ -13,8 +22,8 @@ import org.kframework.definition.Constructors; import org.kframework.definition.Context; import org.kframework.definition.Definition; -import org.kframework.definition.FlatModule; import org.kframework.definition.FlatImport; +import org.kframework.definition.FlatModule; import org.kframework.definition.Module; import org.kframework.definition.NonTerminal; import org.kframework.definition.Production; @@ -40,391 +49,424 @@ import scala.collection.JavaConverters; import scala.util.Either; -import javax.json.*; -import java.io.IOException; -import java.io.StringReader; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - -/** - * Parses a Json term into the KORE data structures. - */ +/** Parses a Json term into the KORE data structures. */ public class JsonParser { - public static final String INJECTEDKLABEL = "InjectedKLabel" - , KAPPLY = "KApply" - , KAS = "KAs" - , KATT = "KAtt" - , KBUBBLE = "KBubble" - , KCONFIGURATION = "KConfiguration" - , KCONTEXT = "KContext" - , KDEFINITION = "KDefinition" - , KNONTERMINAL = "KNonTerminal" - , KMODULE = "KModule" - , KFLATMODULE = "KFlatModule" - , KFLATMODULELIST = "KFlatModuleList" - , KIMPORT = "KImport" - , KPRODUCTION = "KProduction" - , KREGEXTERMINAL = "KRegexTerminal" - , KREWRITE = "KRewrite" - , KRULE = "KRule" - , KCLAIM = "KClaim" - , KSEQUENCE = "KSequence" - , KSORT = "KSort" - , KSORTSYNONYM = "KSortSynonym" - , KSYNTAXLEXICAL = "KSyntaxLexical" - , KSYNTAXASSOCIATIVITY = "KSyntaxAssociativity" - , KSYNTAXPRIORITY = "KSyntaxPriority" - , KSYNTAXSORT = "KSyntaxSort" - , KTERMINAL = "KTerminal" - , KTOKEN = "KToken" - , KVARIABLE = "KVariable" - ; - -///////////////////////////// -// Parsing Definition Json // -///////////////////////////// - - public static Definition parseDefinition(byte[] data) { - return parseDefinition(new String(data, StandardCharsets.UTF_8)); + public static final String INJECTEDKLABEL = "InjectedKLabel", + KAPPLY = "KApply", + KAS = "KAs", + KATT = "KAtt", + KBUBBLE = "KBubble", + KCONFIGURATION = "KConfiguration", + KCONTEXT = "KContext", + KDEFINITION = "KDefinition", + KNONTERMINAL = "KNonTerminal", + KMODULE = "KModule", + KFLATMODULE = "KFlatModule", + KFLATMODULELIST = "KFlatModuleList", + KIMPORT = "KImport", + KPRODUCTION = "KProduction", + KREGEXTERMINAL = "KRegexTerminal", + KREWRITE = "KRewrite", + KRULE = "KRule", + KCLAIM = "KClaim", + KSEQUENCE = "KSequence", + KSORT = "KSort", + KSORTSYNONYM = "KSortSynonym", + KSYNTAXLEXICAL = "KSyntaxLexical", + KSYNTAXASSOCIATIVITY = "KSyntaxAssociativity", + KSYNTAXPRIORITY = "KSyntaxPriority", + KSYNTAXSORT = "KSyntaxSort", + KTERMINAL = "KTerminal", + KTOKEN = "KToken", + KVARIABLE = "KVariable"; + + ///////////////////////////// + // Parsing Definition Json // + ///////////////////////////// + + public static Definition parseDefinition(byte[] data) { + return parseDefinition(new String(data, StandardCharsets.UTF_8)); + } + + public static Definition parseDefinition(String data) { + JsonReader reader = Json.createReader(new StringReader(data)); + return parseJsonDef(reader.readObject()); + } + + public static Definition parseJsonDef(JsonObject data) { + try { + if (!(data.containsKey("format") + && data.containsKey("version") + && data.containsKey("term"))) { + throw KEMException.criticalError( + "Must have `format`, `version`, and `term` fields in serialized Json!"); + } + if (!data.getString("format").equals("KAST")) { + throw KEMException.criticalError( + "Only can deserialize 'KAST' format Json! Found: " + data.getString("format")); + } + if (data.getInt("version") != ToJson.version) { + throw KEMException.criticalError( + "Only can deserialize KAST version '" + + ToJson.version + + "'! Found: " + + data.getInt("version")); + } + return toDefinition(data.getJsonObject("term")); + } catch (IOException e) { + throw KEMException.criticalError("Could not read Definition term from json", e); } - - public static Definition parseDefinition(String data) { - JsonReader reader = Json.createReader(new StringReader(data)); - return parseJsonDef(reader.readObject()); + } + + public static Definition toDefinition(JsonObject data) throws IOException { + if (!data.getString("node").equals(KDEFINITION)) + throw KEMException.criticalError( + "Unexpected node found in KAST Json term: " + data.getString("node")); + + String mainModuleName = data.getString("mainModule"); + JsonArray mods = data.getJsonArray("modules"); + List flatModules = new ArrayList<>(); + for (JsonObject m : mods.getValuesAs(JsonObject.class)) { + flatModules.add(toFlatModule(m)); } - public static Definition parseJsonDef(JsonObject data) { - try { - if (! (data.containsKey("format") && data.containsKey("version") && data.containsKey("term"))) { - throw KEMException.criticalError("Must have `format`, `version`, and `term` fields in serialized Json!"); - } - if (! data.getString("format").equals("KAST")) { - throw KEMException.criticalError("Only can deserialize 'KAST' format Json! Found: " + data.getString("format")); - } - if (data.getInt("version") != ToJson.version) { - throw KEMException.criticalError("Only can deserialize KAST version '" + ToJson.version + "'! Found: " + data.getInt("version")); - } - return toDefinition(data.getJsonObject("term")); - } catch (IOException e) { - throw KEMException.criticalError("Could not read Definition term from json", e); - } + scala.collection.Set koreModules = FlatModule.toModules(immutable(flatModules), Set()); + return Constructors.Definition( + koreModules + .find(x -> x.name().equals(mainModuleName)) + .getOrElse( + () -> { + throw new AssertionError( + "Could not find main module name " + + mainModuleName + + " when loading from JSON."); + }), + koreModules, + toAtt(data.getJsonObject("att"))); + } + + ///////////////////////// + // Parsing Module Json // + ///////////////////////// + + public static FlatModule toFlatModule(JsonObject data) throws IOException { + if (!data.getString("node").equals(KFLATMODULE)) + throw KEMException.criticalError( + "Unexpected node found in KAST Json term: " + data.getString("node")); + + String name = data.getString("name"); + + JsonArray jsonimports = data.getJsonArray("imports"); + Set imports = new HashSet<>(); + jsonimports + .getValuesAs(JsonObject.class) + .forEach( + i -> + imports.add( + FlatImport.apply(i.getString("name"), i.getBoolean("isPublic"), Att.empty()))); + + JsonArray sentences = data.getJsonArray("localSentences"); + Set localSentences = new HashSet<>(); + for (JsonObject j : sentences.getValuesAs(JsonObject.class)) { + localSentences.add(toSentence(j)); } - public static Definition toDefinition(JsonObject data) throws IOException { - if (! data.getString("node").equals(KDEFINITION)) - throw KEMException.criticalError("Unexpected node found in KAST Json term: " + data.getString("node")); - - String mainModuleName = data.getString("mainModule"); - JsonArray mods = data.getJsonArray("modules"); - List flatModules = new ArrayList<>(); - for (JsonObject m: mods.getValuesAs(JsonObject.class)) { - flatModules.add(toFlatModule(m)); + return new FlatModule( + name, immutable(imports), immutable(localSentences), toAtt(data.getJsonObject("att"))); + } + + /////////////////////////// + // Parsing Sentence Json // + /////////////////////////// + + public static Sentence toSentence(JsonObject data) { + switch (data.getString("node")) { + case KCONTEXT -> { + K body = toK(data.getJsonObject("body")); + K requires = toK(data.getJsonObject("requires")); + Att att = toAtt(data.getJsonObject("att")); + return new Context(body, requires, att); + } + case KRULE -> { + K body = toK(data.getJsonObject("body")); + K requires = toK(data.getJsonObject("requires")); + K ensures = toK(data.getJsonObject("ensures")); + Att att = toAtt(data.getJsonObject("att")); + return new Rule(body, requires, ensures, att); + } + case KCLAIM -> { + K body = toK(data.getJsonObject("body")); + K requires = toK(data.getJsonObject("requires")); + K ensures = toK(data.getJsonObject("ensures")); + Att att = toAtt(data.getJsonObject("att")); + return new Claim(body, requires, ensures, att); + } + case KSYNTAXPRIORITY -> { + JsonArray priorities = data.getJsonArray("priorities"); + Att att = toAtt(data.getJsonObject("att")); + List> syntaxPriorities = new ArrayList<>(); + priorities.getValuesAs(JsonArray.class).forEach(tags -> syntaxPriorities.add(toTags(tags))); + return new SyntaxPriority(immutable(syntaxPriorities), att); + } + case KSYNTAXASSOCIATIVITY -> { + String assocString = data.getString("assoc"); + Associativity assoc = + "Left".equals(assocString) + ? Associativity.Left + : "Right".equals(assocString) + ? Associativity.Right + : "NonAssoc".equals(assocString) + ? Associativity.NonAssoc + : Associativity.Unspecified; + scala.collection.Set tags = toTags(data.getJsonArray("tags")); + Att att = toAtt(data.getJsonObject("att")); + return new SyntaxAssociativity(assoc, tags, att); + } + case KCONFIGURATION -> { + K body = toK(data.getJsonObject("body")); + K ensures = toK(data.getJsonObject("ensures")); + Att att = toAtt(data.getJsonObject("att")); + return new Configuration(body, ensures, att); + } + case KSYNTAXSORT -> { + Sort sort = toSort(data.getJsonObject("sort")); + Att att = toAtt(data.getJsonObject("att")); + List params = new ArrayList<>(); + for (JsonObject s : data.getJsonArray("params").getValuesAs(JsonObject.class)) { + params.add(toSort(s)); } - - scala.collection.Set koreModules = FlatModule.toModules(immutable(flatModules), Set()); - return Constructors.Definition( - koreModules.find(x -> x.name().equals(mainModuleName)) - .getOrElse(() -> { throw new AssertionError("Could not find main module name " + mainModuleName + " when loading from JSON."); }), - koreModules, toAtt(data.getJsonObject("att"))); - } - -///////////////////////// -// Parsing Module Json // -///////////////////////// - - public static FlatModule toFlatModule(JsonObject data) throws IOException { - if (! data.getString("node").equals(KFLATMODULE)) - throw KEMException.criticalError("Unexpected node found in KAST Json term: " + data.getString("node")); - + return new SyntaxSort(immutable(params), sort, att); + } + case KSORTSYNONYM -> { + Sort newSort = toSort(data.getJsonObject("newSort")); + Sort oldSort = toSort(data.getJsonObject("oldSort")); + Att att = toAtt(data.getJsonObject("att")); + return new SortSynonym(newSort, oldSort, att); + } + case KSYNTAXLEXICAL -> { String name = data.getString("name"); - - JsonArray jsonimports = data.getJsonArray("imports"); - Set imports = new HashSet<>(); - jsonimports.getValuesAs(JsonObject.class).forEach(i -> imports.add(FlatImport.apply(i.getString("name"), i.getBoolean("isPublic"), Att.empty()))); - - JsonArray sentences = data.getJsonArray("localSentences"); - Set localSentences = new HashSet<>(); - for (JsonObject j: sentences.getValuesAs(JsonObject.class)) { - localSentences.add(toSentence(j)); - } - - return new FlatModule(name, immutable(imports), immutable(localSentences), toAtt(data.getJsonObject("att"))); - } - -/////////////////////////// -// Parsing Sentence Json // -/////////////////////////// - - public static Sentence toSentence(JsonObject data) { - switch (data.getString("node")) { - case KCONTEXT -> { - K body = toK(data.getJsonObject("body")); - K requires = toK(data.getJsonObject("requires")); - Att att = toAtt(data.getJsonObject("att")); - return new Context(body, requires, att); + String regex = data.getString("regex"); + Att att = toAtt(data.getJsonObject("att")); + return new SyntaxLexical(name, regex, att); + } + case KBUBBLE -> { + String sentenceType = data.getString("sentenceType"); + String contents = data.getString("contents"); + Att att = toAtt(data.getJsonObject("att")); + return new Bubble(sentenceType, contents, att); + } + case KPRODUCTION -> { + Option klabel = + Option.apply( + data.containsKey("klabel") ? toKLabel(data.getJsonObject("klabel")) : null); + Sort sort = toSort(data.getJsonObject("sort")); + Att att = toAtt(data.getJsonObject("att")); + + List pItems = new ArrayList<>(); + for (JsonObject pi : data.getJsonArray("productionItems").getValuesAs(JsonObject.class)) { + pItems.add(toProductionItem(pi)); } - case KRULE -> { - K body = toK(data.getJsonObject("body")); - K requires = toK(data.getJsonObject("requires")); - K ensures = toK(data.getJsonObject("ensures")); - Att att = toAtt(data.getJsonObject("att")); - return new Rule(body, requires, ensures, att); - } - case KCLAIM -> { - K body = toK(data.getJsonObject("body")); - K requires = toK(data.getJsonObject("requires")); - K ensures = toK(data.getJsonObject("ensures")); - Att att = toAtt(data.getJsonObject("att")); - return new Claim(body, requires, ensures, att); - } - case KSYNTAXPRIORITY -> { - JsonArray priorities = data.getJsonArray("priorities"); - Att att = toAtt(data.getJsonObject("att")); - List> syntaxPriorities = new ArrayList<>(); - priorities.getValuesAs(JsonArray.class).forEach(tags -> syntaxPriorities.add(toTags(tags))); - return new SyntaxPriority(immutable(syntaxPriorities), att); - } - case KSYNTAXASSOCIATIVITY -> { - String assocString = data.getString("assoc"); - Associativity assoc = "Left".equals(assocString) ? Associativity.Left - : "Right".equals(assocString) ? Associativity.Right - : "NonAssoc".equals(assocString) ? Associativity.NonAssoc - : Associativity.Unspecified; - scala.collection.Set tags = toTags(data.getJsonArray("tags")); - Att att = toAtt(data.getJsonObject("att")); - return new SyntaxAssociativity(assoc, tags, att); - } - case KCONFIGURATION -> { - K body = toK(data.getJsonObject("body")); - K ensures = toK(data.getJsonObject("ensures")); - Att att = toAtt(data.getJsonObject("att")); - return new Configuration(body, ensures, att); - } - case KSYNTAXSORT -> { - Sort sort = toSort(data.getJsonObject("sort")); - Att att = toAtt(data.getJsonObject("att")); - List params = new ArrayList<>(); - for (JsonObject s : data.getJsonArray("params").getValuesAs(JsonObject.class)) { - params.add(toSort(s)); - } - return new SyntaxSort(immutable(params), sort, att); - } - case KSORTSYNONYM -> { - Sort newSort = toSort(data.getJsonObject("newSort")); - Sort oldSort = toSort(data.getJsonObject("oldSort")); - Att att = toAtt(data.getJsonObject("att")); - return new SortSynonym(newSort, oldSort, att); - } - case KSYNTAXLEXICAL -> { - String name = data.getString("name"); - String regex = data.getString("regex"); - Att att = toAtt(data.getJsonObject("att")); - return new SyntaxLexical(name, regex, att); - } - case KBUBBLE -> { - String sentenceType = data.getString("sentenceType"); - String contents = data.getString("contents"); - Att att = toAtt(data.getJsonObject("att")); - return new Bubble(sentenceType, contents, att); - } - case KPRODUCTION -> { - Option klabel = Option.apply(data.containsKey("klabel") ? toKLabel(data.getJsonObject("klabel")) : null); - Sort sort = toSort(data.getJsonObject("sort")); - Att att = toAtt(data.getJsonObject("att")); - - List pItems = new ArrayList<>(); - for (JsonObject pi : data.getJsonArray("productionItems").getValuesAs(JsonObject.class)) { - pItems.add(toProductionItem(pi)); - } - List params = new ArrayList<>(); - for (JsonObject s : data.getJsonArray("params").getValuesAs(JsonObject.class)) { - params.add(toSort(s)); - } - return new Production(klabel, immutable(params), sort, immutable(pItems), att); - } - default -> throw KEMException.criticalError("Unexpected node found in KAST Json term: " + data.getString("node")); + List params = new ArrayList<>(); + for (JsonObject s : data.getJsonArray("params").getValuesAs(JsonObject.class)) { + params.add(toSort(s)); } + return new Production(klabel, immutable(params), sort, immutable(pItems), att); + } + default -> throw KEMException.criticalError( + "Unexpected node found in KAST Json term: " + data.getString("node")); } - - private static scala.collection.Set toTags(JsonArray data) { - Set tags = new HashSet<>(); - data.getValuesAs(JsonString.class).forEach(s -> tags.add(new Tag(s.getString()))); - return JavaConverters.asScalaSet(tags); + } + + private static scala.collection.Set toTags(JsonArray data) { + Set tags = new HashSet<>(); + data.getValuesAs(JsonString.class).forEach(s -> tags.add(new Tag(s.getString()))); + return JavaConverters.asScalaSet(tags); + } + + private static Sort toSort(JsonObject data) { + if (!data.getString("node").equals(KSORT)) + throw KEMException.criticalError( + "Unexpected node found in KAST Json term: " + data.getString("node")); + return Outer.parseSort(data.getString("name")); + } + + private static ProductionItem toProductionItem(JsonObject data) { + switch (data.getString("node")) { + case KNONTERMINAL -> { + Sort sort = toSort(data.getJsonObject("sort")); + Option name = + Option.apply(data.containsKey("name") ? data.getString("name") : null); + return new NonTerminal(sort, name); + } + case KREGEXTERMINAL -> { + String precedeRegex = data.getString("precedeRegex"); + String regex = data.getString("regex"); + String followRegex = data.getString("followRegex"); + return new RegexTerminal(precedeRegex, regex, followRegex); + } + case KTERMINAL -> { + String value = data.getString("value"); + return new Terminal(value); + } + default -> throw KEMException.criticalError( + "Unexpected node found in ProductionItem Json term: " + data.getString("node")); } - - private static Sort toSort(JsonObject data) { - if (! data.getString("node").equals(KSORT)) - throw KEMException.criticalError("Unexpected node found in KAST Json term: " + data.getString("node")); - return Outer.parseSort(data.getString("name")); + } + + ////////////////////// + // Parsing Att Json // + ////////////////////// + + public static Att toAtt(JsonObject data) { + if (!(data.getString("node").equals(KATT) && data.containsKey("att"))) + throw KEMException.criticalError( + "Unexpected node found in KAST Json term when unparsing KATT: " + data.getString("node")); + JsonObject attMap = data.getJsonObject("att"); + Att newAtt = Att.empty(); + for (String key : attMap.keySet()) { + if (key.equals(Location.class.getName())) { + JsonArray locarr = attMap.getJsonArray(Location.class.getName()); + newAtt = + newAtt.add( + Location.class, + Location(locarr.getInt(0), locarr.getInt(1), locarr.getInt(2), locarr.getInt(3))); + } else if (key.equals(Source.class.getName())) { + newAtt = newAtt.add(Source.class, Source.apply(attMap.getString(key))); + } else if (key.equals(Production.class.getName())) { + newAtt = newAtt.add(Production.class, (Production) toSentence(attMap.getJsonObject(key))); + } else if (key.equals(Sort.class.getName())) { + newAtt = newAtt.add(Sort.class, toSort(attMap.getJsonObject(key))); + } else if (key.equals(Att.BRACKET_LABEL().key())) { + newAtt = newAtt.add(Att.BRACKET_LABEL(), KLabel.class, toKLabel(attMap.getJsonObject(key))); + } else if (key.equals(Att.PREDICATE().key())) { + newAtt = newAtt.add(Att.PREDICATE(), Sort.class, toSort(attMap.getJsonObject(key))); + } else if (key.equals(Att.CELL_OPT_ABSENT().key())) { + newAtt = newAtt.add(Att.CELL_OPT_ABSENT(), Sort.class, toSort(attMap.getJsonObject(key))); + } else if (key.equals(Att.CELL_FRAGMENT().key())) { + newAtt = newAtt.add(Att.CELL_FRAGMENT(), Sort.class, toSort(attMap.getJsonObject(key))); + } else if (key.equals(Att.SORT_PARAMS().key())) { + newAtt = newAtt.add(Att.SORT_PARAMS(), Sort.class, toSort(attMap.getJsonObject(key))); + } else { + Att.Key attKey = + Att.getBuiltinKeyOptional(key) + // The JSON is emitted after we may have added internal attributes + .or(() -> Att.getInternalKeyOptional(key)) + .orElseThrow( + () -> + KEMException.criticalError( + "Unrecognized attribute " + + key + + " found in KAST Json term when unparsing KATT: " + + attMap + + "\n" + + "Hint: User-defined groups can be added with the group(_)" + + " attribute.")); + newAtt = newAtt.add(attKey, attMap.getString(key)); + } } - - private static ProductionItem toProductionItem(JsonObject data) { - switch (data.getString("node")) { - case KNONTERMINAL -> { - Sort sort = toSort(data.getJsonObject("sort")); - Option name = Option.apply(data.containsKey("name") ? data.getString("name") : null); - return new NonTerminal(sort, name); - } - case KREGEXTERMINAL -> { - String precedeRegex = data.getString("precedeRegex"); - String regex = data.getString("regex"); - String followRegex = data.getString("followRegex"); - return new RegexTerminal(precedeRegex, regex, followRegex); - } - case KTERMINAL -> { - String value = data.getString("value"); - return new Terminal(value); - } - default -> throw KEMException.criticalError("Unexpected node found in ProductionItem Json term: " + data.getString("node")); - } + Either newAttOrError = newAtt.withGroupAttAsUserGroups(); + if (newAttOrError.isLeft()) { + throw KEMException.criticalError( + newAttOrError.left().get() + + "\nOccurred in KAST Json term when unparsing KATT: " + + attMap); } - -////////////////////// -// Parsing Att Json // -////////////////////// - - public static Att toAtt(JsonObject data) { - if (! (data.getString("node").equals(KATT) && data.containsKey("att"))) - throw KEMException.criticalError("Unexpected node found in KAST Json term when unparsing KATT: " + data.getString("node")); - JsonObject attMap = data.getJsonObject("att"); - Att newAtt = Att.empty(); - for (String key: attMap.keySet()) { - if (key.equals(Location.class.getName())) { - JsonArray locarr = attMap.getJsonArray(Location.class.getName()); - newAtt = newAtt.add(Location.class, Location(locarr.getInt(0), locarr.getInt(1), locarr.getInt(2), locarr.getInt(3))); - } else if (key.equals(Source.class.getName())) { - newAtt = newAtt.add(Source.class, Source.apply(attMap.getString(key))); - } else if (key.equals(Production.class.getName())) { - newAtt = newAtt.add(Production.class, (Production) toSentence(attMap.getJsonObject(key))); - } else if (key.equals(Sort.class.getName())) { - newAtt = newAtt.add(Sort.class, toSort(attMap.getJsonObject(key))); - } else if (key.equals(Att.BRACKET_LABEL().key())) { - newAtt = newAtt.add(Att.BRACKET_LABEL(), KLabel.class, toKLabel(attMap.getJsonObject(key))); - } else if (key.equals(Att.PREDICATE().key())) { - newAtt = newAtt.add(Att.PREDICATE(), Sort.class, toSort(attMap.getJsonObject(key))); - } else if (key.equals(Att.CELL_OPT_ABSENT().key())) { - newAtt = newAtt.add(Att.CELL_OPT_ABSENT(), Sort.class, toSort(attMap.getJsonObject(key))); - } else if (key.equals(Att.CELL_FRAGMENT().key())) { - newAtt = newAtt.add(Att.CELL_FRAGMENT(), Sort.class, toSort(attMap.getJsonObject(key))); - } else if (key.equals(Att.SORT_PARAMS().key())) { - newAtt = newAtt.add(Att.SORT_PARAMS(), Sort.class, toSort(attMap.getJsonObject(key))); - } else { - Att.Key attKey = - Att.getBuiltinKeyOptional(key) - // The JSON is emitted after we may have added internal attributes - .or(() -> Att.getInternalKeyOptional(key)) - .orElseThrow(() -> - KEMException.criticalError("Unrecognized attribute " + key + - " found in KAST Json term when unparsing KATT: " + - attMap + - "\nHint: User-defined groups can be added with the group(_) attribute.") - ); - newAtt = newAtt.add(attKey, attMap.getString(key)); - } - } - Either newAttOrError = newAtt.withGroupAttAsUserGroups(); - if (newAttOrError.isLeft()) { - throw KEMException.criticalError(newAttOrError.left().get() + - "\nOccurred in KAST Json term when unparsing KATT: " + attMap); - } - return newAttOrError.right().get(); + return newAttOrError.right().get(); + } + + //////////////////// + // Parsing K Json // + //////////////////// + + public static K parse(byte[] data) { + return parse(new String(data, StandardCharsets.UTF_8)); + } + + public static K parse(String data) { + JsonReader reader = Json.createReader(new StringReader(data)); + return parseJson(reader.readObject()); + } + + public static K parseJson(JsonObject data) { + if (!(data.containsKey("format") && data.containsKey("version") && data.containsKey("term"))) { + throw KEMException.criticalError( + "Must have `format`, `version`, and `term` fields in serialized Json!"); } - -//////////////////// -// Parsing K Json // -//////////////////// - - public static K parse(byte[] data) { - return parse(new String(data, StandardCharsets.UTF_8)); + if (!data.getString("format").equals("KAST")) { + throw KEMException.criticalError( + "Only can deserialize 'KAST' format Json! Found: " + data.getString("format")); } - - public static K parse(String data) { - JsonReader reader = Json.createReader(new StringReader(data)); - return parseJson(reader.readObject()); + if (data.getInt("version") != ToJson.version) { + throw KEMException.criticalError( + "Only can deserialize KAST version '" + + ToJson.version + + "'! Found: " + + data.getInt("version")); } - - public static K parseJson(JsonObject data) { - if (! (data.containsKey("format") && data.containsKey("version") && data.containsKey("term"))) { - throw KEMException.criticalError("Must have `format`, `version`, and `term` fields in serialized Json!"); + return toK(data.getJsonObject("term")); + } + + private static K toK(JsonObject data) { + KLabel klabel; + + switch (data.getString("node")) { + case KTOKEN: + return KToken(data.getString("token"), toSort(data.getJsonObject("sort"))); + + case KAPPLY: + int arity = data.getInt("arity"); + K[] args = toKs(arity, data.getJsonArray("args")); + klabel = toKLabel(data.getJsonObject("label")); + return KApply(klabel, args); + + case KSEQUENCE: + int seqLen = data.getInt("arity"); + K[] items = toKs(seqLen, data.getJsonArray("items")); + return KSequence(items); + + case KVARIABLE: + Att varAtt = Att.empty(); + if (data.containsKey("sort")) { + varAtt = varAtt.add(Sort.class, toSort(data.getJsonObject("sort"))); } - if (! data.getString("format").equals("KAST")) { - throw KEMException.criticalError("Only can deserialize 'KAST' format Json! Found: " + data.getString("format")); - } - if (data.getInt("version") != ToJson.version) { - throw KEMException.criticalError("Only can deserialize KAST version '" + ToJson.version + "'! Found: " + data.getInt("version")); - } - return toK(data.getJsonObject("term")); - } - - private static K toK(JsonObject data) { - KLabel klabel; - - switch (data.getString("node")) { + return KVariable(data.getString("name"), varAtt); - case KTOKEN: - return KToken(data.getString("token"), toSort(data.getJsonObject("sort"))); + case KREWRITE: + K lhs = toK(data.getJsonObject("lhs")); + K rhs = toK(data.getJsonObject("rhs")); + return KRewrite(lhs, rhs, Att.empty()); - case KAPPLY: - int arity = data.getInt("arity"); - K[] args = toKs(arity, data.getJsonArray("args")); - klabel = toKLabel(data.getJsonObject("label")); - return KApply(klabel, args); + case KAS: + K pattern = toK(data.getJsonObject("pattern")); + K alias = toK(data.getJsonObject("alias")); + return KORE.KAs(pattern, alias, Att.empty()); - case KSEQUENCE: - int seqLen = data.getInt("arity"); - K[] items = toKs(seqLen, data.getJsonArray("items")); - return KSequence(items); + case INJECTEDKLABEL: + klabel = toKLabel(data.getJsonObject("label")); + return InjectedKLabel(klabel); - case KVARIABLE: - Att varAtt = Att.empty(); - if (data.containsKey("sort")) { - varAtt = varAtt.add(Sort.class, toSort(data.getJsonObject("sort"))); - } - return KVariable(data.getString("name"), varAtt); - - case KREWRITE: - K lhs = toK(data.getJsonObject("lhs")); - K rhs = toK(data.getJsonObject("rhs")); - return KRewrite(lhs, rhs, Att.empty()); - - case KAS: - K pattern = toK(data.getJsonObject("pattern")); - K alias = toK(data.getJsonObject("alias")); - return KORE.KAs(pattern, alias, Att.empty()); - - case INJECTEDKLABEL: - klabel = toKLabel(data.getJsonObject("label")); - return InjectedKLabel(klabel); - - default: - throw KEMException.criticalError("Unexpected node found in KAST Json term: " + data.getString("node")); - } + default: + throw KEMException.criticalError( + "Unexpected node found in KAST Json term: " + data.getString("node")); } + } - private static KLabel toKLabel(JsonObject data) { - JsonArray jparams = data.getJsonArray("params"); - List params = new ArrayList<>(); - for (JsonValue p : jparams) { - params.add(toSort((JsonObject)p)); - } - Sort[] sarray = params.toArray(new Sort[0]); - return KLabel(data.getString("name"), sarray); + private static KLabel toKLabel(JsonObject data) { + JsonArray jparams = data.getJsonArray("params"); + List params = new ArrayList<>(); + for (JsonValue p : jparams) { + params.add(toSort((JsonObject) p)); } - - private static K[] toKs(int arity, JsonArray data) { - K[] items = new K[arity]; - for (int i = 0; i < arity; i++) { - items[i] = toK(data.getValuesAs(JsonObject.class).get(i)); - } - return items; + Sort[] sarray = params.toArray(new Sort[0]); + return KLabel(data.getString("name"), sarray); + } + + private static K[] toKs(int arity, JsonArray data) { + K[] items = new K[arity]; + for (int i = 0; i < arity; i++) { + items[i] = toK(data.getValuesAs(JsonObject.class).get(i)); } + return items; + } } diff --git a/kernel/src/main/java/org/kframework/parser/outer/ExtractFencedKCodeFromMarkdown.java b/kernel/src/main/java/org/kframework/parser/outer/ExtractFencedKCodeFromMarkdown.java index f9b011dabda..adec5076a3f 100644 --- a/kernel/src/main/java/org/kframework/parser/outer/ExtractFencedKCodeFromMarkdown.java +++ b/kernel/src/main/java/org/kframework/parser/outer/ExtractFencedKCodeFromMarkdown.java @@ -7,114 +7,111 @@ import com.vladsch.flexmark.util.ast.NodeVisitor; import com.vladsch.flexmark.util.ast.VisitHandler; import com.vladsch.flexmark.util.data.MutableDataSet; +import java.util.HashSet; +import java.util.Set; import org.jetbrains.annotations.NotNull; import org.kframework.attributes.Source; import org.kframework.parser.markdown.ASTExpressionStart; import org.kframework.parser.markdown.TagSelector; -import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KExceptionManager; -import java.util.HashSet; -import java.util.Set; - /** * Takes a Markdown file, and extract annotated code-blocks according to the mdSelector expression. * The inner code is kept exactly in place so error reporting can be precise. + * * @author Radu Mereuta */ public class ExtractFencedKCodeFromMarkdown { - private final KExceptionManager kem; + private final KExceptionManager kem; + private final ASTExpressionStart mdSelector; + + public ExtractFencedKCodeFromMarkdown(KExceptionManager kem, String mdSelector) { + this.kem = kem; + this.mdSelector = TagSelector.parseSelectorExp(mdSelector); + } + + public String extract(String mdText, Source source) { + KCodeExtractor extractor = new KCodeExtractor(mdText, mdSelector, source, kem); + return extractor.getKCode(); + } + + private static class KCodeExtractor { private final ASTExpressionStart mdSelector; + private final String mdText; + private final Source source; + private final KExceptionManager kem; + int lastOffset; + // gather the k code in a single string without markdown + StringBuilder kCodeSb; + // build a copy with only whitespaces so location information for code-block parsing matches + StringBuilder blankSb; - public ExtractFencedKCodeFromMarkdown(KExceptionManager kem, String mdSelector) { - this.kem = kem; - this.mdSelector = TagSelector.parseSelectorExp(mdSelector); + public KCodeExtractor( + String mdText, ASTExpressionStart mdSelector, Source source, KExceptionManager kem) { + this.mdText = mdText; + this.mdSelector = mdSelector; + this.source = source; + this.kem = kem; } - public String extract(String mdText, Source source) { - KCodeExtractor extractor = new KCodeExtractor(mdText, mdSelector, source, kem); - return extractor.getKCode(); - } + NodeVisitor visitor = new NodeVisitor(new VisitHandler<>(FencedCodeBlock.class, this::visit)); - private static class KCodeExtractor { - private final ASTExpressionStart mdSelector; - private final String mdText; - private final Source source; - private final KExceptionManager kem; - int lastOffset; - // gather the k code in a single string without markdown - StringBuilder kCodeSb; - // build a copy with only whitespaces so location information for code-block parsing matches - StringBuilder blankSb; - public KCodeExtractor(String mdText, ASTExpressionStart mdSelector, Source source, KExceptionManager kem) { - this.mdText = mdText; - this.mdSelector = mdSelector; - this.source = source; - this.kem = kem; + public void visit(FencedCodeBlock block) { + // copy up to where the code-block info starts + while (lastOffset < block.getInfo().getStartOffset()) { + if (Character.isWhitespace(mdText.charAt(lastOffset))) { + kCodeSb.append(mdText.charAt(lastOffset)); + blankSb.append(mdText.charAt(lastOffset)); + } else blankSb.append(" "); + lastOffset++; + } + String cbStr = block.getInfo().toString(); + Set tags = new HashSet<>(); + tags = TagSelector.parseTags(blankSb + cbStr, source, kem); + // interested only in code blocks marked as valid by the mdSelector expression + if (TagSelector.eval(mdSelector, tags)) { + // navigate from previous offset to the current one and + // make everything whitespace to preserve location info + long offset = block.getContentChars().getStartOffset(); + while (lastOffset < offset) { + if (Character.isWhitespace(mdText.charAt(lastOffset))) { + kCodeSb.append(mdText.charAt(lastOffset)); + blankSb.append(mdText.charAt(lastOffset)); + } else blankSb.append(" "); + lastOffset++; } - - NodeVisitor visitor = new NodeVisitor( - new VisitHandler<>(FencedCodeBlock.class, this::visit) - ); - - public void visit(FencedCodeBlock block) { - // copy up to where the code-block info starts - while (lastOffset < block.getInfo().getStartOffset()) { - if (Character.isWhitespace(mdText.charAt(lastOffset))) { - kCodeSb.append(mdText.charAt(lastOffset)); - blankSb.append(mdText.charAt(lastOffset)); - } else - blankSb.append(" "); - lastOffset++; - } - String cbStr = block.getInfo().toString(); - Set tags = new HashSet<>(); - tags = TagSelector.parseTags(blankSb + cbStr, source, kem); - // interested only in code blocks marked as valid by the mdSelector expression - if (TagSelector.eval(mdSelector, tags)) { - // navigate from previous offset to the current one and - // make everything whitespace to preserve location info - long offset = block.getContentChars().getStartOffset(); - while (lastOffset < offset) { - if (Character.isWhitespace(mdText.charAt(lastOffset))) { - kCodeSb.append(mdText.charAt(lastOffset)); - blankSb.append(mdText.charAt(lastOffset)); - } else - blankSb.append(" "); - lastOffset++; - } - // copy each character because block.getContentChars() removes indentation and can offset location info - offset = block.getContentChars().getEndOffset(); - while (lastOffset < offset) { - kCodeSb.append(mdText.charAt(lastOffset)); - if (Character.isWhitespace(mdText.charAt(lastOffset))) - blankSb.append(mdText.charAt(lastOffset)); - else - blankSb.append(" "); - lastOffset++; - } - } - // Descending into children - visitor.visitChildren(block); + // copy each character because block.getContentChars() removes indentation and can offset + // location info + offset = block.getContentChars().getEndOffset(); + while (lastOffset < offset) { + kCodeSb.append(mdText.charAt(lastOffset)); + if (Character.isWhitespace(mdText.charAt(lastOffset))) + blankSb.append(mdText.charAt(lastOffset)); + else blankSb.append(" "); + lastOffset++; } + } + // Descending into children + visitor.visitChildren(block); + } - String getKCode() { - MutableDataSet options = new MutableDataSet(); - Parser parser = Parser.builder(options).build(); - @NotNull Document doc = parser.parse(mdText); - lastOffset = 0; - kCodeSb = new StringBuilder(); - blankSb = new StringBuilder(); - visitor.visit(doc); - // make everything whitespace to preserve location info for end of file errors - while (lastOffset < mdText.length()) { - if (Character.isWhitespace(mdText.charAt(lastOffset))) - kCodeSb.append(mdText.charAt(lastOffset)); - lastOffset++; - } + String getKCode() { + MutableDataSet options = new MutableDataSet(); + Parser parser = Parser.builder(options).build(); + @NotNull Document doc = parser.parse(mdText); + lastOffset = 0; + kCodeSb = new StringBuilder(); + blankSb = new StringBuilder(); + visitor.visit(doc); + // make everything whitespace to preserve location info for end of file errors + while (lastOffset < mdText.length()) { + if (Character.isWhitespace(mdText.charAt(lastOffset))) + kCodeSb.append(mdText.charAt(lastOffset)); + lastOffset++; + } - return kCodeSb.toString(); - } + return kCodeSb.toString(); } + } } diff --git a/kernel/src/main/java/org/kframework/unparser/AddBrackets.java b/kernel/src/main/java/org/kframework/unparser/AddBrackets.java index 4dcfa92dada..a8eee37bbb8 100644 --- a/kernel/src/main/java/org/kframework/unparser/AddBrackets.java +++ b/kernel/src/main/java/org/kframework/unparser/AddBrackets.java @@ -1,6 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; import org.kframework.attributes.Att; import org.kframework.builtin.Sorts; import org.kframework.definition.Module; @@ -16,196 +22,209 @@ import org.pcollections.ConsPStack; import scala.Tuple2; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; - -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; - /** - * Implements the naive algorithm to add brackets in order to disambiguate an unparsed AST. This algorithm executes - * in linear time in the size of the term, but does not correctly solve grammars in which multiple productions share - * the same terminals in such a way as to cause ambiguities that cannot be resolved using priorities and associativities. - * As such, we use this algorithm in krun in output --pretty, but it is insufficient for --output sound. + * Implements the naive algorithm to add brackets in order to disambiguate an unparsed AST. This + * algorithm executes in linear time in the size of the term, but does not correctly solve grammars + * in which multiple productions share the same terminals in such a way as to cause ambiguities that + * cannot be resolved using priorities and associativities. As such, we use this algorithm in krun + * in output --pretty, but it is insufficient for --output sound. */ public record AddBrackets(Module m) { - public ProductionReference addBrackets(ProductionReference t) { - return addBrackets(t, null, null); - } + public ProductionReference addBrackets(ProductionReference t) { + return addBrackets(t, null, null); + } - public ProductionReference addBrackets(ProductionReference t, ProductionReference previousLeftCapture, ProductionReference previousRightCapture) { - if (t instanceof Constant) { - return t; - } - TermCons outer = (TermCons)t; - List newItems = new ArrayList<>(); - for (Term t2 : outer.items()) { - ProductionReference inner = (ProductionReference) t2; - ProductionReference leftCapture = getLeftCapture(previousLeftCapture, outer, inner); - ProductionReference rightCapture = getRightCapture(previousRightCapture, outer, inner); - ProductionReference newInner = addBrackets(inner, outer, leftCapture, rightCapture); - newInner = addBrackets(newInner, leftCapture, rightCapture); - newItems.add(newInner); - } - return TermCons.apply(ConsPStack.from(newItems), outer.production()); - } - - public ProductionReference addBrackets(ProductionReference inner, TermCons outer, ProductionReference leftCapture, ProductionReference rightCapture) { - if (requiresBracketWithSimpleAlgorithm(outer, leftCapture, rightCapture, inner)) { - int position = getPosition(inner, outer); - Sort outerSort = ((NonTerminal)outer.production().items().apply(position)).sort(); - Sort innerSort = inner.production().sort(); - for (Tuple2> sort : iterable(m.bracketProductionsFor())) { - boolean isCorrectOuterSort = m.subsorts().lessThanEq(sort._1(), outerSort); - if (isCorrectOuterSort) { - for (Production p : mutable(sort._2())) { - boolean isCorrectInnerSort = stream(p.items()) - .filter(i -> i instanceof NonTerminal) - .map(i -> (NonTerminal) i) - .map(NonTerminal::sort) - .anyMatch(s -> m.subsorts().lessThanEq(innerSort, s)); - if (isCorrectInnerSort) { - return TermCons.apply(ConsPStack.singleton(inner), p); - } - } - } - } - return TermCons.apply(ConsPStack.singleton(inner), Production(Seq(), Sorts.KBott(), Seq(NonTerminal(Sorts.K())))); - } - return inner; - } - - boolean requiresBracketWithSimpleAlgorithm(ProductionReference outer, ProductionReference leftCapture, ProductionReference rightCapture, ProductionReference inner) { - boolean priority = isPriorityWrong(outer, inner, getPosition(inner, outer)); - boolean inversePriority; - EnumSet fixity = getFixity(inner, outer); - EnumSet innerFixity = getFixity(inner); - if (inner.production().klabel().equals(outer.production().klabel()) && - inner.production().klabel().isDefined() && - m.attributesFor().apply(inner.production().klabel().get().head()).contains(Att.ASSOC())) - return false; - if (inner instanceof Constant) - return false; - if (fixity.size() == 0) - return false; - if (priority) - return true; - if (inner.production().isSyntacticSubsort()) - return false; - - if (innerFixity.contains(Fixity.BARE_RIGHT) && rightCapture != null) { - inversePriority = isPriorityWrong(inner, rightCapture, inner.production().items().size() - 1); - EnumSet rightCaptureFixity = getFixity(rightCapture); - if (!inversePriority && rightCaptureFixity.contains(Fixity.BARE_LEFT)) { - return true; + public ProductionReference addBrackets( + ProductionReference t, + ProductionReference previousLeftCapture, + ProductionReference previousRightCapture) { + if (t instanceof Constant) { + return t; + } + TermCons outer = (TermCons) t; + List newItems = new ArrayList<>(); + for (Term t2 : outer.items()) { + ProductionReference inner = (ProductionReference) t2; + ProductionReference leftCapture = getLeftCapture(previousLeftCapture, outer, inner); + ProductionReference rightCapture = getRightCapture(previousRightCapture, outer, inner); + ProductionReference newInner = addBrackets(inner, outer, leftCapture, rightCapture); + newInner = addBrackets(newInner, leftCapture, rightCapture); + newItems.add(newInner); + } + return TermCons.apply(ConsPStack.from(newItems), outer.production()); + } + + public ProductionReference addBrackets( + ProductionReference inner, + TermCons outer, + ProductionReference leftCapture, + ProductionReference rightCapture) { + if (requiresBracketWithSimpleAlgorithm(outer, leftCapture, rightCapture, inner)) { + int position = getPosition(inner, outer); + Sort outerSort = ((NonTerminal) outer.production().items().apply(position)).sort(); + Sort innerSort = inner.production().sort(); + for (Tuple2> sort : + iterable(m.bracketProductionsFor())) { + boolean isCorrectOuterSort = m.subsorts().lessThanEq(sort._1(), outerSort); + if (isCorrectOuterSort) { + for (Production p : mutable(sort._2())) { + boolean isCorrectInnerSort = + stream(p.items()) + .filter(i -> i instanceof NonTerminal) + .map(i -> (NonTerminal) i) + .map(NonTerminal::sort) + .anyMatch(s -> m.subsorts().lessThanEq(innerSort, s)); + if (isCorrectInnerSort) { + return TermCons.apply(ConsPStack.singleton(inner), p); } + } } - if (innerFixity.contains(Fixity.BARE_LEFT) && leftCapture != null) { - inversePriority = isPriorityWrong(inner, leftCapture, 0); - EnumSet leftCaptureFixity = getFixity(leftCapture); - return !inversePriority && leftCaptureFixity.contains(Fixity.BARE_RIGHT); - } - return false; + } + return TermCons.apply( + ConsPStack.singleton(inner), + Production(Seq(), Sorts.KBott(), Seq(NonTerminal(Sorts.K())))); } - - private boolean isPriorityWrong(ProductionReference outer, ProductionReference inner, int position) { - if (outer.production().klabel().isEmpty() || inner.production().klabel().isEmpty()) { - return false; - } - Tag parentLabel = new Tag(outer.production().klabel().get().name()); - Tag localLabel = new Tag(inner.production().klabel().get().name()); - if (!m.subsorts().lessThanEq(inner.production().sort(), ((NonTerminal)outer.production().items().apply(position)).sort())) { - return true; - } - if (m.priorities().lessThan(parentLabel, localLabel)) { - return true; - } - if (m.leftAssoc().contains(new Tuple2<>(parentLabel, localLabel)) && position == outer.production().items().size() - 1) { - return true; - } - return m.rightAssoc().contains(new Tuple2<>(parentLabel, localLabel)) && position == 0; + return inner; + } + + boolean requiresBracketWithSimpleAlgorithm( + ProductionReference outer, + ProductionReference leftCapture, + ProductionReference rightCapture, + ProductionReference inner) { + boolean priority = isPriorityWrong(outer, inner, getPosition(inner, outer)); + boolean inversePriority; + EnumSet fixity = getFixity(inner, outer); + EnumSet innerFixity = getFixity(inner); + if (inner.production().klabel().equals(outer.production().klabel()) + && inner.production().klabel().isDefined() + && m.attributesFor().apply(inner.production().klabel().get().head()).contains(Att.ASSOC())) + return false; + if (inner instanceof Constant) return false; + if (fixity.size() == 0) return false; + if (priority) return true; + if (inner.production().isSyntacticSubsort()) return false; + + if (innerFixity.contains(Fixity.BARE_RIGHT) && rightCapture != null) { + inversePriority = isPriorityWrong(inner, rightCapture, inner.production().items().size() - 1); + EnumSet rightCaptureFixity = getFixity(rightCapture); + if (!inversePriority && rightCaptureFixity.contains(Fixity.BARE_LEFT)) { + return true; + } } - - private enum Fixity { - BARE_LEFT, - BARE_RIGHT + if (innerFixity.contains(Fixity.BARE_LEFT) && leftCapture != null) { + inversePriority = isPriorityWrong(inner, leftCapture, 0); + EnumSet leftCaptureFixity = getFixity(leftCapture); + return !inversePriority && leftCaptureFixity.contains(Fixity.BARE_RIGHT); } + return false; + } - ProductionReference getLeftCapture(ProductionReference previousLeftCapture, ProductionReference outer, ProductionReference inner) { - EnumSet fixity = getFixity(outer); - int position = getPosition(inner, outer); - if (position == 0 && fixity.contains(Fixity.BARE_LEFT)) { - return previousLeftCapture; - } else { - return outer; - } + private boolean isPriorityWrong( + ProductionReference outer, ProductionReference inner, int position) { + if (outer.production().klabel().isEmpty() || inner.production().klabel().isEmpty()) { + return false; } - - ProductionReference getRightCapture(ProductionReference previousRightCapture, ProductionReference outer, ProductionReference inner) { - EnumSet fixity = getFixity(outer); - int position = getPosition(inner, outer); - if (position == outer.production().items().size() - 1 && fixity.contains(Fixity.BARE_RIGHT)) { - return previousRightCapture; - } else { - return outer; - } + Tag parentLabel = new Tag(outer.production().klabel().get().name()); + Tag localLabel = new Tag(inner.production().klabel().get().name()); + if (!m.subsorts() + .lessThanEq( + inner.production().sort(), + ((NonTerminal) outer.production().items().apply(position)).sort())) { + return true; + } + if (m.priorities().lessThan(parentLabel, localLabel)) { + return true; + } + if (m.leftAssoc().contains(new Tuple2<>(parentLabel, localLabel)) + && position == outer.production().items().size() - 1) { + return true; + } + return m.rightAssoc().contains(new Tuple2<>(parentLabel, localLabel)) && position == 0; + } + + private enum Fixity { + BARE_LEFT, + BARE_RIGHT + } + + ProductionReference getLeftCapture( + ProductionReference previousLeftCapture, + ProductionReference outer, + ProductionReference inner) { + EnumSet fixity = getFixity(outer); + int position = getPosition(inner, outer); + if (position == 0 && fixity.contains(Fixity.BARE_LEFT)) { + return previousLeftCapture; + } else { + return outer; + } + } + + ProductionReference getRightCapture( + ProductionReference previousRightCapture, + ProductionReference outer, + ProductionReference inner) { + EnumSet fixity = getFixity(outer); + int position = getPosition(inner, outer); + if (position == outer.production().items().size() - 1 && fixity.contains(Fixity.BARE_RIGHT)) { + return previousRightCapture; + } else { + return outer; } + } - private EnumSet getFixity(ProductionReference t) { - Production p = t.production(); - EnumSet set = EnumSet.noneOf(Fixity.class); - if (t instanceof Constant) { - return set; - } - if (p.items().apply(0) instanceof NonTerminal) - set.add(Fixity.BARE_LEFT); - if (p.items().apply(p.items().size() - 1) instanceof NonTerminal) - set.add(Fixity.BARE_RIGHT); - return set; - } - - private EnumSet getFixity(ProductionReference inner, ProductionReference outer) { - assert outer instanceof TermCons; - TermCons tc = (TermCons)outer; - int i; - for (i = 0; i < tc.items().size(); i++) { - if (tc.get(i) == inner) - break; - } - Production p = tc.production(); - EnumSet set = EnumSet.noneOf(Fixity.class); - int position = getPosition(inner, outer); - if (!hasTerminalAtIdx(p, position+1)) { - set.add(Fixity.BARE_RIGHT); - } - if (!hasTerminalAtIdx(p, position-1)) { - set.add(Fixity.BARE_LEFT); - } - return set; + private EnumSet getFixity(ProductionReference t) { + Production p = t.production(); + EnumSet set = EnumSet.noneOf(Fixity.class); + if (t instanceof Constant) { + return set; + } + if (p.items().apply(0) instanceof NonTerminal) set.add(Fixity.BARE_LEFT); + if (p.items().apply(p.items().size() - 1) instanceof NonTerminal) set.add(Fixity.BARE_RIGHT); + return set; + } + + private EnumSet getFixity(ProductionReference inner, ProductionReference outer) { + assert outer instanceof TermCons; + TermCons tc = (TermCons) outer; + int i; + for (i = 0; i < tc.items().size(); i++) { + if (tc.get(i) == inner) break; + } + Production p = tc.production(); + EnumSet set = EnumSet.noneOf(Fixity.class); + int position = getPosition(inner, outer); + if (!hasTerminalAtIdx(p, position + 1)) { + set.add(Fixity.BARE_RIGHT); } + if (!hasTerminalAtIdx(p, position - 1)) { + set.add(Fixity.BARE_LEFT); + } + return set; + } - boolean hasTerminalAtIdx(Production p, int position) { - if (position < 0 || position >= p.items().size()) { - return false; - } - return p.items().apply(position) instanceof TerminalLike; - } - - private int getPosition(ProductionReference inner, ProductionReference outer) { - EnumSet set = EnumSet.noneOf(Fixity.class); - assert outer instanceof TermCons; - TermCons tc = (TermCons)outer; - Production p = tc.production(); - for (int i = 0, j = 0; i < p.items().size(); i++) { - if (p.items().apply(i) instanceof NonTerminal) { - if (tc.get(j) == inner) { - return i; - } - j++; - } - } - throw new AssertionError(); + boolean hasTerminalAtIdx(Production p, int position) { + if (position < 0 || position >= p.items().size()) { + return false; + } + return p.items().apply(position) instanceof TerminalLike; + } + + private int getPosition(ProductionReference inner, ProductionReference outer) { + EnumSet set = EnumSet.noneOf(Fixity.class); + assert outer instanceof TermCons; + TermCons tc = (TermCons) outer; + Production p = tc.production(); + for (int i = 0, j = 0; i < p.items().size(); i++) { + if (p.items().apply(i) instanceof NonTerminal) { + if (tc.get(j) == inner) { + return i; + } + j++; + } } + throw new AssertionError(); + } } diff --git a/kernel/src/main/java/org/kframework/unparser/ColorSetting.java b/kernel/src/main/java/org/kframework/unparser/ColorSetting.java index 11aa53687c0..c3c752a89ff 100644 --- a/kernel/src/main/java/org/kframework/unparser/ColorSetting.java +++ b/kernel/src/main/java/org/kframework/unparser/ColorSetting.java @@ -2,9 +2,10 @@ package org.kframework.unparser; /** - * @author Denis Bogdanas - * Date: 10/9/13 + * @author Denis Bogdanas Date: 10/9/13 */ public enum ColorSetting { - OFF, ON, EXTENDED + OFF, + ON, + EXTENDED } diff --git a/kernel/src/main/java/org/kframework/unparser/Formatter.java b/kernel/src/main/java/org/kframework/unparser/Formatter.java index 8b65a020851..d56babf66ef 100644 --- a/kernel/src/main/java/org/kframework/unparser/Formatter.java +++ b/kernel/src/main/java/org/kframework/unparser/Formatter.java @@ -2,6 +2,9 @@ package org.kframework.unparser; +import static org.fusesource.jansi.Ansi.*; +import static org.kframework.Collections.*; + import org.kframework.attributes.Att; import org.kframework.definition.NonTerminal; import org.kframework.definition.Production; @@ -10,135 +13,158 @@ import org.kframework.parser.Constant; import org.kframework.parser.Term; import org.kframework.parser.TermCons; -import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.ColorUtil; - -import static org.kframework.Collections.*; -import static org.fusesource.jansi.Ansi.*; +import org.kframework.utils.errorsystem.KEMException; public class Formatter { - public static String format(Term term) { - Indenter indenter = new Indenter(2); - format(term, indenter, ColorSetting.OFF); - return indenter.toString(); - } + public static String format(Term term) { + Indenter indenter = new Indenter(2); + format(term, indenter, ColorSetting.OFF); + return indenter.toString(); + } - public static String format(Term term, ColorSetting colorize) { - Indenter indenter = new Indenter(2); - format(term, indenter, colorize); - return indenter.toString(); - } + public static String format(Term term, ColorSetting colorize) { + Indenter indenter = new Indenter(2); + format(term, indenter, colorize); + return indenter.toString(); + } - public static void format(Term term, Indenter indenter, ColorSetting colorize) { - int indent = 0; - int localColor = 0; - if (term instanceof Constant c) { - color(indenter, c.production(), 0, colorize); - indenter.append(c.value()); - resetColor(indenter, c.production(), colorize); - } else if (term instanceof TermCons tc) { - String format = tc.production().att().getOptional(Att.FORMAT()).orElse(defaultFormat(tc.production().items().size())); - for (int i = 0; i < format.length(); i++) { - char c = format.charAt(i); - if (c == '%') { - char c2 = format.charAt(i + 1); - i++; - switch (c2) { - case 'n' -> indenter.newline(); - case 'i' -> { - indenter.indent(); - indent++; - } - case 'd' -> { - indenter.dedent(); - indent--; - } - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { - StringBuilder sb = new StringBuilder(); - for (; i < format.length() && format.charAt(i) >= '0' && format.charAt(i) <= '9'; i++) { - sb.append(format.charAt(i)); - } - i--; - int idx = Integer.parseInt(sb.toString()); - if (idx == 0 || idx > tc.production().items().size()) { - throw KEMException.compilerError("Invalid format attribute; index must be in range 1-N for a production with N items.", tc.production()); - } - ProductionItem item = tc.production().items().apply(idx - 1); - if (item instanceof Terminal) { - color(indenter, tc.production(), localColor++, colorize); - indenter.append(((Terminal) item).value()); - resetColor(indenter, tc.production(), colorize); - } else if (item instanceof NonTerminal) { - int nt = 0; - for (ProductionItem pi : iterable(tc.production().items())) { - if (pi instanceof NonTerminal) { - if (pi == item) { - break; - } - nt++; - } - } - assert tc.production().nonterminal(nt) == item; - Term inner = tc.get(nt); - boolean assoc = false; - if (inner instanceof TermCons innerTc) { - Production origProd = tc.production().att().getOptional(Att.ORIGINAL_PRD(), Production.class).orElse(tc.production()); - Production innerOrigProd = innerTc.production().att().getOptional(Att.ORIGINAL_PRD(), Production.class).orElse(innerTc.production()); - if (innerOrigProd.equals(origProd) && origProd.att().contains(Att.ASSOC())) { - assoc = true; - } - } - if (assoc) { - for (int j = 0; j < indent; j++) { - indenter.dedent(); - } - } - format(tc.get(nt), indenter, colorize); - if (assoc) { - for (int j = 0; j < indent; j++) { - indenter.indent(); - } - } - } else { - throw KEMException.internalError("Cannot currently format productions with regex terminals which are not tokens.", tc.production()); - } - } - default -> indenter.append(c2); + public static void format(Term term, Indenter indenter, ColorSetting colorize) { + int indent = 0; + int localColor = 0; + if (term instanceof Constant c) { + color(indenter, c.production(), 0, colorize); + indenter.append(c.value()); + resetColor(indenter, c.production(), colorize); + } else if (term instanceof TermCons tc) { + String format = + tc.production() + .att() + .getOptional(Att.FORMAT()) + .orElse(defaultFormat(tc.production().items().size())); + for (int i = 0; i < format.length(); i++) { + char c = format.charAt(i); + if (c == '%') { + char c2 = format.charAt(i + 1); + i++; + switch (c2) { + case 'n' -> indenter.newline(); + case 'i' -> { + indenter.indent(); + indent++; + } + case 'd' -> { + indenter.dedent(); + indent--; + } + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' -> { + StringBuilder sb = new StringBuilder(); + for (; + i < format.length() && format.charAt(i) >= '0' && format.charAt(i) <= '9'; + i++) { + sb.append(format.charAt(i)); + } + i--; + int idx = Integer.parseInt(sb.toString()); + if (idx == 0 || idx > tc.production().items().size()) { + throw KEMException.compilerError( + "Invalid format attribute; index must be in range 1-N for a production with N" + + " items.", + tc.production()); + } + ProductionItem item = tc.production().items().apply(idx - 1); + if (item instanceof Terminal) { + color(indenter, tc.production(), localColor++, colorize); + indenter.append(((Terminal) item).value()); + resetColor(indenter, tc.production(), colorize); + } else if (item instanceof NonTerminal) { + int nt = 0; + for (ProductionItem pi : iterable(tc.production().items())) { + if (pi instanceof NonTerminal) { + if (pi == item) { + break; } - } else { - indenter.append(c); + nt++; + } + } + assert tc.production().nonterminal(nt) == item; + Term inner = tc.get(nt); + boolean assoc = false; + if (inner instanceof TermCons innerTc) { + Production origProd = + tc.production() + .att() + .getOptional(Att.ORIGINAL_PRD(), Production.class) + .orElse(tc.production()); + Production innerOrigProd = + innerTc + .production() + .att() + .getOptional(Att.ORIGINAL_PRD(), Production.class) + .orElse(innerTc.production()); + if (innerOrigProd.equals(origProd) && origProd.att().contains(Att.ASSOC())) { + assoc = true; + } + } + if (assoc) { + for (int j = 0; j < indent; j++) { + indenter.dedent(); + } + } + format(tc.get(nt), indenter, colorize); + if (assoc) { + for (int j = 0; j < indent; j++) { + indenter.indent(); + } } + } else { + throw KEMException.internalError( + "Cannot currently format productions with regex terminals which are not" + + " tokens.", + tc.production()); + } } + default -> indenter.append(c2); + } + } else { + indenter.append(c); } + } } + } - public static String defaultFormat(int size) { - StringBuilder sb = new StringBuilder(); - for (int i = 1; i <= size; i++) { - sb.append("%").append(i).append(" "); - } - sb.deleteCharAt(sb.length() - 1); - return sb.toString(); + public static String defaultFormat(int size) { + StringBuilder sb = new StringBuilder(); + for (int i = 1; i <= size; i++) { + sb.append("%").append(i).append(" "); } + sb.deleteCharAt(sb.length() - 1); + return sb.toString(); + } - private static void color(Indenter indenter, Production p, int offset, ColorSetting colorize) { - if (p.att().contains(Att.COLOR())) { - indenter.append(ColorUtil.RgbToAnsi(p.att().get(Att.COLOR()), colorize)); - } - if (p.att().contains(Att.COLORS())) { - try { - String color = p.att().get(Att.COLORS()).split(",")[offset].trim(); - indenter.append(ColorUtil.RgbToAnsi(color, colorize)); - } catch (ArrayIndexOutOfBoundsException e) { - throw KEMException.compilerError("Invalid colors attribute. Must be a comma separated list with exactly one element per terminal.", e, p); - } - } + private static void color(Indenter indenter, Production p, int offset, ColorSetting colorize) { + if (p.att().contains(Att.COLOR())) { + indenter.append(ColorUtil.RgbToAnsi(p.att().get(Att.COLOR()), colorize)); + } + if (p.att().contains(Att.COLORS())) { + try { + String color = p.att().get(Att.COLORS()).split(",")[offset].trim(); + indenter.append(ColorUtil.RgbToAnsi(color, colorize)); + } catch (ArrayIndexOutOfBoundsException e) { + throw KEMException.compilerError( + "Invalid colors attribute. Must be a comma separated list with exactly one element per" + + " terminal.", + e, + p); + } } + } - private static void resetColor(Indenter indenter, Production p, ColorSetting colorize) { - if ((p.att().contains(Att.COLOR()) || p.att().contains(Att.COLORS())) && colorize != ColorSetting.OFF) { - indenter.append(ColorUtil.ANSI_NORMAL); - } + private static void resetColor(Indenter indenter, Production p, ColorSetting colorize) { + if ((p.att().contains(Att.COLOR()) || p.att().contains(Att.COLORS())) + && colorize != ColorSetting.OFF) { + indenter.append(ColorUtil.ANSI_NORMAL); } + } } diff --git a/kernel/src/main/java/org/kframework/unparser/Indenter.java b/kernel/src/main/java/org/kframework/unparser/Indenter.java index 2e5967c8114..7168993ed93 100644 --- a/kernel/src/main/java/org/kframework/unparser/Indenter.java +++ b/kernel/src/main/java/org/kframework/unparser/Indenter.java @@ -3,60 +3,60 @@ package org.kframework.unparser; public class Indenter implements Appendable { - private final int indentSize; - private int indentationLevel = 0; - private boolean atNewLine = true; - private final StringBuilder sb = new StringBuilder(); - - public Indenter(int indentSize) { - this.indentSize = indentSize; - } - - public Indenter append(CharSequence str) { - printIndent(); - sb.append(str); - return this; - } - - public Indenter append(CharSequence str, int start, int end) { - printIndent(); - sb.append(str, start, end); - return this; - } - - private void printIndent() { - if (atNewLine) { - for (int i = 0; i < indentSize * indentationLevel; i++) { - sb.append(" "); - } - atNewLine = false; - } - } - - public Indenter indent() { - indentationLevel++; - return this; - } - - public Indenter dedent() { - indentationLevel--; - return this; - } - - public Indenter newline() { - sb.append(System.getProperty("line.separator")); - atNewLine = true; - return this; - } - - @Override - public String toString() { - return sb.toString(); - } - - public Indenter append(char c) { - printIndent(); - sb.append(c); - return this; - } + private final int indentSize; + private int indentationLevel = 0; + private boolean atNewLine = true; + private final StringBuilder sb = new StringBuilder(); + + public Indenter(int indentSize) { + this.indentSize = indentSize; + } + + public Indenter append(CharSequence str) { + printIndent(); + sb.append(str); + return this; + } + + public Indenter append(CharSequence str, int start, int end) { + printIndent(); + sb.append(str, start, end); + return this; + } + + private void printIndent() { + if (atNewLine) { + for (int i = 0; i < indentSize * indentationLevel; i++) { + sb.append(" "); + } + atNewLine = false; + } + } + + public Indenter indent() { + indentationLevel++; + return this; + } + + public Indenter dedent() { + indentationLevel--; + return this; + } + + public Indenter newline() { + sb.append(System.getProperty("line.separator")); + atNewLine = true; + return this; + } + + @Override + public String toString() { + return sb.toString(); + } + + public Indenter append(char c) { + printIndent(); + sb.append(c); + return this; + } } diff --git a/kernel/src/main/java/org/kframework/unparser/KPrint.java b/kernel/src/main/java/org/kframework/unparser/KPrint.java index 983ca441291..7c256b17201 100644 --- a/kernel/src/main/java/org/kframework/unparser/KPrint.java +++ b/kernel/src/main/java/org/kframework/unparser/KPrint.java @@ -1,10 +1,24 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import static org.kframework.kore.KORE.*; + import com.davekoelle.AlphanumComparator; -import com.google.inject.Inject; -import com.google.common.collect.Multiset; import com.google.common.collect.HashMultiset; +import com.google.common.collect.Multiset; +import com.google.inject.Inject; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.annotation.Nullable; import org.kframework.attributes.Att; import org.kframework.backend.kore.ModuleToKORE; @@ -27,7 +41,6 @@ import org.kframework.main.GlobalOptions; import org.kframework.parser.ProductionReference; import org.kframework.parser.Term; -import org.kframework.parser.inner.ParseInModule; import org.kframework.parser.inner.RuleGrammarGenerator; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KExceptionManager; @@ -37,375 +50,406 @@ import scala.Option; import scala.Tuple2; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import static org.kframework.kore.KORE.*; - -/** - * Class for printing information and outputting to files using various serializers. - */ +/** Class for printing information and outputting to files using various serializers. */ @RequestScoped public class KPrint { - private final KExceptionManager kem; - private final FileUtil files; - private final TTYInfo tty; - private final KompileOptions kompileOptions; - - public final PrintOptions options; - - @Nullable - private final CompiledDefinition compiledDefinition; - private final Module executionModule; - private final AddSortInjections addSortInjections; - - public KPrint() { - this(new KExceptionManager(new GlobalOptions()), FileUtil.testFileUtil(), new TTYInfo(false, false, false), - new PrintOptions(), null, new KompileOptions()); - } - - @Inject - public KPrint(KExceptionManager kem, FileUtil files, TTYInfo tty, PrintOptions options, - CompiledDefinition compiledDefinition, KompileOptions kompileOptions) { - this.kem = kem; - this.files = files; - this.tty = tty; - this.options = options; - this.compiledDefinition = compiledDefinition; - if (compiledDefinition != null) { - this.executionModule = compiledDefinition.executionModule(); - this.addSortInjections = new AddSortInjections(executionModule); - } else { - this.executionModule = null; - this.addSortInjections = null; - } - - this.kompileOptions = kompileOptions; + private final KExceptionManager kem; + private final FileUtil files; + private final TTYInfo tty; + private final KompileOptions kompileOptions; + + public final PrintOptions options; + + @Nullable private final CompiledDefinition compiledDefinition; + private final Module executionModule; + private final AddSortInjections addSortInjections; + + public KPrint() { + this( + new KExceptionManager(new GlobalOptions()), + FileUtil.testFileUtil(), + new TTYInfo(false, false, false), + new PrintOptions(), + null, + new KompileOptions()); + } + + @Inject + public KPrint( + KExceptionManager kem, + FileUtil files, + TTYInfo tty, + PrintOptions options, + CompiledDefinition compiledDefinition, + KompileOptions kompileOptions) { + this.kem = kem; + this.files = files; + this.tty = tty; + this.options = options; + this.compiledDefinition = compiledDefinition; + if (compiledDefinition != null) { + this.executionModule = compiledDefinition.executionModule(); + this.addSortInjections = new AddSortInjections(executionModule); + } else { + this.executionModule = null; + this.addSortInjections = null; } - //TODO(dwightguth): use Writer - public void outputFile(String output) { - outputFile(output.getBytes()); - } - - public void outputFile(byte[] output) { - outputFile(output, System.out); + this.kompileOptions = kompileOptions; + } + + // TODO(dwightguth): use Writer + public void outputFile(String output) { + outputFile(output.getBytes()); + } + + public void outputFile(byte[] output) { + outputFile(output, System.out); + } + + public void outputFile(byte[] output, OutputStream out) { + if (options.outputFile == null) { + try { + out.write(output); + out.flush(); + } catch (IOException e) { + throw KEMException.internalError(e.getMessage(), e); + } + } else { + files.saveToWorkingDirectory(options.outputFile, output); } - - public void outputFile(byte[] output, OutputStream out) { - if (options.outputFile == null) { - try { - out.write(output); - out.flush(); - } catch (IOException e) { - throw KEMException.internalError(e.getMessage(), e); - } - } else { - files.saveToWorkingDirectory(options.outputFile, output); + } + + public void prettyPrint(Definition def, Module module, Consumer print, K result) { + prettyPrint(def, module, print, result, Sorts.GeneratedTopCell()); + } + + public void prettyPrint(Definition def, Module module, Consumer print, K result, Sort s) { + print.accept( + prettyPrint( + def, module, result, s, options.color(tty.stdout(), files.getEnv()), options.output)); + } + + public byte[] prettyPrint(Definition def, Module module, K result) { + return prettyPrint( + def, + module, + result, + Sorts.GeneratedTopCell(), + options.color(tty.stdout(), files.getEnv()), + options.output); + } + + public byte[] prettyPrint( + Definition def, + Module module, + K orig, + Sort s, + ColorSetting colorize, + OutputModes outputMode) { + K result = abstractTerm(module, orig); + switch (outputMode) { + case KAST: + case NONE: + case BINARY: + case JSON: + case LATEX: + return serialize(result, outputMode); + case PRETTY: + Module prettyUnparsingModule = + RuleGrammarGenerator.getCombinedGrammar(module, false, files).getExtensionModule(); + return (unparseTerm(result, prettyUnparsingModule, colorize) + "\n").getBytes(); + case PROGRAM: + { + RuleGrammarGenerator gen = new RuleGrammarGenerator(def); + Module programUnparsingModule = + RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(module), false, files) + .getParsingModule(); + return (unparseTerm(result, programUnparsingModule, colorize) + "\n").getBytes(); } - } - - public void prettyPrint(Definition def, Module module, Consumer print, K result) { - prettyPrint(def, module, print, result, Sorts.GeneratedTopCell()); - } - - public void prettyPrint(Definition def, Module module, Consumer print, K result, Sort s) { - print.accept(prettyPrint(def, module, result, s, options.color(tty.stdout(), files.getEnv()), options.output)); - } - - public byte[] prettyPrint(Definition def, Module module, K result) { - return prettyPrint(def, module, result, Sorts.GeneratedTopCell(), options.color(tty.stdout(), files.getEnv()), options.output); - } - - public byte[] prettyPrint(Definition def, Module module, K orig, Sort s, ColorSetting colorize, OutputModes outputMode) { - K result = abstractTerm(module, orig); - switch (outputMode) { - case KAST: - case NONE: - case BINARY: - case JSON: - case LATEX: - return serialize(result, outputMode); - case PRETTY: - Module prettyUnparsingModule = RuleGrammarGenerator.getCombinedGrammar(module, false, files).getExtensionModule(); - return (unparseTerm(result, prettyUnparsingModule, colorize) + "\n").getBytes(); - case PROGRAM: { - RuleGrammarGenerator gen = new RuleGrammarGenerator(def); - Module programUnparsingModule = RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(module), false, files).getParsingModule(); - return (unparseTerm(result, programUnparsingModule, colorize) + "\n").getBytes(); - } - case KORE: - if (compiledDefinition == null) { - throw KEMException.criticalError("KORE output requires a compiled definition."); - } - ModuleToKORE converter = new ModuleToKORE(module, compiledDefinition.topCellInitializer, kompileOptions); - result = ExpandMacros.forNonSentences(executionModule, files, kompileOptions, false).expand(result); - result = addSortInjections.addSortInjections(result, s); - StringBuilder sb = new StringBuilder(); - converter.convert(result, sb); - return sb.toString().getBytes(); - default: - throw KEMException.criticalError("Unsupported output mode without a CompiledDefinition: " + outputMode); + case KORE: + if (compiledDefinition == null) { + throw KEMException.criticalError("KORE output requires a compiled definition."); } + ModuleToKORE converter = + new ModuleToKORE(module, compiledDefinition.topCellInitializer, kompileOptions); + result = + ExpandMacros.forNonSentences(executionModule, files, kompileOptions, false) + .expand(result); + result = addSortInjections.addSortInjections(result, s); + StringBuilder sb = new StringBuilder(); + converter.convert(result, sb); + return sb.toString().getBytes(); + default: + throw KEMException.criticalError( + "Unsupported output mode without a CompiledDefinition: " + outputMode); } + } + + public byte[] serialize(K term) { + return KPrint.serialize(term, options.output); + } + + public static byte[] serialize(K term, OutputModes outputMode) { + return switch (outputMode) { + case KAST -> (ToKast.apply(term) + "\n").getBytes(); + case NONE -> "".getBytes(); + case BINARY -> ToBinary.apply(term); + case JSON -> ToJson.apply(term); + case LATEX -> ToLatex.apply(term); + default -> throw KEMException.criticalError("Unsupported serialization mode: " + outputMode); + }; + } + + public String unparseTerm(K input, Module test) { + return unparseTerm(input, test, options.color(tty.stdout(), files.getEnv())); + } + + public String unparseTerm(K input, Module test, ColorSetting colorize) { + return unparseInternal(test, input, colorize); + } + + private Term disambiguateForUnparse(Module mod, Term t) { + return t; + } + + private String unparseInternal(Module mod, K input, ColorSetting colorize) { + ExpandMacros expandMacros = ExpandMacros.forNonSentences(mod, files, kompileOptions, true); + return Formatter.format( + new AddBrackets(mod) + .addBrackets( + (ProductionReference) + disambiguateForUnparse( + mod, + KOREToTreeNodes.apply( + KOREToTreeNodes.up(mod, expandMacros.expand(input)), mod))), + colorize); + } + + public K abstractTerm(Module mod, K term) { + K filteredSubst = options.noFilterSubstitution ? term : filterSubst(term, mod); + K origNames = + options.restoreOriginalNames ? restoreOriginalNameIfPresent(filteredSubst) : filteredSubst; + K collectionsSorted = options.noSortCollections ? origNames : sortCollections(mod, origNames); + // non-determinism is still possible if associative/commutative collection terms start with + // anonymous vars + K alphaRenamed = options.noAlphaRenaming ? collectionsSorted : alphaRename(collectionsSorted); + K squashedTerm = squashTerms(mod, alphaRenamed); + K flattenedTerm = flattenTerms(mod, squashedTerm); + + return flattenedTerm; + } + + private Set vars(K term) { + return new HashSet<>(multivars(term)); + } + + private Multiset multivars(K term) { + Multiset vars = HashMultiset.create(); + new VisitK() { + @Override + public void apply(KVariable var) { + vars.add(var); + } + }.apply(term); + return vars; + } - public byte[] serialize(K term) { - return KPrint.serialize(term, options.output); - } - - public static byte[] serialize(K term, OutputModes outputMode) { - return switch (outputMode) { - case KAST -> (ToKast.apply(term) + "\n").getBytes(); - case NONE -> "".getBytes(); - case BINARY -> ToBinary.apply(term); - case JSON -> ToJson.apply(term); - case LATEX -> ToLatex.apply(term); - default -> throw KEMException.criticalError("Unsupported serialization mode: " + outputMode); - }; - } - - public String unparseTerm(K input, Module test) { - return unparseTerm(input, test, options.color(tty.stdout(), files.getEnv())); - } - - public String unparseTerm(K input, Module test, ColorSetting colorize) { - return unparseInternal(test, input, colorize); - } - - private Term disambiguateForUnparse(Module mod, Term t) { - return t; - } - - private String unparseInternal(Module mod, K input, ColorSetting colorize) { - ExpandMacros expandMacros = ExpandMacros.forNonSentences(mod, files, kompileOptions, true); - return Formatter.format( - new AddBrackets(mod).addBrackets((ProductionReference) disambiguateForUnparse(mod, KOREToTreeNodes.apply(KOREToTreeNodes.up(mod, expandMacros.expand(input)), mod))), colorize); + private K filterSubst(K term, Module mod) { + if (!(term instanceof KApply kapp)) { + return term; } - - public K abstractTerm(Module mod, K term) { - K filteredSubst = options.noFilterSubstitution ? term : filterSubst(term, mod); - K origNames = options.restoreOriginalNames ? restoreOriginalNameIfPresent(filteredSubst) : filteredSubst; - K collectionsSorted = options.noSortCollections ? origNames : sortCollections(mod, origNames); - //non-determinism is still possible if associative/commutative collection terms start with anonymous vars - K alphaRenamed = options.noAlphaRenaming ? collectionsSorted : alphaRename(collectionsSorted); - K squashedTerm = squashTerms(mod, alphaRenamed); - K flattenedTerm = flattenTerms(mod, squashedTerm); - - return flattenedTerm; + if (kapp.klabel().head().equals(KLabels.ML_AND)) { + return filterConjunction(kapp, mod); + } else if (kapp.klabel().head().equals(KLabels.ML_OR)) { + KLabel unit = KLabel(KLabels.ML_FALSE.name(), kapp.klabel().params().apply(0)); + List disjuncts = Assoc.flatten(kapp.klabel(), kapp.items(), unit); + return disjuncts.stream() + .map(d -> filterConjunction(d, mod)) + .distinct() + .reduce((k1, k2) -> KApply(kapp.klabel(), k1, k2)) + .orElse(KApply(unit)); + } else if (kapp.klabel().head().equals(KLabels.ML_EQUALS)) { + KLabel unit = KLabel(KLabels.ML_TRUE.name(), kapp.klabel().params().apply(0)); + return filterEquality(kapp, multivars(kapp), mod).orElse(KApply(unit)); + } else { + return term; } + } - private Set vars(K term) { - return new HashSet<>(multivars(term)); + private K filterConjunction(K term, Module mod) { + if (!(term instanceof KApply kapp)) { + return term; } - - private Multiset multivars(K term) { - Multiset vars = HashMultiset.create(); - new VisitK() { - @Override - public void apply(KVariable var) { - vars.add(var); - } - }.apply(term); - return vars; + if (kapp.klabel().head().equals(KLabels.ML_AND)) { + KLabel unit = KLabel(KLabels.ML_TRUE.name(), kapp.klabel().params().apply(0)); + List conjuncts = Assoc.flatten(kapp.klabel(), kapp.items(), unit); + return conjuncts.stream() + .map(d -> filterEquality(d, multivars(kapp), mod)) + .filter(Optional::isPresent) + .map(Optional::get) + .reduce((k1, k2) -> KApply(kapp.klabel(), k1, k2)) + .orElse(KApply(unit)); + } else if (kapp.klabel().head().equals(KLabels.ML_EQUALS)) { + KLabel unit = KLabel(KLabels.ML_TRUE.name(), kapp.klabel().params().apply(0)); + return filterEquality(kapp, multivars(kapp), mod).orElse(KApply(unit)); + } else { + return term; } + } - private K filterSubst(K term, Module mod) { - if (!(term instanceof KApply kapp)) { - return term; - } - if (kapp.klabel().head().equals(KLabels.ML_AND)) { - return filterConjunction(kapp, mod); - } else if (kapp.klabel().head().equals(KLabels.ML_OR)) { - KLabel unit = KLabel(KLabels.ML_FALSE.name(), kapp.klabel().params().apply(0)); - List disjuncts = Assoc.flatten(kapp.klabel(), kapp.items(), unit); - return disjuncts.stream() - .map(d -> filterConjunction(d, mod)) - .distinct() - .reduce((k1, k2) -> KApply(kapp.klabel(), k1, k2)) - .orElse(KApply(unit)); - } else if (kapp.klabel().head().equals(KLabels.ML_EQUALS)) { - KLabel unit = KLabel(KLabels.ML_TRUE.name(), kapp.klabel().params().apply(0)); - return filterEquality(kapp, multivars(kapp), mod).orElse(KApply(unit)); - } else { - return term; - } + public Optional filterEquality(K term, Multiset vars, Module mod) { + if (!(term instanceof KApply kapp)) { + return Optional.of(term); } - - private K filterConjunction(K term, Module mod) { - if (!(term instanceof KApply kapp)) { - return term; - } - if (kapp.klabel().head().equals(KLabels.ML_AND)) { - KLabel unit = KLabel(KLabels.ML_TRUE.name(), kapp.klabel().params().apply(0)); - List conjuncts = Assoc.flatten(kapp.klabel(), kapp.items(), unit); - return conjuncts.stream() - .map(d -> filterEquality(d, multivars(kapp), mod)) - .filter(Optional::isPresent) - .map(Optional::get) - .reduce((k1, k2) -> KApply(kapp.klabel(), k1, k2)) - .orElse(KApply(unit)); - } else if (kapp.klabel().head().equals(KLabels.ML_EQUALS)) { - KLabel unit = KLabel(KLabels.ML_TRUE.name(), kapp.klabel().params().apply(0)); - return filterEquality(kapp, multivars(kapp), mod).orElse(KApply(unit)); - } else { - return term; + if (kapp.klabel().head().equals(KLabels.ML_EQUALS)) { + if (!(kapp.items().get(0) instanceof KVariable) + && (!(kapp.items().get(0) instanceof KApply) + || !mod.attributesFor() + .apply(((KApply) kapp.items().get(0)).klabel()) + .contains(Att.FUNCTION()))) { + return Optional.of(term); } - } - - public Optional filterEquality(K term, Multiset vars, Module mod) { - if (!(term instanceof KApply kapp)) { + Set leftVars = vars(kapp.items().get(0)); + if (leftVars.stream().filter(v -> !v.att().contains(Att.ANONYMOUS())).findAny().isPresent()) { return Optional.of(term); } - if (kapp.klabel().head().equals(KLabels.ML_EQUALS)) { - if (!(kapp.items().get(0) instanceof KVariable) && - (!(kapp.items().get(0) instanceof KApply) || - !mod.attributesFor().apply(((KApply)kapp.items().get(0)).klabel()).contains(Att.FUNCTION()))) { + for (KVariable var : leftVars) { + if (vars.count(var) != 1) { return Optional.of(term); } - Set leftVars = vars(kapp.items().get(0)); - if (leftVars.stream().filter(v -> !v.att().contains(Att.ANONYMOUS())).findAny().isPresent()) { - return Optional.of(term); + } + return Optional.empty(); + } else { + return Optional.of(term); + } + } + + private K sortCollections(Module mod, K input) { + Module unparsingModule = + RuleGrammarGenerator.getCombinedGrammar(mod, false, files).getExtensionModule(); + return new TransformK() { + @Override + public K apply(KApply k) { + if (k.klabel() instanceof KVariable) { + return super.apply(k); } - for (KVariable var : leftVars) { - if (vars.count(var) != 1) { - return Optional.of(term); + Att att = unparsingModule.attributesFor().apply(KLabel(k.klabel().name())); + if (att.contains(Att.COMM()) && att.contains(Att.ASSOC()) && att.contains(Att.UNIT())) { + List items = + new ArrayList<>( + Assoc.flatten(k.klabel(), k.klist().items(), KLabel(att.get(Att.UNIT())))); + List> printed = new ArrayList<>(); + for (K item : items) { + String s = unparseInternal(unparsingModule, apply(item), ColorSetting.OFF); + printed.add(Tuple2.apply(s, item)); } + printed.sort(Comparator.comparing(Tuple2::_1, new AlphanumComparator())); + items = printed.stream().map(Tuple2::_2).map(this::apply).collect(Collectors.toList()); + return items.stream() + .reduce((k1, k2) -> KApply(k.klabel(), k1, k2)) + .orElse(KApply(KLabel(att.get(Att.UNIT())))); } - return Optional.empty(); - } else { - return Optional.of(term); + return super.apply(k); } - } - - private K sortCollections(Module mod, K input) { - Module unparsingModule = RuleGrammarGenerator.getCombinedGrammar(mod, false, files).getExtensionModule(); - return new TransformK() { - @Override - public K apply(KApply k) { - if (k.klabel() instanceof KVariable) { - return super.apply(k); - } - Att att = unparsingModule.attributesFor().apply(KLabel(k.klabel().name())); - if (att.contains(Att.COMM()) && att.contains(Att.ASSOC()) && att.contains(Att.UNIT())) { - List items = new ArrayList<>(Assoc.flatten(k.klabel(), k.klist().items(), KLabel(att.get(Att.UNIT())))); - List> printed = new ArrayList<>(); - for (K item : items) { - String s = unparseInternal(unparsingModule, apply(item), ColorSetting.OFF); - printed.add(Tuple2.apply(s, item)); - } - printed.sort(Comparator.comparing(Tuple2::_1, new AlphanumComparator())); - items = printed.stream().map(Tuple2::_2).map(this::apply).collect(Collectors.toList()); - return items.stream().reduce((k1, k2) -> KApply(k.klabel(), k1, k2)).orElse(KApply(KLabel(att.get(Att.UNIT())))); - } - return super.apply(k); - } - }.apply(input); - } - - private K alphaRename(K input) { - return new TransformK() { - final Map renames = new HashMap<>(); - int newCount = 0; - - @Override - public K apply(KVariable k) { - if (k.att().contains(Att.ANONYMOUS())) { - return renames.computeIfAbsent(k, k2 -> KVariable("V" + newCount++, k.att())); - } - return k; - } - }.apply(input); - } - - private K restoreOriginalNameIfPresent(K input) { - return new TransformK() { - @Override - public K apply(KVariable k) { - if (k.att().contains(Att.ORIGINAL_NAME())) { - return KVariable(k.att().get(Att.ORIGINAL_NAME()), k.att()); - } - return k; - } - }.apply(input); - } - - private K squashTerms(Module mod, K input) { - return new TransformK() { - @Override - public K apply(KApply orig) { - String name = orig.klabel().name(); - return options.omittedKLabels.contains(name) ? omitTerm(mod, orig) - : options.tokenizedKLabels.contains(name) ? tokenizeTerm(mod, orig) - : options.tokastKLabels.contains(name) ? toKASTTerm(mod, orig) - : super.apply(orig) ; - } - }.apply(input); - } - - private static K omitTerm(Module mod, KApply kapp) { - Sort finalSort = Sorts.K(); - Option termSort = mod.sortFor().get(kapp.klabel()); - if (! termSort.isEmpty()) { - finalSort = termSort.get(); + }.apply(input); + } + + private K alphaRename(K input) { + return new TransformK() { + final Map renames = new HashMap<>(); + int newCount = 0; + + @Override + public K apply(KVariable k) { + if (k.att().contains(Att.ANONYMOUS())) { + return renames.computeIfAbsent(k, k2 -> KVariable("V" + newCount++, k.att())); } - return KApply(kapp.klabel(), KToken(kapp.klabel().name(), finalSort)); - } - - private K tokenizeTerm(Module mod, KApply kapp) { - Module unparsingModule = RuleGrammarGenerator.getCombinedGrammar(mod, false, files).getExtensionModule(); - String tokenizedTerm = unparseTerm(kapp, unparsingModule, ColorSetting.OFF); - Sort finalSort = Sorts.K(); - Option termSort = mod.sortFor().get(kapp.klabel()); - if (! termSort.isEmpty()) { - finalSort = termSort.get(); + return k; + } + }.apply(input); + } + + private K restoreOriginalNameIfPresent(K input) { + return new TransformK() { + @Override + public K apply(KVariable k) { + if (k.att().contains(Att.ORIGINAL_NAME())) { + return KVariable(k.att().get(Att.ORIGINAL_NAME()), k.att()); } - return KApply(kapp.klabel(), KToken(tokenizedTerm, finalSort)); + return k; + } + }.apply(input); + } + + private K squashTerms(Module mod, K input) { + return new TransformK() { + @Override + public K apply(KApply orig) { + String name = orig.klabel().name(); + return options.omittedKLabels.contains(name) + ? omitTerm(mod, orig) + : options.tokenizedKLabels.contains(name) + ? tokenizeTerm(mod, orig) + : options.tokastKLabels.contains(name) ? toKASTTerm(mod, orig) : super.apply(orig); + } + }.apply(input); + } + + private static K omitTerm(Module mod, KApply kapp) { + Sort finalSort = Sorts.K(); + Option termSort = mod.sortFor().get(kapp.klabel()); + if (!termSort.isEmpty()) { + finalSort = termSort.get(); } - - private static K toKASTTerm(Module mod, KApply kapp) { - String kastTerm = ToKast.apply(kapp); - Sort finalSort = Sorts.K(); - Option termSort = mod.sortFor().get(kapp.klabel()); - if (! termSort.isEmpty()) { - finalSort = termSort.get(); - } - return KToken(kastTerm, finalSort); + return KApply(kapp.klabel(), KToken(kapp.klabel().name(), finalSort)); + } + + private K tokenizeTerm(Module mod, KApply kapp) { + Module unparsingModule = + RuleGrammarGenerator.getCombinedGrammar(mod, false, files).getExtensionModule(); + String tokenizedTerm = unparseTerm(kapp, unparsingModule, ColorSetting.OFF); + Sort finalSort = Sorts.K(); + Option termSort = mod.sortFor().get(kapp.klabel()); + if (!termSort.isEmpty()) { + finalSort = termSort.get(); } - - private K flattenTerms(Module mod, K input) { - return new TransformK() { - @Override - public K apply(KApply orig) { - K newK = super.apply(orig); - if (! (newK instanceof KApply kapp)) { - return newK; - } - String name = orig.klabel().name(); - return options.flattenedKLabels.contains(name) ? flattenTerm(mod, kapp) - : kapp ; - } - }.apply(input); + return KApply(kapp.klabel(), KToken(tokenizedTerm, finalSort)); + } + + private static K toKASTTerm(Module mod, KApply kapp) { + String kastTerm = ToKast.apply(kapp); + Sort finalSort = Sorts.K(); + Option termSort = mod.sortFor().get(kapp.klabel()); + if (!termSort.isEmpty()) { + finalSort = termSort.get(); } - - private static K flattenTerm(Module mod, KApply kapp) { - List items = new ArrayList<>(); - Att att = mod.attributesFor().apply(KLabel(kapp.klabel().name())); - if (att.contains(Att.ASSOC()) && att.contains(Att.UNIT())) { - items = Assoc.flatten(kapp.klabel(), kapp.klist().items(), KLabel(att.get(Att.UNIT()))); - } else { - items = kapp.klist().items(); + return KToken(kastTerm, finalSort); + } + + private K flattenTerms(Module mod, K input) { + return new TransformK() { + @Override + public K apply(KApply orig) { + K newK = super.apply(orig); + if (!(newK instanceof KApply kapp)) { + return newK; } - return KApply(kapp.klabel(), KList(items), kapp.att()); + String name = orig.klabel().name(); + return options.flattenedKLabels.contains(name) ? flattenTerm(mod, kapp) : kapp; + } + }.apply(input); + } + + private static K flattenTerm(Module mod, KApply kapp) { + List items = new ArrayList<>(); + Att att = mod.attributesFor().apply(KLabel(kapp.klabel().name())); + if (att.contains(Att.ASSOC()) && att.contains(Att.UNIT())) { + items = Assoc.flatten(kapp.klabel(), kapp.klist().items(), KLabel(att.get(Att.UNIT()))); + } else { + items = kapp.klist().items(); } + return KApply(kapp.klabel(), KList(items), kapp.att()); + } } diff --git a/kernel/src/main/java/org/kframework/unparser/OutputModes.java b/kernel/src/main/java/org/kframework/unparser/OutputModes.java index 9e3c7a931ae..e6088da0aa5 100644 --- a/kernel/src/main/java/org/kframework/unparser/OutputModes.java +++ b/kernel/src/main/java/org/kframework/unparser/OutputModes.java @@ -3,25 +3,33 @@ /** * Contains functionality generic to all output modes. - * @author dwightguth * + * @author dwightguth */ public enum OutputModes { - PRETTY, PROGRAM, KAST, BINARY, JSON, LATEX, KORE, NONE; + PRETTY, + PROGRAM, + KAST, + BINARY, + JSON, + LATEX, + KORE, + NONE; + + private String extension; - private String extension; - static { - PRETTY.extension = "kpretty"; - PROGRAM.extension = "pgm"; - KAST.extension = "kast"; - BINARY.extension = "kbin"; - JSON.extension = "json"; - LATEX.extension = "tex"; - KORE.extension = "kore"; - NONE.extension = ""; - } + static { + PRETTY.extension = "kpretty"; + PROGRAM.extension = "pgm"; + KAST.extension = "kast"; + BINARY.extension = "kbin"; + JSON.extension = "json"; + LATEX.extension = "tex"; + KORE.extension = "kore"; + NONE.extension = ""; + } - public String ext() { - return extension; - } + public String ext() { + return extension; + } } diff --git a/kernel/src/main/java/org/kframework/unparser/PrintOptions.java b/kernel/src/main/java/org/kframework/unparser/PrintOptions.java index 74c860c80da..ac23ff1289e 100644 --- a/kernel/src/main/java/org/kframework/unparser/PrintOptions.java +++ b/kernel/src/main/java/org/kframework/unparser/PrintOptions.java @@ -2,107 +2,138 @@ package org.kframework.unparser; import com.beust.jcommander.Parameter; -import com.google.inject.Inject; -import org.kframework.utils.options.BaseEnumConverter; -import org.kframework.utils.options.StringListConverter; - import java.util.ArrayList; import java.util.List; import java.util.Map; +import org.kframework.utils.options.BaseEnumConverter; +import org.kframework.utils.options.StringListConverter; public class PrintOptions { - public PrintOptions() { + public PrintOptions() {} + + public PrintOptions(ColorSetting color) { + this.color = color; + } + + public PrintOptions(OutputModes output) { + this.output = output; + } + + @Parameter( + names = "--color", + description = "Use colors in output. Default is on.", + descriptionKey = "mode", + converter = ColorModeConverter.class) + private ColorSetting color; + + public ColorSetting color(boolean ttyStdout, Map env) { + boolean colorize = outputFile == null && ttyStdout; + ColorSetting colors = color; + if (colors == null) { + try { + if (!colorize) { + colors = ColorSetting.OFF; + } else if (Integer.parseInt(env.get("K_COLOR_SUPPORT")) >= 256) { + colors = ColorSetting.EXTENDED; + } else { + colors = ColorSetting.ON; + } + } catch (NumberFormatException e) { + colors = ColorSetting.ON; + } } + return colors; + } - public PrintOptions(ColorSetting color) { - this.color = color; - } + public static class ColorModeConverter extends BaseEnumConverter { - public PrintOptions(OutputModes output) { - this.output = output; + public ColorModeConverter(String optionName) { + super(optionName); } - @Parameter(names = "--color", description = "Use colors in output. Default is on.", descriptionKey = "mode", - converter=ColorModeConverter.class) - private ColorSetting color; - - public ColorSetting color(boolean ttyStdout, Map env) { - boolean colorize = outputFile == null && ttyStdout; - ColorSetting colors = color; - if (colors == null) { - try { - if (!colorize) { - colors = ColorSetting.OFF; - } else if (Integer.parseInt(env.get("K_COLOR_SUPPORT")) >= 256) { - colors = ColorSetting.EXTENDED; - } else { - colors = ColorSetting.ON; - } - } catch (NumberFormatException e) { - colors = ColorSetting.ON; - } - } - return colors; + @Override + public Class enumClass() { + return ColorSetting.class; } - - public static class ColorModeConverter extends BaseEnumConverter { - - public ColorModeConverter(String optionName) { - super(optionName); - } - - @Override - public Class enumClass() { - return ColorSetting.class; - } + } + + @Parameter( + names = "--output-file", + description = "Store output in the file instead of displaying it.", + descriptionKey = "file") + public String outputFile; + + @Parameter( + names = {"--output", "-o"}, + descriptionKey = "mode", + converter = OutputModeConverter.class, + description = + "How to display krun results. is either" + + " [pretty|program|kast|binary|json|latex|kore|none].") + public OutputModes output = OutputModes.PRETTY; + + public static class OutputModeConverter extends BaseEnumConverter { + + public OutputModeConverter(String optionName) { + super(optionName); } - @Parameter(names="--output-file", description="Store output in the file instead of displaying it.", - descriptionKey = "file") - public String outputFile; - - @Parameter(names={"--output", "-o"}, descriptionKey = "mode", converter=OutputModeConverter.class, - description="How to display krun results. is either [pretty|program|kast|binary|json|latex|kore|none].") - public OutputModes output = OutputModes.PRETTY; - - public static class OutputModeConverter extends BaseEnumConverter { - - public OutputModeConverter(String optionName) { - super(optionName); - } - - @Override - public Class enumClass() { - return OutputModes.class; - } + @Override + public Class enumClass() { + return OutputModes.class; } - - @Parameter(names={"--output-omit"}, descriptionKey = "KLabels", listConverter=StringListConverter.class, - description="KLabels to omit from the output.") - public List omittedKLabels = new ArrayList(); - - @Parameter(names={"--output-tokenize"}, descriptionKey = "KLabels", listConverter=StringListConverter.class, - description="KLabels to tokenize underneath (reducing output size).") - public List tokenizedKLabels = new ArrayList(); - - @Parameter(names={"--output-flatten"}, descriptionKey = "KLabels", listConverter=StringListConverter.class, - description="(Assoc) KLabels to flatten into one list.") - public List flattenedKLabels = new ArrayList(); - - @Parameter(names={"--output-tokast"}, descriptionKey = "KLabels", listConverter=StringListConverter.class, - description="KLabels to output as KAST tokens.") - public List tokastKLabels = new ArrayList(); - - @Parameter(names={"--no-alpha-renaming"}, listConverter=StringListConverter.class, description="Do not alpha rename anonymous variables in output.") - public boolean noAlphaRenaming = false; - - @Parameter(names={"--no-substitution-filtering"}, listConverter=StringListConverter.class, description="Do not remove conjuncts of anonymous variables from substitution in output.") - public boolean noFilterSubstitution = false; - - @Parameter(names={"--restore-original-names"}, listConverter=StringListConverter.class, description="Restore original variable names when provided by attributes.") - public boolean restoreOriginalNames = false; - - @Parameter(names={"--no-sort-collections"}, listConverter=StringListConverter.class, description="Do not sort collections before printing (for speed).") - public boolean noSortCollections = false; + } + + @Parameter( + names = {"--output-omit"}, + descriptionKey = "KLabels", + listConverter = StringListConverter.class, + description = "KLabels to omit from the output.") + public List omittedKLabels = new ArrayList(); + + @Parameter( + names = {"--output-tokenize"}, + descriptionKey = "KLabels", + listConverter = StringListConverter.class, + description = "KLabels to tokenize underneath (reducing output size).") + public List tokenizedKLabels = new ArrayList(); + + @Parameter( + names = {"--output-flatten"}, + descriptionKey = "KLabels", + listConverter = StringListConverter.class, + description = "(Assoc) KLabels to flatten into one list.") + public List flattenedKLabels = new ArrayList(); + + @Parameter( + names = {"--output-tokast"}, + descriptionKey = "KLabels", + listConverter = StringListConverter.class, + description = "KLabels to output as KAST tokens.") + public List tokastKLabels = new ArrayList(); + + @Parameter( + names = {"--no-alpha-renaming"}, + listConverter = StringListConverter.class, + description = "Do not alpha rename anonymous variables in output.") + public boolean noAlphaRenaming = false; + + @Parameter( + names = {"--no-substitution-filtering"}, + listConverter = StringListConverter.class, + description = "Do not remove conjuncts of anonymous variables from substitution in output.") + public boolean noFilterSubstitution = false; + + @Parameter( + names = {"--restore-original-names"}, + listConverter = StringListConverter.class, + description = "Restore original variable names when provided by attributes.") + public boolean restoreOriginalNames = false; + + @Parameter( + names = {"--no-sort-collections"}, + listConverter = StringListConverter.class, + description = "Do not sort collections before printing (for speed).") + public boolean noSortCollections = false; } diff --git a/kernel/src/main/java/org/kframework/unparser/ToBinary.java b/kernel/src/main/java/org/kframework/unparser/ToBinary.java index 217a67ae643..7df0dac8e1a 100644 --- a/kernel/src/main/java/org/kframework/unparser/ToBinary.java +++ b/kernel/src/main/java/org/kframework/unparser/ToBinary.java @@ -1,6 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Map; import org.kframework.kore.InjectedKLabel; import org.kframework.kore.K; import org.kframework.kore.KApply; @@ -11,123 +18,115 @@ import org.kframework.parser.binary.BinaryParser; import org.kframework.utils.errorsystem.KEMException; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.IdentityHashMap; -import java.util.Map; - /** - * Writes a KAST term to the KAST binary format. For details of that format, see {@link BinaryParser}. + * Writes a KAST term to the KAST binary format. For details of that format, see {@link + * BinaryParser}. */ public class ToBinary { - public static void apply(OutputStream out, K k) { - try { - DataOutputStream data = new DataOutputStream(out); - //magic - data.writeByte(0x7f); - data.writeBytes("KAST"); - //version - data.writeByte(4); - data.writeByte(0); - data.writeByte(1); - new ToBinary(data).traverse(k); - data.writeByte(BinaryParser.END); - } catch (IOException e) { - throw KEMException.criticalError("Could not write K term to binary", e, k); - } - + public static void apply(OutputStream out, K k) { + try { + DataOutputStream data = new DataOutputStream(out); + // magic + data.writeByte(0x7f); + data.writeBytes("KAST"); + // version + data.writeByte(4); + data.writeByte(0); + data.writeByte(1); + new ToBinary(data).traverse(k); + data.writeByte(BinaryParser.END); + } catch (IOException e) { + throw KEMException.criticalError("Could not write K term to binary", e, k); } - - public static byte[] apply(K k) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - apply(out, k); - return out.toByteArray(); + } + + public static byte[] apply(K k) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + apply(out, k); + return out.toByteArray(); + } + + private final DataOutputStream data; + private final Map interns = new HashMap<>(); + private final Map kInterns = new IdentityHashMap<>(); + private int numTermsWritten; + + private ToBinary(DataOutputStream data) { + this.data = data; + } + + private void traverse(K k) throws IOException { + if (kInterns.containsKey(k)) { + data.writeByte(BinaryParser.BACK_REFERENCE); + data.writeInt(numTermsWritten - kInterns.get(k)); + add_intern(k); + return; } + if (k instanceof KToken tok) { - private final DataOutputStream data; - private final Map interns = new HashMap<>(); - private final Map kInterns = new IdentityHashMap<>(); - private int numTermsWritten; + data.writeByte(BinaryParser.KTOKEN); + add_intern(k); + writeString(tok.s()); + writeString(tok.sort().toString()); - private ToBinary(DataOutputStream data) { - this.data = data; - } + } else if (k instanceof KApply app) { - private void traverse(K k) throws IOException { - if (kInterns.containsKey(k)) { - data.writeByte(BinaryParser.BACK_REFERENCE); - data.writeInt(numTermsWritten - kInterns.get(k)); - add_intern(k); - return; - } - if (k instanceof KToken tok) { - - data.writeByte(BinaryParser.KTOKEN); - add_intern(k); - writeString(tok.s()); - writeString(tok.sort().toString()); - - } else if (k instanceof KApply app) { - - for (K item : app.asIterable()) { - traverse(item); - } - data.writeByte(BinaryParser.KAPPLY); - add_intern(k); - writeString(app.klabel().name()); - data.writeBoolean(app.klabel() instanceof KVariable); - data.writeInt(app.size()); - - } else if (k instanceof KSequence seq) { - - for (K item : seq.asIterable()) { - traverse(item); - } - data.writeByte(BinaryParser.KSEQUENCE); - add_intern(k); - data.writeInt(seq.size()); - - } else if (k instanceof KVariable var) { - - data.writeByte(BinaryParser.KVARIABLE); - add_intern(k); - writeString(var.name()); - - } else if (k instanceof KRewrite rew) { - - traverse(rew.left()); - traverse(rew.right()); - data.writeByte(BinaryParser.KREWRITE); - add_intern(k); - - } else if (k instanceof InjectedKLabel inj) { - - data.writeByte(BinaryParser.INJECTEDKLABEL); - add_intern(k); - writeString(inj.klabel().name()); - data.writeBoolean(inj.klabel() instanceof KVariable); - - } else { - throw KEMException.criticalError("Unimplemented for Binary serialization: ", k); - } - } + for (K item : app.asIterable()) { + traverse(item); + } + data.writeByte(BinaryParser.KAPPLY); + add_intern(k); + writeString(app.klabel().name()); + data.writeBoolean(app.klabel() instanceof KVariable); + data.writeInt(app.size()); - private void add_intern(K k) { - kInterns.put(k, numTermsWritten); - numTermsWritten++; - } + } else if (k instanceof KSequence seq) { + + for (K item : seq.asIterable()) { + traverse(item); + } + data.writeByte(BinaryParser.KSEQUENCE); + add_intern(k); + data.writeInt(seq.size()); - private void writeString(String s) throws IOException { - int idx = interns.getOrDefault(s, interns.size()); - data.writeInt(interns.size() - idx); - if (idx == interns.size()) { - data.writeInt(s.length()); - data.writeChars(s); - interns.put(s, interns.size()); - } + } else if (k instanceof KVariable var) { + + data.writeByte(BinaryParser.KVARIABLE); + add_intern(k); + writeString(var.name()); + + } else if (k instanceof KRewrite rew) { + + traverse(rew.left()); + traverse(rew.right()); + data.writeByte(BinaryParser.KREWRITE); + add_intern(k); + + } else if (k instanceof InjectedKLabel inj) { + + data.writeByte(BinaryParser.INJECTEDKLABEL); + add_intern(k); + writeString(inj.klabel().name()); + data.writeBoolean(inj.klabel() instanceof KVariable); + + } else { + throw KEMException.criticalError("Unimplemented for Binary serialization: ", k); + } + } + + private void add_intern(K k) { + kInterns.put(k, numTermsWritten); + numTermsWritten++; + } + + private void writeString(String s) throws IOException { + int idx = interns.getOrDefault(s, interns.size()); + data.writeInt(interns.size() - idx); + if (idx == interns.size()) { + data.writeInt(s.length()); + data.writeChars(s); + interns.put(s, interns.size()); } + } } diff --git a/kernel/src/main/java/org/kframework/unparser/ToJson.java b/kernel/src/main/java/org/kframework/unparser/ToJson.java index 86fa96bd331..2b8f12222e7 100644 --- a/kernel/src/main/java/org/kframework/unparser/ToJson.java +++ b/kernel/src/main/java/org/kframework/unparser/ToJson.java @@ -1,17 +1,24 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import static org.kframework.Collections.*; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collections; +import javax.json.*; import org.kframework.attributes.Att; -import org.kframework.attributes.Att.Key; import org.kframework.attributes.Location; import org.kframework.attributes.Source; import org.kframework.definition.Bubble; -import org.kframework.definition.Context; import org.kframework.definition.Configuration; +import org.kframework.definition.Context; import org.kframework.definition.Definition; -import org.kframework.definition.NonTerminal; -import org.kframework.definition.Module; import org.kframework.definition.FlatModule; +import org.kframework.definition.Module; +import org.kframework.definition.NonTerminal; import org.kframework.definition.Production; import org.kframework.definition.ProductionItem; import org.kframework.definition.RegexTerminal; @@ -37,467 +44,455 @@ import org.kframework.kore.Sort; import org.kframework.parser.json.JsonParser; import org.kframework.utils.errorsystem.KEMException; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.DataOutputStream; -import java.io.ByteArrayOutputStream; -import java.util.Collections; - -import javax.json.*; - import scala.Option; import scala.Tuple2; import scala.collection.JavaConverters; import scala.collection.Set; -import static org.kframework.Collections.*; - -/** - * Writes a KAST term to the KAST Json format. - */ +/** Writes a KAST term to the KAST Json format. */ public class ToJson { - public static final int version = 3; + public static final int version = 3; -/////////////////////////////// -// ToJson Definition Objects // -/////////////////////////////// + /////////////////////////////// + // ToJson Definition Objects // + /////////////////////////////// - private static final JsonBuilderFactory factory = Json.createBuilderFactory(Collections.emptyMap()); + private static final JsonBuilderFactory factory = + Json.createBuilderFactory(Collections.emptyMap()); - public static byte[] apply(Definition def) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - DataOutputStream data = new DataOutputStream(out); - JsonWriter jsonWriter = Json.createWriter(data); + public static byte[] apply(Definition def) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + DataOutputStream data = new DataOutputStream(out); + JsonWriter jsonWriter = Json.createWriter(data); - JsonObjectBuilder term = factory.createObjectBuilder(); - term.add("format", "KAST"); - term.add("version", version); - term.add("term", toJson(def)); + JsonObjectBuilder term = factory.createObjectBuilder(); + term.add("format", "KAST"); + term.add("version", version); + term.add("term", toJson(def)); - jsonWriter.write(term.build()); - jsonWriter.close(); - data.close(); - } catch (IOException e) { - throw KEMException.criticalError("Could not write Definition to Json", e); - } - return out.toByteArray(); + jsonWriter.write(term.build()); + jsonWriter.close(); + data.close(); + } catch (IOException e) { + throw KEMException.criticalError("Could not write Definition to Json", e); } - - public static byte[] apply(java.util.Set mods, String mainSpecModule) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - DataOutputStream data = new DataOutputStream(out); - JsonWriter jsonWriter = Json.createWriter(data); - - JsonObjectBuilder term = factory.createObjectBuilder(); - term.add("format", "KAST"); - term.add("version", version); - JsonObjectBuilder jmodlist = factory.createObjectBuilder(); - - jmodlist.add("node", JsonParser.KFLATMODULELIST); - jmodlist.add("mainModule", mainSpecModule); - - JsonArrayBuilder jmods = factory.createArrayBuilder(); - for (Module m : mods) { - jmods.add(toJson(m)); - } - jmodlist.add("term", jmods); - term.add("term", jmodlist); - - jsonWriter.write(term.build()); - jsonWriter.close(); - data.close(); - } catch (IOException e) { - throw KEMException.criticalError("Could not write Module to Json", e); - } - return out.toByteArray(); + return out.toByteArray(); + } + + public static byte[] apply(java.util.Set mods, String mainSpecModule) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + DataOutputStream data = new DataOutputStream(out); + JsonWriter jsonWriter = Json.createWriter(data); + + JsonObjectBuilder term = factory.createObjectBuilder(); + term.add("format", "KAST"); + term.add("version", version); + JsonObjectBuilder jmodlist = factory.createObjectBuilder(); + + jmodlist.add("node", JsonParser.KFLATMODULELIST); + jmodlist.add("mainModule", mainSpecModule); + + JsonArrayBuilder jmods = factory.createArrayBuilder(); + for (Module m : mods) { + jmods.add(toJson(m)); + } + jmodlist.add("term", jmods); + term.add("term", jmodlist); + + jsonWriter.write(term.build()); + jsonWriter.close(); + data.close(); + } catch (IOException e) { + throw KEMException.criticalError("Could not write Module to Json", e); } + return out.toByteArray(); + } - public static JsonStructure toJson(Definition def) { - JsonObjectBuilder jdef = factory.createObjectBuilder(); - - JsonArrayBuilder mods = factory.createArrayBuilder(); - for (Module m : JavaConverters.setAsJavaSet(def.modules())) { - mods.add(toJson(m)); - } - - jdef.add("node", JsonParser.KDEFINITION); - jdef.add("mainModule", def.mainModule().name()); - jdef.add("modules", mods); - jdef.add("att", toJson(def.att())); + public static JsonStructure toJson(Definition def) { + JsonObjectBuilder jdef = factory.createObjectBuilder(); - return jdef.build(); + JsonArrayBuilder mods = factory.createArrayBuilder(); + for (Module m : JavaConverters.setAsJavaSet(def.modules())) { + mods.add(toJson(m)); } - public static JsonStructure toJson(Att att) { - // Emit user groups as group(_) to prevent conflicts between user groups and internals - att = att.withUserGroupsAsGroupAtt(); - - JsonObjectBuilder jatt = factory.createObjectBuilder(); - jatt.add("node", JsonParser.KATT); - - JsonObjectBuilder jattKeys = factory.createObjectBuilder(); - for (Tuple2 attKeyPair : JavaConverters.seqAsJavaList(att.att().keys().toSeq())) { - if (attKeyPair._1().key().equals(Location.class.getName())) { - JsonArrayBuilder locarr = factory.createArrayBuilder(); - Location loc = att.get(Location.class); - locarr.add(loc.startLine()); - locarr.add(loc.startColumn()); - locarr.add(loc.endLine()); - locarr.add(loc.endColumn()); - jattKeys.add(attKeyPair._1().key(), locarr.build()); - } else if (attKeyPair._1().key().equals(Source.class.getName())){ - jattKeys.add(attKeyPair._1().key(), att.get(Source.class).source()); - } else if (attKeyPair._1().key().equals(Production.class.getName())){ - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Production.class))); - } else if (attKeyPair._1().key().equals(Sort.class.getName())){ - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Sort.class))); - } else if (attKeyPair._1().equals(Att.BRACKET_LABEL())) { - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.BRACKET_LABEL(), KLabel.class))); - } else if (attKeyPair._1().equals(Att.PREDICATE())) { - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.PREDICATE(), Sort.class))); - } else if (attKeyPair._1().equals(Att.CELL_OPT_ABSENT())) { - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.CELL_OPT_ABSENT(), Sort.class))); - } else if (attKeyPair._1().equals(Att.CELL_FRAGMENT())) { - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.CELL_FRAGMENT(), Sort.class))); - } else if (attKeyPair._1().equals(Att.SORT_PARAMS())) { - jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.SORT_PARAMS(), Sort.class))); - } else - jattKeys.add(attKeyPair._1().key(), att.att().get(attKeyPair).get().toString()); - } - jatt.add("att", jattKeys.build()); - - return jatt.build(); + jdef.add("node", JsonParser.KDEFINITION); + jdef.add("mainModule", def.mainModule().name()); + jdef.add("modules", mods); + jdef.add("att", toJson(def.att())); + + return jdef.build(); + } + + public static JsonStructure toJson(Att att) { + // Emit user groups as group(_) to prevent conflicts between user groups and internals + att = att.withUserGroupsAsGroupAtt(); + + JsonObjectBuilder jatt = factory.createObjectBuilder(); + jatt.add("node", JsonParser.KATT); + + JsonObjectBuilder jattKeys = factory.createObjectBuilder(); + for (Tuple2 attKeyPair : + JavaConverters.seqAsJavaList(att.att().keys().toSeq())) { + if (attKeyPair._1().key().equals(Location.class.getName())) { + JsonArrayBuilder locarr = factory.createArrayBuilder(); + Location loc = att.get(Location.class); + locarr.add(loc.startLine()); + locarr.add(loc.startColumn()); + locarr.add(loc.endLine()); + locarr.add(loc.endColumn()); + jattKeys.add(attKeyPair._1().key(), locarr.build()); + } else if (attKeyPair._1().key().equals(Source.class.getName())) { + jattKeys.add(attKeyPair._1().key(), att.get(Source.class).source()); + } else if (attKeyPair._1().key().equals(Production.class.getName())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Production.class))); + } else if (attKeyPair._1().key().equals(Sort.class.getName())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Sort.class))); + } else if (attKeyPair._1().equals(Att.BRACKET_LABEL())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.BRACKET_LABEL(), KLabel.class))); + } else if (attKeyPair._1().equals(Att.PREDICATE())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.PREDICATE(), Sort.class))); + } else if (attKeyPair._1().equals(Att.CELL_OPT_ABSENT())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.CELL_OPT_ABSENT(), Sort.class))); + } else if (attKeyPair._1().equals(Att.CELL_FRAGMENT())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.CELL_FRAGMENT(), Sort.class))); + } else if (attKeyPair._1().equals(Att.SORT_PARAMS())) { + jattKeys.add(attKeyPair._1().key(), toJson(att.get(Att.SORT_PARAMS(), Sort.class))); + } else jattKeys.add(attKeyPair._1().key(), att.att().get(attKeyPair).get().toString()); } - -/////////////////////////// -// ToJson Module Objects // -/////////////////////////// - - public static JsonStructure toJson(Module mod) { - return toJson(mod.flattened()); + jatt.add("att", jattKeys.build()); + + return jatt.build(); + } + + /////////////////////////// + // ToJson Module Objects // + /////////////////////////// + + public static JsonStructure toJson(Module mod) { + return toJson(mod.flattened()); + } + + public static JsonStructure toJson(FlatModule mod) { + JsonObjectBuilder jmod = factory.createObjectBuilder(); + + jmod.add("node", JsonParser.KFLATMODULE); + + JsonArrayBuilder imports = factory.createArrayBuilder(); + stream(mod.imports()) + .forEach( + i -> { + JsonObjectBuilder jimp = factory.createObjectBuilder(); + jimp.add("node", JsonParser.KIMPORT); + jimp.add("name", i.name()); + jimp.add("isPublic", i.isPublic()); + imports.add(jimp.build()); + }); + + JsonArrayBuilder sentences = factory.createArrayBuilder(); + mod.localSentences().foreach(s -> sentences.add(toJson(s))); + + jmod.add("name", mod.name()); + jmod.add("imports", imports); + jmod.add("localSentences", sentences); + jmod.add("att", toJson(mod.att())); + + return jmod.build(); + } + + ///////////////////////////// + // ToJSon Sentence Objects // + ///////////////////////////// + + public static JsonStructure toJson(Sentence sen) { + if (sen instanceof Context) return toJson((Context) sen); + if (sen instanceof RuleOrClaim) return toJson((RuleOrClaim) sen); + if (sen instanceof SyntaxPriority) return toJson((SyntaxPriority) sen); + if (sen instanceof SyntaxAssociativity) return toJson((SyntaxAssociativity) sen); + if (sen instanceof Configuration) return toJson((Configuration) sen); + if (sen instanceof Bubble) return toJson((Bubble) sen); + if (sen instanceof SyntaxSort) return toJson((SyntaxSort) sen); + if (sen instanceof SortSynonym) return toJson((SortSynonym) sen); + if (sen instanceof SyntaxLexical) return toJson((SyntaxLexical) sen); + if (sen instanceof Production) return toJson((Production) sen); + + JsonObjectBuilder jsen = factory.createObjectBuilder(); + jsen.add("node", "badsentence"); + return jsen.build(); + } + + public static JsonStructure toJson(Context con) { + JsonObjectBuilder jcon = factory.createObjectBuilder(); + + jcon.add("node", JsonParser.KCONTEXT); + jcon.add("body", toJson(con.body())); + jcon.add("requires", toJson(con.requires())); + jcon.add("att", toJson(con.att())); + + return jcon.build(); + } + + public static JsonStructure toJson(RuleOrClaim rule) { + JsonObjectBuilder jrule = factory.createObjectBuilder(); + + jrule.add("node", rule instanceof Rule ? JsonParser.KRULE : JsonParser.KCLAIM); + jrule.add("body", toJson(rule.body())); + jrule.add("requires", toJson(rule.requires())); + jrule.add("ensures", toJson(rule.ensures())); + jrule.add("att", toJson(rule.att())); + + return jrule.build(); + } + + public static JsonStructure toJson(SyntaxPriority syn) { + JsonObjectBuilder jsyn = factory.createObjectBuilder(); + + jsyn.add("node", JsonParser.KSYNTAXPRIORITY); + + JsonArrayBuilder priArray = factory.createArrayBuilder(); + for (Set pri : JavaConverters.seqAsJavaList(syn.priorities())) { + JsonArrayBuilder tagArray = factory.createArrayBuilder(); + pri.foreach(t -> tagArray.add(t.name())); + priArray.add(tagArray); } + jsyn.add("priorities", priArray); - public static JsonStructure toJson(FlatModule mod) { - JsonObjectBuilder jmod = factory.createObjectBuilder(); + jsyn.add("att", toJson(syn.att())); - jmod.add("node", JsonParser.KFLATMODULE); + return jsyn.build(); + } - JsonArrayBuilder imports = factory.createArrayBuilder(); - stream(mod.imports()).forEach(i -> { - JsonObjectBuilder jimp = factory.createObjectBuilder(); - jimp.add("node", JsonParser.KIMPORT); - jimp.add("name", i.name()); - jimp.add("isPublic", i.isPublic()); - imports.add(jimp.build()); - }); + public static JsonStructure toJson(SyntaxAssociativity syn) { + JsonObjectBuilder jsyn = factory.createObjectBuilder(); - JsonArrayBuilder sentences = factory.createArrayBuilder(); - mod.localSentences().foreach(s -> sentences.add(toJson(s))); + jsyn.add("node", JsonParser.KSYNTAXASSOCIATIVITY); + jsyn.add("assoc", syn.assoc().toString()); - jmod.add("name", mod.name()); - jmod.add("imports", imports); - jmod.add("localSentences", sentences); - jmod.add("att", toJson(mod.att())); + JsonArrayBuilder tagArray = factory.createArrayBuilder(); + syn.tags().foreach(t -> tagArray.add(t.name())); + jsyn.add("tags", tagArray); - return jmod.build(); - } + jsyn.add("att", toJson(syn.att())); -///////////////////////////// -// ToJSon Sentence Objects // -///////////////////////////// - - public static JsonStructure toJson(Sentence sen) { - if (sen instanceof Context) return toJson((Context) sen); - if (sen instanceof RuleOrClaim) return toJson((RuleOrClaim) sen); - if (sen instanceof SyntaxPriority) return toJson((SyntaxPriority) sen); - if (sen instanceof SyntaxAssociativity) return toJson((SyntaxAssociativity) sen); - if (sen instanceof Configuration) return toJson((Configuration) sen); - if (sen instanceof Bubble) return toJson((Bubble) sen); - if (sen instanceof SyntaxSort) return toJson((SyntaxSort) sen); - if (sen instanceof SortSynonym) return toJson((SortSynonym) sen); - if (sen instanceof SyntaxLexical) return toJson((SyntaxLexical) sen); - if (sen instanceof Production) return toJson((Production) sen); - - JsonObjectBuilder jsen = factory.createObjectBuilder(); - jsen.add("node", "badsentence"); - return jsen.build(); - } - - public static JsonStructure toJson(Context con) { - JsonObjectBuilder jcon = factory.createObjectBuilder(); - - jcon.add("node", JsonParser.KCONTEXT); - jcon.add("body", toJson(con.body())); - jcon.add("requires", toJson(con.requires())); - jcon.add("att", toJson(con.att())); - - return jcon.build(); - } - - public static JsonStructure toJson(RuleOrClaim rule) { - JsonObjectBuilder jrule = factory.createObjectBuilder(); + return jsyn.build(); + } - jrule.add("node", rule instanceof Rule ? JsonParser.KRULE : JsonParser.KCLAIM); - jrule.add("body", toJson(rule.body())); - jrule.add("requires", toJson(rule.requires())); - jrule.add("ensures", toJson(rule.ensures())); - jrule.add("att", toJson(rule.att())); - - return jrule.build(); - } + public static JsonStructure toJson(Configuration con) { + JsonObjectBuilder jcon = factory.createObjectBuilder(); - public static JsonStructure toJson(SyntaxPriority syn) { - JsonObjectBuilder jsyn = factory.createObjectBuilder(); + jcon.add("node", JsonParser.KCONFIGURATION); + jcon.add("body", toJson(con.body())); + jcon.add("ensures", toJson(con.ensures())); + jcon.add("att", toJson(con.att())); - jsyn.add("node", JsonParser.KSYNTAXPRIORITY); + return jcon.build(); + } - JsonArrayBuilder priArray = factory.createArrayBuilder(); - for (Set pri : JavaConverters.seqAsJavaList(syn.priorities())) { - JsonArrayBuilder tagArray = factory.createArrayBuilder(); - pri.foreach(t -> tagArray.add(t.name())); - priArray.add(tagArray); - } - jsyn.add("priorities", priArray); + public static JsonStructure toJson(Bubble bub) { + JsonObjectBuilder jbub = factory.createObjectBuilder(); - jsyn.add("att", toJson(syn.att())); + jbub.add("node", JsonParser.KBUBBLE); + jbub.add("sentenceType", bub.sentenceType()); + jbub.add("contents", bub.contents()); + jbub.add("att", toJson(bub.att())); - return jsyn.build(); - } - - public static JsonStructure toJson(SyntaxAssociativity syn) { - JsonObjectBuilder jsyn = factory.createObjectBuilder(); - - jsyn.add("node", JsonParser.KSYNTAXASSOCIATIVITY); - jsyn.add("assoc", syn.assoc().toString()); - - JsonArrayBuilder tagArray = factory.createArrayBuilder(); - syn.tags().foreach(t -> tagArray.add(t.name())); - jsyn.add("tags", tagArray); - - jsyn.add("att", toJson(syn.att())); - - return jsyn.build(); - } + return jbub.build(); + } - public static JsonStructure toJson(Configuration con) { - JsonObjectBuilder jcon = factory.createObjectBuilder(); + public static JsonStructure toJson(SyntaxSort syn) { + JsonObjectBuilder jsyn = factory.createObjectBuilder(); - jcon.add("node", JsonParser.KCONFIGURATION); - jcon.add("body", toJson(con.body())); - jcon.add("ensures", toJson(con.ensures())); - jcon.add("att", toJson(con.att())); + jsyn.add("node", JsonParser.KSYNTAXSORT); + jsyn.add("sort", toJson(syn.sort())); - return jcon.build(); - } + JsonArrayBuilder params = factory.createArrayBuilder(); + JavaConverters.seqAsJavaList(syn.params()).forEach(p -> params.add(toJson(p))); + jsyn.add("params", params.build()); - public static JsonStructure toJson(Bubble bub) { - JsonObjectBuilder jbub = factory.createObjectBuilder(); + jsyn.add("att", toJson(syn.att())); - jbub.add("node", JsonParser.KBUBBLE); - jbub.add("sentenceType", bub.sentenceType()); - jbub.add("contents", bub.contents()); - jbub.add("att", toJson(bub.att())); + return jsyn.build(); + } - return jbub.build(); - } + public static JsonStructure toJson(SortSynonym syn) { + JsonObjectBuilder jsyn = factory.createObjectBuilder(); - public static JsonStructure toJson(SyntaxSort syn) { - JsonObjectBuilder jsyn = factory.createObjectBuilder(); + jsyn.add("node", JsonParser.KSORTSYNONYM); + jsyn.add("newSort", toJson(syn.newSort())); + jsyn.add("oldSort", toJson(syn.oldSort())); + jsyn.add("att", toJson(syn.att())); - jsyn.add("node", JsonParser.KSYNTAXSORT); - jsyn.add("sort", toJson(syn.sort())); + return jsyn.build(); + } - JsonArrayBuilder params = factory.createArrayBuilder(); - JavaConverters.seqAsJavaList(syn.params()).forEach(p -> params.add(toJson(p))); - jsyn.add("params", params.build()); + public static JsonStructure toJson(SyntaxLexical syn) { + JsonObjectBuilder jsyn = factory.createObjectBuilder(); - jsyn.add("att", toJson(syn.att())); + jsyn.add("node", JsonParser.KSYNTAXLEXICAL); + jsyn.add("name", syn.name()); + jsyn.add("regex", syn.regex()); + jsyn.add("att", toJson(syn.att())); - return jsyn.build(); - } + return jsyn.build(); + } - public static JsonStructure toJson(SortSynonym syn) { - JsonObjectBuilder jsyn = factory.createObjectBuilder(); + public static JsonStructure toJson(Production pro) { + JsonObjectBuilder jpro = factory.createObjectBuilder(); - jsyn.add("node", JsonParser.KSORTSYNONYM); - jsyn.add("newSort", toJson(syn.newSort())); - jsyn.add("oldSort", toJson(syn.oldSort())); - jsyn.add("att", toJson(syn.att())); + jpro.add("node", JsonParser.KPRODUCTION); - return jsyn.build(); + Option klabel = pro.klabel(); + if (!klabel.isEmpty()) { + jpro.add("klabel", toJson(klabel.get())); } - public static JsonStructure toJson(SyntaxLexical syn) { - JsonObjectBuilder jsyn = factory.createObjectBuilder(); - - jsyn.add("node", JsonParser.KSYNTAXLEXICAL); - jsyn.add("name", syn.name()); - jsyn.add("regex", syn.regex()); - jsyn.add("att", toJson(syn.att())); - - return jsyn.build(); + JsonArrayBuilder productionItems = factory.createArrayBuilder(); + JavaConverters.seqAsJavaList(pro.items()).forEach(p -> productionItems.add(toJson(p))); + jpro.add("productionItems", productionItems.build()); + + JsonArrayBuilder params = factory.createArrayBuilder(); + JavaConverters.seqAsJavaList(pro.params()).forEach(p -> params.add(toJson(p))); + jpro.add("params", params.build()); + + jpro.add("sort", toJson(pro.sort())); + jpro.add("att", toJson(pro.att())); + + return jpro.build(); + } + + public static JsonObject toJson(ProductionItem prod) { + JsonObjectBuilder jsonProduction = factory.createObjectBuilder(); + + if (prod instanceof NonTerminal t) { + jsonProduction.add("node", JsonParser.KNONTERMINAL); + jsonProduction.add("sort", toJson(t.sort())); + Option name = t.name(); + if (!name.isEmpty()) jsonProduction.add("name", name.get()); + } else if (prod instanceof RegexTerminal t) { + jsonProduction.add("node", JsonParser.KREGEXTERMINAL); + jsonProduction.add("precedeRegex", t.precedeRegex()); + jsonProduction.add("regex", t.regex()); + jsonProduction.add("followRegex", t.followRegex()); + } else if (prod instanceof Terminal t) { + jsonProduction.add("node", JsonParser.KTERMINAL); + jsonProduction.add("value", t.value()); } - public static JsonStructure toJson(Production pro) { - JsonObjectBuilder jpro = factory.createObjectBuilder(); + return jsonProduction.build(); + } - jpro.add("node", JsonParser.KPRODUCTION); + public static JsonStructure toJson(Sort sort) { + JsonObjectBuilder jsort = factory.createObjectBuilder(); - Option klabel = pro.klabel(); - if (! klabel.isEmpty()) { - jpro.add("klabel", toJson(klabel.get())); - } + jsort.add("node", JsonParser.KSORT); + // store sort and its parameters as a flat string + jsort.add("name", sort.toString()); - JsonArrayBuilder productionItems = factory.createArrayBuilder(); - JavaConverters.seqAsJavaList(pro.items()).forEach(p -> productionItems.add(toJson(p))); - jpro.add("productionItems", productionItems.build()); + return jsort.build(); + } - JsonArrayBuilder params = factory.createArrayBuilder(); - JavaConverters.seqAsJavaList(pro.params()).forEach(p -> params.add(toJson(p))); - jpro.add("params", params.build()); + ////////////////////// + // ToJson K Objects // + ////////////////////// - jpro.add("sort", toJson(pro.sort())); - jpro.add("att", toJson(pro.att())); + public static void apply(OutputStream out, K k) { + try { + DataOutputStream data = new DataOutputStream(out); + JsonWriter jsonWriter = Json.createWriter(data); - return jpro.build(); - } + JsonObjectBuilder kterm = factory.createObjectBuilder(); + kterm.add("format", "KAST"); + kterm.add("version", version); + kterm.add("term", toJson(k)); - public static JsonObject toJson(ProductionItem prod) { - JsonObjectBuilder jsonProduction = factory.createObjectBuilder(); - - if (prod instanceof NonTerminal t) { - jsonProduction.add("node", JsonParser.KNONTERMINAL); - jsonProduction.add("sort", toJson(t.sort())); - Option name = t.name(); - if (! name.isEmpty()) - jsonProduction.add("name", name.get()); - } else if (prod instanceof RegexTerminal t) { - jsonProduction.add("node", JsonParser.KREGEXTERMINAL); - jsonProduction.add("precedeRegex", t.precedeRegex()); - jsonProduction.add("regex", t.regex()); - jsonProduction.add("followRegex", t.followRegex()); - } else if (prod instanceof Terminal t) { - jsonProduction.add("node", JsonParser.KTERMINAL); - jsonProduction.add("value", t.value()); - } - - return jsonProduction.build(); + jsonWriter.write(kterm.build()); + jsonWriter.close(); + data.close(); + } catch (IOException e) { + throw KEMException.criticalError("Could not write K term to Json", e, k); } + } - public static JsonStructure toJson(Sort sort) { - JsonObjectBuilder jsort = factory.createObjectBuilder(); + public static byte[] apply(K k) { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + apply(out, k); + return out.toByteArray(); + } - jsort.add("node", JsonParser.KSORT); - // store sort and its parameters as a flat string - jsort.add("name", sort.toString()); + public static JsonStructure toJson(K k) { + JsonObjectBuilder knode = factory.createObjectBuilder(); + if (k instanceof KToken tok) { - return jsort.build(); - } + knode.add("node", JsonParser.KTOKEN); + knode.add("sort", toJson(tok.sort())); + knode.add("token", tok.s()); -////////////////////// -// ToJson K Objects // -////////////////////// - - public static void apply(OutputStream out, K k) { - try { - DataOutputStream data = new DataOutputStream(out); - JsonWriter jsonWriter = Json.createWriter(data); - - JsonObjectBuilder kterm = factory.createObjectBuilder(); - kterm.add("format", "KAST"); - kterm.add("version", version); - kterm.add("term", toJson(k)); - - jsonWriter.write(kterm.build()); - jsonWriter.close(); - data.close(); - } catch (IOException e) { - throw KEMException.criticalError("Could not write K term to Json", e, k); - } - } + } else if (k instanceof KApply app) { - public static byte[] apply(K k) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - apply(out, k); - return out.toByteArray(); - } - - public static JsonStructure toJson(K k) { - JsonObjectBuilder knode = factory.createObjectBuilder(); - if (k instanceof KToken tok) { - - knode.add("node", JsonParser.KTOKEN); - knode.add("sort", toJson(tok.sort())); - knode.add("token", tok.s()); - - } else if (k instanceof KApply app) { + knode.add("node", JsonParser.KAPPLY); + knode.add("label", toJson(((KApply) k).klabel())); - knode.add("node", JsonParser.KAPPLY); - knode.add("label", toJson(((KApply) k).klabel())); + JsonArrayBuilder args = factory.createArrayBuilder(); + for (K item : app.klist().asIterable()) { + args.add(toJson(item)); + } - JsonArrayBuilder args = factory.createArrayBuilder(); - for (K item : app.klist().asIterable()) { - args.add(toJson(item)); - } + knode.add("arity", app.klist().size()); + knode.add("args", args.build()); - knode.add("arity", app.klist().size()); - knode.add("args", args.build()); + } else if (k instanceof KSequence seq) { - } else if (k instanceof KSequence seq) { + knode.add("node", JsonParser.KSEQUENCE); - knode.add("node", JsonParser.KSEQUENCE); + JsonArrayBuilder items = factory.createArrayBuilder(); + for (K item : seq.asIterable()) { + items.add(toJson(item)); + } - JsonArrayBuilder items = factory.createArrayBuilder(); - for (K item : seq.asIterable()) { - items.add(toJson(item)); - } + knode.add("arity", seq.size()); + knode.add("items", items.build()); - knode.add("arity", seq.size()); - knode.add("items", items.build()); + } else if (k instanceof KVariable var) { - } else if (k instanceof KVariable var) { + knode.add("node", JsonParser.KVARIABLE); + knode.add("name", var.name()); + if (k.att().contains(Sort.class)) { + knode.add("sort", toJson(k.att().get(Sort.class))); + } - knode.add("node", JsonParser.KVARIABLE); - knode.add("name", var.name()); - if (k.att().contains(Sort.class)) { - knode.add("sort", toJson(k.att().get(Sort.class))); - } + } else if (k instanceof KRewrite rew) { - } else if (k instanceof KRewrite rew) { + knode.add("node", JsonParser.KREWRITE); + knode.add("lhs", toJson(rew.left())); + knode.add("rhs", toJson(rew.right())); - knode.add("node", JsonParser.KREWRITE); - knode.add("lhs", toJson(rew.left())); - knode.add("rhs", toJson(rew.right())); + } else if (k instanceof KAs alias) { - } else if (k instanceof KAs alias) { + knode.add("node", JsonParser.KAS); + knode.add("pattern", toJson(alias.pattern())); + knode.add("alias", toJson(alias.alias())); - knode.add("node", JsonParser.KAS); - knode.add("pattern", toJson(alias.pattern())); - knode.add("alias", toJson(alias.alias())); + } else if (k instanceof InjectedKLabel inj) { - } else if (k instanceof InjectedKLabel inj) { - - knode.add("node", JsonParser.INJECTEDKLABEL); - knode.add("label", toJson(inj.klabel())); - - } else { - throw KEMException.criticalError("Unimplemented for JSON serialization: ", k); - } - return knode.build(); - } + knode.add("node", JsonParser.INJECTEDKLABEL); + knode.add("label", toJson(inj.klabel())); - public static JsonStructure toJson(KLabel kl) { - JsonObjectBuilder jkl = factory.createObjectBuilder(); - jkl.add("node", "KLabel"); - jkl.add("name", kl.name()); - JsonArrayBuilder params = factory.createArrayBuilder(); - for (Sort s : mutable(kl.params())) - params.add(toJson(s)); - jkl.add("params", params.build()); - return jkl.build(); + } else { + throw KEMException.criticalError("Unimplemented for JSON serialization: ", k); } + return knode.build(); + } + + public static JsonStructure toJson(KLabel kl) { + JsonObjectBuilder jkl = factory.createObjectBuilder(); + jkl.add("node", "KLabel"); + jkl.add("name", kl.name()); + JsonArrayBuilder params = factory.createArrayBuilder(); + for (Sort s : mutable(kl.params())) params.add(toJson(s)); + jkl.add("params", params.build()); + return jkl.build(); + } } diff --git a/kernel/src/main/java/org/kframework/unparser/ToLatex.java b/kernel/src/main/java/org/kframework/unparser/ToLatex.java index 2b99a1ca0e0..161c72e7d35 100644 --- a/kernel/src/main/java/org/kframework/unparser/ToLatex.java +++ b/kernel/src/main/java/org/kframework/unparser/ToLatex.java @@ -1,6 +1,13 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Optional; +import java.util.regex.Pattern; import org.kframework.attributes.Att; import org.kframework.kore.InjectedKLabel; import org.kframework.kore.K; @@ -10,129 +17,121 @@ import org.kframework.kore.KSequence; import org.kframework.kore.KToken; import org.kframework.kore.KVariable; -import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.StringUtil; +import org.kframework.utils.errorsystem.KEMException; -import java.io.IOException; -import java.io.DataOutputStream; -import java.io.ByteArrayOutputStream; -import java.nio.charset.StandardCharsets; - -import java.util.Arrays; -import java.util.Optional; -import java.util.regex.Pattern; - -/** - * Writes a KAST term to the LaTeX format. - */ +/** Writes a KAST term to the LaTeX format. */ public class ToLatex { - public static byte[] apply(K k) { - try { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - apply(new DataOutputStream(out), k); - return out.toByteArray(); - } catch (IOException e) { - throw KEMException.criticalError("Could not write K term to LaTeX", e, k); - } - } - - private static String[] asciiReadableEncodingLatexCalc() { - String[] latexEncoder = Arrays.copyOf(StringUtil.asciiReadableEncodingDefault, StringUtil.asciiReadableEncodingDefault.length); - latexEncoder[0x30] = "Zero"; - latexEncoder[0x31] = "I"; - latexEncoder[0x32] = "II"; - latexEncoder[0x33] = "III"; - latexEncoder[0x34] = "IV"; - latexEncoder[0x35] = "V"; - latexEncoder[0x36] = "VI"; - latexEncoder[0x37] = "VII"; - latexEncoder[0x38] = "VIII"; - latexEncoder[0x39] = "IX"; - latexEncoder[0x7a] = "ActZ"; - return latexEncoder; - } - - public static final Pattern identChar = Pattern.compile("[A-Za-y]"); - public static String[] asciiReadableEncodingLatex = asciiReadableEncodingLatexCalc(); - - public static String latexedKLabel(String orig) { - StringBuilder buffer = new StringBuilder(); - StringUtil.encodeStringToAlphanumeric(buffer, orig, asciiReadableEncodingLatex, identChar, "z"); - return "klabel" + buffer; + public static byte[] apply(K k) { + try { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + apply(new DataOutputStream(out), k); + return out.toByteArray(); + } catch (IOException e) { + throw KEMException.criticalError("Could not write K term to LaTeX", e, k); } - - private static void writeString(DataOutputStream out, String str) throws IOException { - out.write(str.getBytes(StandardCharsets.UTF_8)); - } - - public static void apply(DataOutputStream out, Att att) throws IOException { - writeString(out, ("\\outerAtt{" + att.toString() + "}")); - } - - public static void apply(DataOutputStream out, K k) throws IOException { - if (k instanceof KToken tok) { - - writeString(out, ("\\texttt{ " + tok.s() + " }")); - - } else if (k instanceof KApply app) { - - writeString(out, ("\\" + latexedKLabel(app.klabel().name()))); - - for (K item : app.klist().asIterable()) { - writeString(out, "{"); - apply(out, item); - writeString(out, "}"); - } - - } else if (k instanceof KSequence kseq) { - - writeString(out, "\\kseq{"); - - for (K item : kseq.asIterable()) { - apply(out, item); - writeString(out, "}{\\kseq{"); - } - - writeString(out, "}{\\dotk{}}"); - - } else if (k instanceof KVariable var) { - - Optional origName = var.att().getOptional(Att.ORIGINAL_NAME()); - if (origName.isPresent()) { - writeString(out, origName.get()); - } else { - writeString(out, var.name()); - } - - } else if (k instanceof KRewrite rew) { - - writeString(out, "\\krewrites{"); - apply(out, rew.left()); - writeString(out, "}{"); - apply(out, rew.right()); - writeString(out, "}{"); - apply(out, rew.att()); - writeString(out, "}"); - - } else if (k instanceof KAs alias) { - - writeString(out, "\\kas{"); - apply(out, alias.pattern()); - writeString(out, "}{"); - apply(out, alias.alias()); - writeString(out, "}{"); - apply(out, alias.att()); - writeString(out, "}"); - - } else if (k instanceof InjectedKLabel inj) { - - writeString(out, "\\injectedklabel{"); - writeString(out, inj.klabel().name()); - writeString(out, "}"); - - } else { - throw KEMException.criticalError("Unimplemented for LaTeX serialization: ", k); - } + } + + private static String[] asciiReadableEncodingLatexCalc() { + String[] latexEncoder = + Arrays.copyOf( + StringUtil.asciiReadableEncodingDefault, + StringUtil.asciiReadableEncodingDefault.length); + latexEncoder[0x30] = "Zero"; + latexEncoder[0x31] = "I"; + latexEncoder[0x32] = "II"; + latexEncoder[0x33] = "III"; + latexEncoder[0x34] = "IV"; + latexEncoder[0x35] = "V"; + latexEncoder[0x36] = "VI"; + latexEncoder[0x37] = "VII"; + latexEncoder[0x38] = "VIII"; + latexEncoder[0x39] = "IX"; + latexEncoder[0x7a] = "ActZ"; + return latexEncoder; + } + + public static final Pattern identChar = Pattern.compile("[A-Za-y]"); + public static String[] asciiReadableEncodingLatex = asciiReadableEncodingLatexCalc(); + + public static String latexedKLabel(String orig) { + StringBuilder buffer = new StringBuilder(); + StringUtil.encodeStringToAlphanumeric(buffer, orig, asciiReadableEncodingLatex, identChar, "z"); + return "klabel" + buffer; + } + + private static void writeString(DataOutputStream out, String str) throws IOException { + out.write(str.getBytes(StandardCharsets.UTF_8)); + } + + public static void apply(DataOutputStream out, Att att) throws IOException { + writeString(out, ("\\outerAtt{" + att.toString() + "}")); + } + + public static void apply(DataOutputStream out, K k) throws IOException { + if (k instanceof KToken tok) { + + writeString(out, ("\\texttt{ " + tok.s() + " }")); + + } else if (k instanceof KApply app) { + + writeString(out, ("\\" + latexedKLabel(app.klabel().name()))); + + for (K item : app.klist().asIterable()) { + writeString(out, "{"); + apply(out, item); + writeString(out, "}"); + } + + } else if (k instanceof KSequence kseq) { + + writeString(out, "\\kseq{"); + + for (K item : kseq.asIterable()) { + apply(out, item); + writeString(out, "}{\\kseq{"); + } + + writeString(out, "}{\\dotk{}}"); + + } else if (k instanceof KVariable var) { + + Optional origName = var.att().getOptional(Att.ORIGINAL_NAME()); + if (origName.isPresent()) { + writeString(out, origName.get()); + } else { + writeString(out, var.name()); + } + + } else if (k instanceof KRewrite rew) { + + writeString(out, "\\krewrites{"); + apply(out, rew.left()); + writeString(out, "}{"); + apply(out, rew.right()); + writeString(out, "}{"); + apply(out, rew.att()); + writeString(out, "}"); + + } else if (k instanceof KAs alias) { + + writeString(out, "\\kas{"); + apply(out, alias.pattern()); + writeString(out, "}{"); + apply(out, alias.alias()); + writeString(out, "}{"); + apply(out, alias.att()); + writeString(out, "}"); + + } else if (k instanceof InjectedKLabel inj) { + + writeString(out, "\\injectedklabel{"); + writeString(out, inj.klabel().name()); + writeString(out, "}"); + + } else { + throw KEMException.criticalError("Unimplemented for LaTeX serialization: ", k); } + } } diff --git a/kernel/src/main/java/org/kframework/utils/BinaryLoader.java b/kernel/src/main/java/org/kframework/utils/BinaryLoader.java index cecc17435b0..108a462f732 100644 --- a/kernel/src/main/java/org/kframework/utils/BinaryLoader.java +++ b/kernel/src/main/java/org/kframework/utils/BinaryLoader.java @@ -2,12 +2,6 @@ package org.kframework.utils; import com.google.inject.Inject; -import javax.annotation.Nullable; -import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.errorsystem.KException.ExceptionType; -import org.kframework.utils.errorsystem.KExceptionManager; -import org.kframework.utils.inject.RequestScoped; - import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -18,81 +12,87 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamException; -import java.lang.reflect.Field; -import java.lang.reflect.Method; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.nio.channels.OverlappingFileLockException; -import java.util.Collections; -import java.util.HashMap; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import javax.annotation.Nullable; +import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.errorsystem.KException.ExceptionType; +import org.kframework.utils.errorsystem.KExceptionManager; +import org.kframework.utils.inject.RequestScoped; @RequestScoped public class BinaryLoader { - private final KExceptionManager kem; + private final KExceptionManager kem; - @Inject - public BinaryLoader(KExceptionManager kem) { - this.kem = kem; - } + @Inject + public BinaryLoader(KExceptionManager kem) { + this.kem = kem; + } - public void saveOrDie(File file, Object o) { - File dir = file.getAbsoluteFile().getParentFile(); - if (!dir.exists() && !dir.mkdirs()) { - throw KEMException.criticalError("Could not create directory " + dir); - } - try { - saveImpl(file, o); - } catch (IOException e) { - throw KEMException.criticalError("Could not write to " + file.getAbsolutePath(), e); - } + public void saveOrDie(File file, Object o) { + File dir = file.getAbsoluteFile().getParentFile(); + if (!dir.exists() && !dir.mkdirs()) { + throw KEMException.criticalError("Could not create directory " + dir); + } + try { + saveImpl(file, o); + } catch (IOException e) { + throw KEMException.criticalError("Could not write to " + file.getAbsolutePath(), e); } + } - public T loadOrDie(Class cls, File file) { - try { - return loadImpl(file, cls); - } catch (ClassNotFoundException e) { - throw new AssertionError("Something wrong with deserialization", e); - } catch (ObjectStreamException e) { - throw KEMException.criticalError("Kompiled definition is out of date with " - + "the latest version of the K tool. Please re-run kompile and try again.", e); - } catch (IOException e) { - throw KEMException.criticalError("Could not read from " + file.getAbsolutePath(), e); - } + public T loadOrDie(Class cls, File file) { + try { + return loadImpl(file, cls); + } catch (ClassNotFoundException e) { + throw new AssertionError("Something wrong with deserialization", e); + } catch (ObjectStreamException e) { + throw KEMException.criticalError( + "Kompiled definition is out of date with " + + "the latest version of the K tool. Please re-run kompile and try again.", + e); + } catch (IOException e) { + throw KEMException.criticalError("Could not read from " + file.getAbsolutePath(), e); } + } - @Nullable - public T loadCache(Class cls, File file) { - try { - return loadImpl(file, cls); - } catch (FileNotFoundException e) { - //ignored - } catch (IOException | ClassNotFoundException e) { - kem.registerInternalWarning(ExceptionType.INVALIDATED_CACHE, "Invalidating serialized cache due to corruption.", e); - } - return null; + @Nullable + public T loadCache(Class cls, File file) { + try { + return loadImpl(file, cls); + } catch (FileNotFoundException e) { + // ignored + } catch (IOException | ClassNotFoundException e) { + kem.registerInternalWarning( + ExceptionType.INVALIDATED_CACHE, "Invalidating serialized cache due to corruption.", e); } + return null; + } - /** - * Locks the file before writing, so that it cannot be read by another instance of K. If the file is currently in - * use, this method will block until lock can be acquired. - */ - private void saveImpl(File file, Object o) throws IOException { - // we want to atomically update the file in case two kprove threads are writing to the same cache at the same time. - Path tempFile = Files.createTempFile(file.getCanonicalFile().getParentFile().toPath(), "tmp", ".bin"); - try (ObjectOutputStream serializer = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile.toFile())))) { - serializer.writeObject(o); - } - Files.move(tempFile, file.toPath(), StandardCopyOption.ATOMIC_MOVE); + /** + * Locks the file before writing, so that it cannot be read by another instance of K. If the file + * is currently in use, this method will block until lock can be acquired. + */ + private void saveImpl(File file, Object o) throws IOException { + // we want to atomically update the file in case two kprove threads are writing to the same + // cache at the same time. + Path tempFile = + Files.createTempFile(file.getCanonicalFile().getParentFile().toPath(), "tmp", ".bin"); + try (ObjectOutputStream serializer = + new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(tempFile.toFile())))) { + serializer.writeObject(o); } + Files.move(tempFile, file.toPath(), StandardCopyOption.ATOMIC_MOVE); + } - private T loadImpl(File file, Class cls) throws IOException, ClassNotFoundException { - try (ObjectInputStream deserializer = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { //already buffered - Object obj = deserializer.readObject(); - return cls.cast(obj); - } + private T loadImpl(File file, Class cls) throws IOException, ClassNotFoundException { + try (ObjectInputStream deserializer = + new ObjectInputStream( + new BufferedInputStream(new FileInputStream(file)))) { // already buffered + Object obj = deserializer.readObject(); + return cls.cast(obj); } + } } diff --git a/kernel/src/main/java/org/kframework/utils/ColorUtil.java b/kernel/src/main/java/org/kframework/utils/ColorUtil.java index f202543f20b..f72c70bf4fa 100644 --- a/kernel/src/main/java/org/kframework/utils/ColorUtil.java +++ b/kernel/src/main/java/org/kframework/utils/ColorUtil.java @@ -1,522 +1,520 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; -import org.kframework.unparser.ColorSetting; - import java.awt.Color; import java.awt.color.ColorSpace; import java.lang.reflect.Field; import java.util.Collections; -import java.util.Map; import java.util.HashMap; +import java.util.Map; +import org.kframework.unparser.ColorSetting; public final class ColorUtil { - private ColorUtil() {} - - private static Map colors; - - /** - * Terminal code corresponding to closest color for this one, from the list of basic 8 - * terminal codes only. - */ - private static final Map ansiColorsToTerminalCodes; - - /** - * Terminal code corresponding to closest color for this one, from the list of 216 colors supported by - * linux terminals. - */ - private static final Map eightBitColorsToTerminalCodes; - - /** - * A cache to avoid computing the closest terminal color for a given color each time it is needed. - */ - private static final Map, Map> colorToCodeConvertCache; - - public static Map colors() { - colors = doInitColors(); - return Collections.unmodifiableMap(colors); - } - - static { - colors = doInitColors(); - ansiColorsToTerminalCodes = initAnsiColors(); - eightBitColorsToTerminalCodes = initEightBitColors(); - colorToCodeConvertCache = initColorToCodeConvertCache(); + private ColorUtil() {} + + private static Map colors; + + /** + * Terminal code corresponding to closest color for this one, from the list of basic 8 terminal + * codes only. + */ + private static final Map ansiColorsToTerminalCodes; + + /** + * Terminal code corresponding to closest color for this one, from the list of 216 colors + * supported by linux terminals. + */ + private static final Map eightBitColorsToTerminalCodes; + + /** + * A cache to avoid computing the closest terminal color for a given color each time it is needed. + */ + private static final Map, Map> colorToCodeConvertCache; + + public static Map colors() { + colors = doInitColors(); + return Collections.unmodifiableMap(colors); + } + + static { + colors = doInitColors(); + ansiColorsToTerminalCodes = initAnsiColors(); + eightBitColorsToTerminalCodes = initEightBitColors(); + colorToCodeConvertCache = initColorToCodeConvertCache(); + } + + private static HashMap, Map> initColorToCodeConvertCache() { + HashMap, Map> map = new HashMap<>(); + map.put(ansiColorsToTerminalCodes, new HashMap()); + map.put(eightBitColorsToTerminalCodes, new HashMap()); + return map; + } + + private static Map doInitColors() { + Map colors = new HashMap(); + colors.put("black", Color.black); + colors.put("blue", Color.blue); + colors.put("brown", getColorByRgb("#C08040")); + colors.put("cyan", Color.cyan); + colors.put("darkgray", Color.darkGray); + colors.put("gray", Color.gray); + colors.put("green", Color.green); + colors.put("lightgray", Color.lightGray); + colors.put("lime", getColorByRgb("#C0FF00")); + colors.put("magenta", Color.magenta); + colors.put("olive", getColorByRgb("#808000")); + colors.put("orange", Color.orange); + colors.put("pink", Color.pink); + colors.put("purple", getColorByRgb("#C00040")); + colors.put("red", Color.red); + colors.put("teal", getColorByRgb("#008080")); + colors.put("violet", getColorByRgb("#800080")); + colors.put("white", Color.white); + colors.put("yellow", Color.yellow); + colors.put("Apricot", getColorByRgb("#FBB982")); + colors.put("Aquamarine", getColorByRgb("#00B5BE")); + colors.put("Bittersweet", getColorByRgb("#C04F17")); + colors.put("Black", getColorByRgb("#221E1F")); + colors.put("Blue", getColorByRgb("#2D2F92")); + colors.put("BlueGreen", getColorByRgb("#00B3B8")); + colors.put("BlueViolet", getColorByRgb("#473992")); + colors.put("BrickRed", getColorByRgb("#B6321C")); + colors.put("Brown", getColorByRgb("#792500")); + colors.put("BurntOrange", getColorByRgb("#F7921D")); + colors.put("CadetBlue", getColorByRgb("#74729A")); + colors.put("CarnationPink", getColorByRgb("#F282B4")); + colors.put("Cerulean", getColorByRgb("#00A2E3")); + colors.put("CornflowerBlue", getColorByRgb("#41B0E4")); + colors.put("Cyan", getColorByRgb("#00AEEF")); + colors.put("Dandelion", getColorByRgb("#FDBC42")); + colors.put("DarkOrchid", getColorByRgb("#A4538A")); + colors.put("Emerald", getColorByRgb("#00A99D")); + colors.put("ForestGreen", getColorByRgb("#009B55")); + colors.put("Fuchsia", getColorByRgb("#8C368C")); + colors.put("Goldenrod", getColorByRgb("#FFDF42")); + colors.put("Gray", getColorByRgb("#949698")); + colors.put("Green", getColorByRgb("#00A64F")); + colors.put("GreenYellow", getColorByRgb("#DFE674")); + colors.put("JungleGreen", getColorByRgb("#00A99A")); + colors.put("Lavender", getColorByRgb("#F49EC4")); + colors.put("LimeGreen", getColorByRgb("#8DC73E")); + colors.put("Magenta", getColorByRgb("#EC008C")); + colors.put("Mahogany", getColorByRgb("#A9341F")); + colors.put("Maroon", getColorByRgb("#AF3235")); + colors.put("Melon", getColorByRgb("#F89E7B")); + colors.put("MidnightBlue", getColorByRgb("#006795")); + colors.put("Mulberry", getColorByRgb("#A93C93")); + colors.put("NavyBlue", getColorByRgb("#006EB8")); + colors.put("OliveGreen", getColorByRgb("#3C8031")); + colors.put("Orange", getColorByRgb("#F58137")); + colors.put("OrangeRed", getColorByRgb("#ED135A")); + colors.put("Orchid", getColorByRgb("#AF72B0")); + colors.put("Peach", getColorByRgb("#F7965A")); + colors.put("Periwinkle", getColorByRgb("#7977B8")); + colors.put("PineGreen", getColorByRgb("#008B72")); + colors.put("Plum", getColorByRgb("#92268F")); + colors.put("ProcessBlue", getColorByRgb("#00B0F0")); + colors.put("Purple", getColorByRgb("#99479B")); + colors.put("RawSienna", getColorByRgb("#974006")); + colors.put("Red", getColorByRgb("#ED1B23")); + colors.put("RedOrange", getColorByRgb("#F26035")); + colors.put("RedViolet", getColorByRgb("#A1246B")); + colors.put("Rhodamine", getColorByRgb("#EF559F")); + colors.put("RoyalBlue", getColorByRgb("#0071BC")); + colors.put("RoyalPurple", getColorByRgb("#613F99")); + colors.put("RubineRed", getColorByRgb("#ED017D")); + colors.put("Salmon", getColorByRgb("#F69289")); + colors.put("SeaGreen", getColorByRgb("#3FBC9D")); + colors.put("Sepia", getColorByRgb("#671800")); + colors.put("SkyBlue", getColorByRgb("#46C5DD")); + colors.put("SpringGreen", getColorByRgb("#C6DC67")); + colors.put("Tan", getColorByRgb("#DA9D76")); + colors.put("TealBlue", getColorByRgb("#00AEB3")); + colors.put("Thistle", getColorByRgb("#D883B7")); + colors.put("Turquoise", getColorByRgb("#00B4CE")); + colors.put("Violet", getColorByRgb("#58429B")); + colors.put("VioletRed", getColorByRgb("#EF58A0")); + colors.put("White", getColorByRgb("#FFFFFF")); + colors.put("WildStrawberry", getColorByRgb("#EE2967")); + colors.put("Yellow", getColorByRgb("#FFF200")); + colors.put("YellowGreen", getColorByRgb("#98CC70")); + colors.put("YellowOrange", getColorByRgb("#FAA21A")); + + addSvgnamesColors(colors); + + return Collections.unmodifiableMap(colors); + } + + private static void addSvgnamesColors(Map colors) { + Object[][] svgColors = { + {"AliceBlue", .94, .972, 1}, + {"AntiqueWhite", .98, .92, .844}, + {"Aqua", 0, 1, 1}, + {"Aquamarine", .498, 1, .83}, + {"Azure", .94, 1, 1}, + {"Beige", .96, .96, .864}, + {"Bisque", 1, .894, .77}, + {"Black", 0, 0, 0}, + {"BlanchedAlmond", 1, .92, .804}, + {"Blue", 0, 0, 1}, + {"BlueViolet", .54, .17, .888}, + {"Brown", .648, .165, .165}, + {"BurlyWood", .87, .72, .53}, + {"CadetBlue", .372, .62, .628}, + {"Chartreuse", .498, 1, 0}, + {"Chocolate", .824, .41, .116}, + {"Coral", 1, .498, .312}, + {"CornflowerBlue", .392, .585, .93}, + {"Cornsilk", 1, .972, .864}, + {"Crimson", .864, .08, .235}, + {"Cyan", 0, 1, 1}, + {"DarkBlue", 0, 0, .545}, + {"DarkCyan", 0, .545, .545}, + {"DarkGoldenrod", .72, .525, .044}, + {"DarkGray", .664, .664, .664}, + {"DarkGreen", 0, .392, 0}, + {"DarkGrey", .664, .664, .664}, + {"DarkKhaki", .74, .716, .42}, + {"DarkMagenta", .545, 0, .545}, + {"DarkOliveGreen", .332, .42, .185}, + {"DarkOrange", 1, .55, 0}, + {"DarkOrchid", .6, .196, .8}, + {"DarkRed", .545, 0, 0}, + {"DarkSalmon", .912, .59, .48}, + {"DarkSeaGreen", .56, .736, .56}, + {"DarkSlateBlue", .284, .24, .545}, + {"DarkSlateGray", .185, .31, .31}, + {"DarkSlateGrey", .185, .31, .31}, + {"DarkTurquoise", 0, .808, .82}, + {"DarkViolet", .58, 0, .828}, + {"DeepPink", 1, .08, .576}, + {"DeepSkyBlue", 0, .75, 1}, + {"DimGray", .41, .41, .41}, + {"DimGrey", .41, .41, .41}, + {"DodgerBlue", .116, .565, 1}, + {"FireBrick", .698, .132, .132}, + {"FloralWhite", 1, .98, .94}, + {"ForestGreen", .132, .545, .132}, + {"Fuchsia", 1, 0, 1}, + {"Gainsboro", .864, .864, .864}, + {"GhostWhite", .972, .972, 1}, + {"Gold", 1, .844, 0}, + {"Goldenrod", .855, .648, .125}, + {"Gray", .5, .5, .5}, + {"Green", 0, .5, 0}, + {"GreenYellow", .68, 1, .185}, + {"Grey", .5, .5, .5}, + {"Honeydew", .94, 1, .94}, + {"HotPink", 1, .41, .705}, + {"IndianRed", .804, .36, .36}, + {"Indigo", .294, 0, .51}, + {"Ivory", 1, 1, .94}, + {"Khaki", .94, .9, .55}, + {"Lavender", .9, .9, .98}, + {"LavenderBlush", 1, .94, .96}, + {"LawnGreen", .488, .99, 0}, + {"LemonChiffon", 1, .98, .804}, + {"LightBlue", .68, .848, .9}, + {"LightCoral", .94, .5, .5}, + {"LightCyan", .88, 1, 1}, + {"LightGoldenrod", .933, .867, .51}, + {"LightGoldenrodYellow", .98, .98, .824}, + {"LightGray", .828, .828, .828}, + {"LightGreen", .565, .932, .565}, + {"LightGrey", .828, .828, .828}, + {"LightPink", 1, .712, .756}, + {"LightSalmon", 1, .628, .48}, + {"LightSeaGreen", .125, .698, .668}, + {"LightSkyBlue", .53, .808, .98}, + {"LightSlateBlue", .518, .44, 1}, + {"LightSlateGray", .468, .532, .6}, + {"LightSlateGrey", .468, .532, .6}, + {"LightSteelBlue", .69, .77, .87}, + {"LightYellow", 1, 1, .88}, + {"Lime", 0, 1, 0}, + {"LimeGreen", .196, .804, .196}, + {"Linen", .98, .94, .9}, + {"Magenta", 1, 0, 1}, + {"Maroon", .5, 0, 0}, + {"MediumAquamarine", .4, .804, .668}, + {"MediumBlue", 0, 0, .804}, + {"MediumOrchid", .73, .332, .828}, + {"MediumPurple", .576, .44, .86}, + {"MediumSeaGreen", .235, .7, .444}, + {"MediumSlateBlue", .484, .408, .932}, + {"MediumSpringGreen", 0, .98, .604}, + {"MediumTurquoise", .284, .82, .8}, + {"MediumVioletRed", .78, .084, .52}, + {"MidnightBlue", .098, .098, .44}, + {"MintCream", .96, 1, .98}, + {"MistyRose", 1, .894, .884}, + {"Moccasin", 1, .894, .71}, + {"NavajoWhite", 1, .87, .68}, + {"Navy", 0, 0, .5}, + {"NavyBlue", 0, 0, .5}, + {"OldLace", .992, .96, .9}, + {"Olive", .5, .5, 0}, + {"OliveDrab", .42, .556, .136}, + {"Orange", 1, .648, 0}, + {"OrangeRed", 1, .27, 0}, + {"Orchid", .855, .44, .84}, + {"PaleGoldenrod", .932, .91, .668}, + {"PaleGreen", .596, .985, .596}, + {"PaleTurquoise", .688, .932, .932}, + {"PaleVioletRed", .86, .44, .576}, + {"PapayaWhip", 1, .936, .835}, + {"PeachPuff", 1, .855, .725}, + {"Peru", .804, .52, .248}, + {"Pink", 1, .752, .796}, + {"Plum", .868, .628, .868}, + {"PowderBlue", .69, .88, .9}, + {"Purple", .5, 0, .5}, + {"Red", 1, 0, 0}, + {"RosyBrown", .736, .56, .56}, + {"RoyalBlue", .255, .41, .884}, + {"SaddleBrown", .545, .27, .075}, + {"Salmon", .98, .5, .448}, + {"SandyBrown", .956, .644, .376}, + {"SeaGreen", .18, .545, .34}, + {"Seashell", 1, .96, .932}, + {"Sienna", .628, .32, .176}, + {"Silver", .752, .752, .752}, + {"SkyBlue", .53, .808, .92}, + {"SlateBlue", .415, .352, .804}, + {"SlateGray", .44, .5, .565}, + {"SlateGrey", .44, .5, .565}, + {"Snow", 1, .98, .98}, + {"SpringGreen", 0, 1, .498}, + {"SteelBlue", .275, .51, .705}, + {"Tan", .824, .705, .55}, + {"Teal", 0, .5, .5}, + {"Thistle", .848, .75, .848}, + {"Tomato", 1, .39, .28}, + {"Turquoise", .25, .88, .815}, + {"Violet", .932, .51, .932}, + {"VioletRed", .816, .125, .565}, + {"Wheat", .96, .87, .7}, + {"White", 1, 1, 1}, + {"WhiteSmoke", .96, .96, .96}, + {"Yellow", 1, 1, 0}, + {"YellowGreen", .604, .804, .196}, + }; + for (Object[] rawColor : svgColors) { + colors.put( + (String) rawColor[0], + new Color(toFloat(rawColor[1]), toFloat(rawColor[2]), toFloat(rawColor[3]))); } - - private static HashMap, Map> initColorToCodeConvertCache() { - HashMap, Map> map = new HashMap<>(); - map.put(ansiColorsToTerminalCodes, new HashMap()); - map.put(eightBitColorsToTerminalCodes, new HashMap()); - return map; - } - - private static Map doInitColors() { - Map colors = new HashMap(); - colors.put("black", Color.black); - colors.put("blue", Color.blue); - colors.put("brown", getColorByRgb("#C08040")); - colors.put("cyan", Color.cyan); - colors.put("darkgray", Color.darkGray); - colors.put("gray", Color.gray); - colors.put("green", Color.green); - colors.put("lightgray", Color.lightGray); - colors.put("lime", getColorByRgb("#C0FF00")); - colors.put("magenta", Color.magenta); - colors.put("olive", getColorByRgb("#808000")); - colors.put("orange", Color.orange); - colors.put("pink", Color.pink); - colors.put("purple", getColorByRgb("#C00040")); - colors.put("red", Color.red); - colors.put("teal", getColorByRgb("#008080")); - colors.put("violet", getColorByRgb("#800080")); - colors.put("white", Color.white); - colors.put("yellow", Color.yellow); - colors.put("Apricot", getColorByRgb("#FBB982")); - colors.put("Aquamarine", getColorByRgb("#00B5BE")); - colors.put("Bittersweet", getColorByRgb("#C04F17")); - colors.put("Black", getColorByRgb("#221E1F")); - colors.put("Blue", getColorByRgb("#2D2F92")); - colors.put("BlueGreen", getColorByRgb("#00B3B8")); - colors.put("BlueViolet", getColorByRgb("#473992")); - colors.put("BrickRed", getColorByRgb("#B6321C")); - colors.put("Brown", getColorByRgb("#792500")); - colors.put("BurntOrange", getColorByRgb("#F7921D")); - colors.put("CadetBlue", getColorByRgb("#74729A")); - colors.put("CarnationPink", getColorByRgb("#F282B4")); - colors.put("Cerulean", getColorByRgb("#00A2E3")); - colors.put("CornflowerBlue", getColorByRgb("#41B0E4")); - colors.put("Cyan", getColorByRgb("#00AEEF")); - colors.put("Dandelion", getColorByRgb("#FDBC42")); - colors.put("DarkOrchid", getColorByRgb("#A4538A")); - colors.put("Emerald", getColorByRgb("#00A99D")); - colors.put("ForestGreen", getColorByRgb("#009B55")); - colors.put("Fuchsia", getColorByRgb("#8C368C")); - colors.put("Goldenrod", getColorByRgb("#FFDF42")); - colors.put("Gray", getColorByRgb("#949698")); - colors.put("Green", getColorByRgb("#00A64F")); - colors.put("GreenYellow", getColorByRgb("#DFE674")); - colors.put("JungleGreen", getColorByRgb("#00A99A")); - colors.put("Lavender", getColorByRgb("#F49EC4")); - colors.put("LimeGreen", getColorByRgb("#8DC73E")); - colors.put("Magenta", getColorByRgb("#EC008C")); - colors.put("Mahogany", getColorByRgb("#A9341F")); - colors.put("Maroon", getColorByRgb("#AF3235")); - colors.put("Melon", getColorByRgb("#F89E7B")); - colors.put("MidnightBlue", getColorByRgb("#006795")); - colors.put("Mulberry", getColorByRgb("#A93C93")); - colors.put("NavyBlue", getColorByRgb("#006EB8")); - colors.put("OliveGreen", getColorByRgb("#3C8031")); - colors.put("Orange", getColorByRgb("#F58137")); - colors.put("OrangeRed", getColorByRgb("#ED135A")); - colors.put("Orchid", getColorByRgb("#AF72B0")); - colors.put("Peach", getColorByRgb("#F7965A")); - colors.put("Periwinkle", getColorByRgb("#7977B8")); - colors.put("PineGreen", getColorByRgb("#008B72")); - colors.put("Plum", getColorByRgb("#92268F")); - colors.put("ProcessBlue", getColorByRgb("#00B0F0")); - colors.put("Purple", getColorByRgb("#99479B")); - colors.put("RawSienna", getColorByRgb("#974006")); - colors.put("Red", getColorByRgb("#ED1B23")); - colors.put("RedOrange", getColorByRgb("#F26035")); - colors.put("RedViolet", getColorByRgb("#A1246B")); - colors.put("Rhodamine", getColorByRgb("#EF559F")); - colors.put("RoyalBlue", getColorByRgb("#0071BC")); - colors.put("RoyalPurple", getColorByRgb("#613F99")); - colors.put("RubineRed", getColorByRgb("#ED017D")); - colors.put("Salmon", getColorByRgb("#F69289")); - colors.put("SeaGreen", getColorByRgb("#3FBC9D")); - colors.put("Sepia", getColorByRgb("#671800")); - colors.put("SkyBlue", getColorByRgb("#46C5DD")); - colors.put("SpringGreen", getColorByRgb("#C6DC67")); - colors.put("Tan", getColorByRgb("#DA9D76")); - colors.put("TealBlue", getColorByRgb("#00AEB3")); - colors.put("Thistle", getColorByRgb("#D883B7")); - colors.put("Turquoise", getColorByRgb("#00B4CE")); - colors.put("Violet", getColorByRgb("#58429B")); - colors.put("VioletRed", getColorByRgb("#EF58A0")); - colors.put("White", getColorByRgb("#FFFFFF")); - colors.put("WildStrawberry", getColorByRgb("#EE2967")); - colors.put("Yellow", getColorByRgb("#FFF200")); - colors.put("YellowGreen", getColorByRgb("#98CC70")); - colors.put("YellowOrange", getColorByRgb("#FAA21A")); - - addSvgnamesColors(colors); - - return Collections.unmodifiableMap(colors); - } - - private static void addSvgnamesColors(Map colors) { - Object[][] svgColors = { - {"AliceBlue", .94, .972, 1}, - {"AntiqueWhite", .98, .92, .844}, - {"Aqua", 0, 1, 1}, - {"Aquamarine", .498, 1, .83}, - {"Azure", .94, 1, 1}, - {"Beige", .96, .96, .864}, - {"Bisque", 1, .894, .77}, - {"Black", 0, 0, 0}, - {"BlanchedAlmond", 1, .92, .804}, - {"Blue", 0, 0, 1}, - {"BlueViolet", .54, .17, .888}, - {"Brown", .648, .165, .165}, - {"BurlyWood", .87, .72, .53}, - {"CadetBlue", .372, .62, .628}, - {"Chartreuse", .498, 1, 0}, - {"Chocolate", .824, .41, .116}, - {"Coral", 1, .498, .312}, - {"CornflowerBlue", .392, .585, .93}, - {"Cornsilk", 1, .972, .864}, - {"Crimson", .864, .08, .235}, - {"Cyan", 0, 1, 1}, - {"DarkBlue", 0, 0, .545}, - {"DarkCyan", 0, .545, .545}, - {"DarkGoldenrod", .72, .525, .044}, - {"DarkGray", .664, .664, .664}, - {"DarkGreen", 0, .392, 0}, - {"DarkGrey", .664, .664, .664}, - {"DarkKhaki", .74, .716, .42}, - {"DarkMagenta", .545, 0, .545}, - {"DarkOliveGreen", .332, .42, .185}, - {"DarkOrange", 1, .55, 0}, - {"DarkOrchid", .6, .196, .8}, - {"DarkRed", .545, 0, 0}, - {"DarkSalmon", .912, .59, .48}, - {"DarkSeaGreen", .56, .736, .56}, - {"DarkSlateBlue", .284, .24, .545}, - {"DarkSlateGray", .185, .31, .31}, - {"DarkSlateGrey", .185, .31, .31}, - {"DarkTurquoise", 0, .808, .82}, - {"DarkViolet", .58, 0, .828}, - {"DeepPink", 1, .08, .576}, - {"DeepSkyBlue", 0, .75, 1}, - {"DimGray", .41, .41, .41}, - {"DimGrey", .41, .41, .41}, - {"DodgerBlue", .116, .565, 1}, - {"FireBrick", .698, .132, .132}, - {"FloralWhite", 1, .98, .94}, - {"ForestGreen", .132, .545, .132}, - {"Fuchsia", 1, 0, 1}, - {"Gainsboro", .864, .864, .864}, - {"GhostWhite", .972, .972, 1}, - {"Gold", 1, .844, 0}, - {"Goldenrod", .855, .648, .125}, - {"Gray", .5, .5, .5}, - {"Green", 0, .5, 0}, - {"GreenYellow", .68, 1, .185}, - {"Grey", .5, .5, .5}, - {"Honeydew", .94, 1, .94}, - {"HotPink", 1, .41, .705}, - {"IndianRed", .804, .36, .36}, - {"Indigo", .294, 0, .51}, - {"Ivory", 1, 1, .94}, - {"Khaki", .94, .9, .55}, - {"Lavender", .9, .9, .98}, - {"LavenderBlush", 1, .94, .96}, - {"LawnGreen", .488, .99, 0}, - {"LemonChiffon", 1, .98, .804}, - {"LightBlue", .68, .848, .9}, - {"LightCoral", .94, .5, .5}, - {"LightCyan", .88, 1, 1}, - {"LightGoldenrod", .933, .867, .51}, - {"LightGoldenrodYellow", .98, .98, .824}, - {"LightGray", .828, .828, .828}, - {"LightGreen", .565, .932, .565}, - {"LightGrey", .828, .828, .828}, - {"LightPink", 1, .712, .756}, - {"LightSalmon", 1, .628, .48}, - {"LightSeaGreen", .125, .698, .668}, - {"LightSkyBlue", .53, .808, .98}, - {"LightSlateBlue", .518, .44, 1}, - {"LightSlateGray", .468, .532, .6}, - {"LightSlateGrey", .468, .532, .6}, - {"LightSteelBlue", .69, .77, .87}, - {"LightYellow", 1, 1, .88}, - {"Lime", 0, 1, 0}, - {"LimeGreen", .196, .804, .196}, - {"Linen", .98, .94, .9}, - {"Magenta", 1, 0, 1}, - {"Maroon", .5, 0, 0}, - {"MediumAquamarine", .4, .804, .668}, - {"MediumBlue", 0, 0, .804}, - {"MediumOrchid", .73, .332, .828}, - {"MediumPurple", .576, .44, .86}, - {"MediumSeaGreen", .235, .7, .444}, - {"MediumSlateBlue", .484, .408, .932}, - {"MediumSpringGreen", 0, .98, .604}, - {"MediumTurquoise", .284, .82, .8}, - {"MediumVioletRed", .78, .084, .52}, - {"MidnightBlue", .098, .098, .44}, - {"MintCream", .96, 1, .98}, - {"MistyRose", 1, .894, .884}, - {"Moccasin", 1, .894, .71}, - {"NavajoWhite", 1, .87, .68}, - {"Navy", 0, 0, .5}, - {"NavyBlue", 0, 0, .5}, - {"OldLace", .992, .96, .9}, - {"Olive", .5, .5, 0}, - {"OliveDrab", .42, .556, .136}, - {"Orange", 1, .648, 0}, - {"OrangeRed", 1, .27, 0}, - {"Orchid", .855, .44, .84}, - {"PaleGoldenrod", .932, .91, .668}, - {"PaleGreen", .596, .985, .596}, - {"PaleTurquoise", .688, .932, .932}, - {"PaleVioletRed", .86, .44, .576}, - {"PapayaWhip", 1, .936, .835}, - {"PeachPuff", 1, .855, .725}, - {"Peru", .804, .52, .248}, - {"Pink", 1, .752, .796}, - {"Plum", .868, .628, .868}, - {"PowderBlue", .69, .88, .9}, - {"Purple", .5, 0, .5}, - {"Red", 1, 0, 0}, - {"RosyBrown", .736, .56, .56}, - {"RoyalBlue", .255, .41, .884}, - {"SaddleBrown", .545, .27, .075}, - {"Salmon", .98, .5, .448}, - {"SandyBrown", .956, .644, .376}, - {"SeaGreen", .18, .545, .34}, - {"Seashell", 1, .96, .932}, - {"Sienna", .628, .32, .176}, - {"Silver", .752, .752, .752}, - {"SkyBlue", .53, .808, .92}, - {"SlateBlue", .415, .352, .804}, - {"SlateGray", .44, .5, .565}, - {"SlateGrey", .44, .5, .565}, - {"Snow", 1, .98, .98}, - {"SpringGreen", 0, 1, .498}, - {"SteelBlue", .275, .51, .705}, - {"Tan", .824, .705, .55}, - {"Teal", 0, .5, .5}, - {"Thistle", .848, .75, .848}, - {"Tomato", 1, .39, .28}, - {"Turquoise", .25, .88, .815}, - {"Violet", .932, .51, .932}, - {"VioletRed", .816, .125, .565}, - {"Wheat", .96, .87, .7}, - {"White", 1, 1, 1}, - {"WhiteSmoke", .96, .96, .96}, - {"Yellow", 1, 1, 0}, - {"YellowGreen", .604, .804, .196}, - }; - for (Object[] rawColor : svgColors) { - colors.put((String) rawColor[0], new Color(toFloat(rawColor[1]), toFloat(rawColor[2]), toFloat(rawColor[3]))); + } + + private static float toFloat(Object rawColor) { + return rawColor instanceof Integer ? (float) (Integer) rawColor : (float) (double) rawColor; + } + + private static Color getColorByRgb(String rgb) { + int r = Integer.valueOf(rgb.substring(1, 3), 16); + int g = Integer.valueOf(rgb.substring(3, 5), 16); + int b = Integer.valueOf(rgb.substring(5, 7), 16); + return new Color(r, g, b); + } + + private static Map initAnsiColors() { + Map map = new HashMap(8); + map.put(Color.black, getBasicTerminalCode(30)); + map.put(Color.red, getBasicTerminalCode(31)); + map.put(Color.green, getBasicTerminalCode(32)); + map.put(Color.yellow, getBasicTerminalCode(33)); + map.put(Color.blue, getBasicTerminalCode(34)); + map.put(Color.magenta, getBasicTerminalCode(35)); + map.put(Color.cyan, getBasicTerminalCode(36)); + map.put(Color.white, getBasicTerminalCode(37)); + + return Collections.unmodifiableMap(map); + } + + /** + * Basic colors codes have the form \e[<code>m . You can test them by running in your + * terminal: echo -en "\e[35mTEST" + */ + private static String getBasicTerminalCode(int code) { + return "\u001b[" + code + "m"; + } + + private static Map initEightBitColors() { + Map coordMap = new HashMap(); + coordMap.put(0, 0); + coordMap.put(1, 95); + coordMap.put(2, 135); + coordMap.put(3, 175); + coordMap.put(4, 215); + coordMap.put(5, 255); + + Map map = new HashMap(); + for (int i = 0; i < 6; i++) { + for (int j = 0; j < 6; j++) { + for (int k = 0; k < 6; k++) { + int code = i * 36 + j * 6 + k + 16; + Color color = new Color(coordMap.get(i), coordMap.get(j), coordMap.get(k)); + map.put(color, getEightBitTerminalCode(code)); } + } } - private static float toFloat(Object rawColor) { - return rawColor instanceof Integer ? (float) (Integer) rawColor : (float) (double) rawColor; - } - - private static Color getColorByRgb(String rgb) { - int r = Integer.valueOf(rgb.substring(1, 3), 16); - int g = Integer.valueOf(rgb.substring(3, 5), 16); - int b = Integer.valueOf(rgb.substring(5, 7), 16); - return new Color(r, g, b); + return Collections.unmodifiableMap(map); + } + + /** 8-bit format example: echo -en "\e[38;5;180mTEST" */ + private static String getEightBitTerminalCode(int code) { + return "\u001b[38;5;" + code + "m"; + } + + public static synchronized String RgbToAnsi(String rgb, ColorSetting colorSetting) { + return switch (colorSetting) { + case OFF -> ""; + case ON -> getClosestTerminalCode(colors.get(rgb), ansiColorsToTerminalCodes); + case EXTENDED -> getClosestTerminalCode(colors.get(rgb), eightBitColorsToTerminalCodes); + default -> throw new UnsupportedOperationException("colorSettung: " + colorSetting); + }; + } + + public static void main(String[] args) { + for (String name : colors.keySet()) { + System.out.println(name); + System.out.println(RgbToAnsi(name, ColorSetting.EXTENDED)); } + } - private static Map initAnsiColors() { - Map map = new HashMap(8); - map.put(Color.black, getBasicTerminalCode(30)); - map.put(Color.red, getBasicTerminalCode(31)); - map.put(Color.green, getBasicTerminalCode(32)); - map.put(Color.yellow, getBasicTerminalCode(33)); - map.put(Color.blue, getBasicTerminalCode(34)); - map.put(Color.magenta, getBasicTerminalCode(35)); - map.put(Color.cyan, getBasicTerminalCode(36)); - map.put(Color.white, getBasicTerminalCode(37)); - - return Collections.unmodifiableMap(map); + private static String getClosestTerminalCode(Color rgb, Map codesMap) { + if (rgb == null) return ""; + if (colorToCodeConvertCache.get(codesMap).get(rgb) == null) { + colorToCodeConvertCache.get(codesMap).put(rgb, getClosestTerminalCodeImpl(rgb, codesMap)); } - - /** - * Basic colors codes have the form \e[<code>m . You can test them by running in your terminal: - * echo -en "\e[35mTEST" - */ - private static String getBasicTerminalCode(int code) { - return "\u001b[" + code + "m"; + return colorToCodeConvertCache.get(codesMap).get(rgb); + } + + private static String getClosestTerminalCodeImpl(Color rgb, Map codesMap) { + double minColorError = Double.MAX_VALUE; + Color minColor = null; + for (Color ansi : codesMap.keySet()) { + double colorError = getColorError(rgb, ansi); + if (colorError < minColorError) { + minColorError = colorError; + minColor = ansi; + } } - - private static Map initEightBitColors() { - Map coordMap = new HashMap(); - coordMap.put(0,0); - coordMap.put(1,95); - coordMap.put(2,135); - coordMap.put(3,175); - coordMap.put(4,215); - coordMap.put(5,255); - - Map map = new HashMap(); - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 6; j++) { - for (int k = 0; k < 6; k++) { - int code = i *36 + j * 6 + k + 16; - Color color = new Color(coordMap.get(i),coordMap.get(j),coordMap.get(k)); - map.put(color, getEightBitTerminalCode(code)); - } - } - } - - return Collections.unmodifiableMap(map); + return codesMap.get(minColor); + } + + public static final String ANSI_NORMAL = "\u001b[0m"; + + private static final double sl = 1.0; + private static final double kc = 1.0; + private static final double kh = 1.0; + // graphic args + private static final double kl = 1.0; + private static final double k1 = 0.045; + private static final double k2 = 0.015; + + public static final class CIELab extends ColorSpace { + private static final ColorSpace CIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); + + private final double xn, yn, zn; + + CIELab() { + super(ColorSpace.TYPE_Lab, 3); + float[] ref = Color.white.getColorComponents(CIEXYZ, null); + xn = ref[0]; + yn = ref[1]; + zn = ref[2]; } - /** - * 8-bit format example: echo -en "\e[38;5;180mTEST" - */ - private static String getEightBitTerminalCode(int code) { - return "\u001b[38;5;" + code + "m"; + @Override + public float[] toRGB(float[] floats) { + return CIEXYZ.toRGB(toCIEXYZ(floats)); } - public synchronized static String RgbToAnsi(String rgb, ColorSetting colorSetting) { - return switch (colorSetting) { - case OFF -> ""; - case ON -> getClosestTerminalCode(colors.get(rgb), ansiColorsToTerminalCodes); - case EXTENDED -> getClosestTerminalCode(colors.get(rgb), eightBitColorsToTerminalCodes); - default -> throw new UnsupportedOperationException("colorSettung: " + colorSetting); - }; + @Override + public float[] fromRGB(float[] floats) { + return fromCIEXYZ(CIEXYZ.fromRGB(floats)); } - public static void main(String[] args) { - for (String name : colors.keySet()) { - System.out.println(name); - System.out.println(RgbToAnsi(name, ColorSetting.EXTENDED)); - } + @Override + public float[] toCIEXYZ(float[] floats) { + double l = floats[0]; + double a = floats[1]; + double b = floats[2]; + double x = xn * finv((l + 16.0) / 116.0 + a / 500.0); + double y = yn * finv((l + 16.0) / 116.0); + double z = zn * finv((l + 16.0) / 116.0 - b / 200.0); + return new float[] {(float) x, (float) y, (float) z}; } - private static String getClosestTerminalCode(Color rgb, Map codesMap) { - if (rgb == null) - return ""; - if (colorToCodeConvertCache.get(codesMap).get(rgb) == null) { - colorToCodeConvertCache.get(codesMap).put(rgb, getClosestTerminalCodeImpl(rgb, codesMap)); - } - return colorToCodeConvertCache.get(codesMap).get(rgb); + @Override + public float[] fromCIEXYZ(float[] floats) { + double x = floats[0]; + double y = floats[1]; + double z = floats[2]; + double l = 116.0 * f(y / yn) - 16.0; + double a = 500.0 * (f(x / xn) - f(y / yn)); + double b = 200.0 * (f(y / yn) - f(z / zn)); + return new float[] {(float) l, (float) a, (float) b}; } - private static String getClosestTerminalCodeImpl(Color rgb, Map codesMap) { - double minColorError = Double.MAX_VALUE; - Color minColor = null; - for (Color ansi : codesMap.keySet()) { - double colorError = getColorError(rgb, ansi); - if (colorError < minColorError) { - minColorError = colorError; - minColor = ansi; - } - } - return codesMap.get(minColor); - } + private static final double delta = 6.0 / 29.0; + private static final double f0 = 4.0 / 29.0; - public static final String ANSI_NORMAL = "\u001b[0m"; - - private static final double sl = 1.0; - private static final double kc = 1.0; - private static final double kh = 1.0; - // graphic args - private static final double kl = 1.0; - private static final double k1 = 0.045; - private static final double k2 = 0.015; - - public static final class CIELab extends ColorSpace { - private static final ColorSpace CIEXYZ = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); - - private final double xn, yn, zn; - - CIELab() { - super(ColorSpace.TYPE_Lab, 3); - float[] ref = Color.white.getColorComponents(CIEXYZ, null); - xn = ref[0]; - yn = ref[1]; - zn = ref[2]; - } - - @Override - public float[] toRGB(float[] floats) { - return CIEXYZ.toRGB(toCIEXYZ(floats)); - } - - @Override - public float[] fromRGB(float[] floats) { - return fromCIEXYZ(CIEXYZ.fromRGB(floats)); - } - - @Override - public float[] toCIEXYZ(float[] floats) { - double l = floats[0]; - double a = floats[1]; - double b = floats[2]; - double x = xn * finv((l + 16.0)/116.0 + a/500.0); - double y = yn * finv((l + 16.0)/116.0); - double z = zn * finv((l + 16.0)/116.0 - b/200.0); - return new float[]{ (float)x, (float)y, (float)z }; - } - - @Override - public float[] fromCIEXYZ(float[] floats) { - double x = floats[0]; - double y = floats[1]; - double z = floats[2]; - double l = 116.0 * f(y/yn) - 16.0; - double a = 500.0 * (f(x/xn) - f(y/yn)); - double b = 200.0 * (f(y/yn) - f(z/zn)); - return new float[]{ (float)l, (float)a, (float)b }; - } - - private static final double delta = 6.0/29.0; - private static final double f0 = 4.0/29.0; - - private double f(double t) { - if (t > delta*delta*delta) { - return Math.cbrt(t); - } - return t/(3*delta*delta) + f0; - } - - private double finv(double t) { - if (t > delta) { - return t*t*t; - } - return 3*delta*delta*(t - f0); - } + private double f(double t) { + if (t > delta * delta * delta) { + return Math.cbrt(t); + } + return t / (3 * delta * delta) + f0; } - // Computes the CIE94 color difference of two colors - private static double getColorError(Color color1, Color color2) { - float[] rgb1 = color1.getRGBColorComponents(null); - float[] rgb2 = color2.getRGBColorComponents(null); - - ColorSpace labSpace = new CIELab(); - float[] lab1 = labSpace.fromRGB(rgb1); - float[] lab2 = labSpace.fromRGB(rgb2); - - double deltaL = lab1[0] - lab2[0]; - double deltaA = lab1[1] - lab2[1]; - double deltaB = lab1[2] - lab2[2]; - - double c1 = Math.sqrt(lab1[1]*lab1[1] + lab1[2]*lab1[2]); - double c2 = Math.sqrt(lab2[1]*lab2[1] + lab2[2]*lab2[2]); - double deltaC = c1 - c2; - - double deltaH = deltaA*deltaA + deltaB*deltaB - deltaC*deltaC; - deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH); - - double sc = 1.0 + k1*c1; - double sh = 1.0 + k2*c1; - - double l = deltaL/(kl*sl); - double c = deltaC/(kc*sc); - double h = deltaH/(kh*sh); - double i = l*l + c*c + h*h; - return i < 0 ? 0 : Math.sqrt(i); + private double finv(double t) { + if (t > delta) { + return t * t * t; + } + return 3 * delta * delta * (t - f0); } - - public static Color getColorByName(String colorName) { - try { - // Find the field and value of colorName - Field field = Class.forName("java.awt.Color").getField(colorName); - return (Color)field.get(null); - } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { - return null; - } + } + + // Computes the CIE94 color difference of two colors + private static double getColorError(Color color1, Color color2) { + float[] rgb1 = color1.getRGBColorComponents(null); + float[] rgb2 = color2.getRGBColorComponents(null); + + ColorSpace labSpace = new CIELab(); + float[] lab1 = labSpace.fromRGB(rgb1); + float[] lab2 = labSpace.fromRGB(rgb2); + + double deltaL = lab1[0] - lab2[0]; + double deltaA = lab1[1] - lab2[1]; + double deltaB = lab1[2] - lab2[2]; + + double c1 = Math.sqrt(lab1[1] * lab1[1] + lab1[2] * lab1[2]); + double c2 = Math.sqrt(lab2[1] * lab2[1] + lab2[2] * lab2[2]); + double deltaC = c1 - c2; + + double deltaH = deltaA * deltaA + deltaB * deltaB - deltaC * deltaC; + deltaH = deltaH < 0 ? 0 : Math.sqrt(deltaH); + + double sc = 1.0 + k1 * c1; + double sh = 1.0 + k2 * c1; + + double l = deltaL / (kl * sl); + double c = deltaC / (kc * sc); + double h = deltaH / (kh * sh); + double i = l * l + c * c + h * h; + return i < 0 ? 0 : Math.sqrt(i); + } + + public static Color getColorByName(String colorName) { + try { + // Find the field and value of colorName + Field field = Class.forName("java.awt.Color").getField(colorName); + return (Color) field.get(null); + } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) { + return null; } + } } diff --git a/kernel/src/main/java/org/kframework/utils/ExitOnTimeoutThread.java b/kernel/src/main/java/org/kframework/utils/ExitOnTimeoutThread.java index 7c2c7da24fe..e2536d72e45 100644 --- a/kernel/src/main/java/org/kframework/utils/ExitOnTimeoutThread.java +++ b/kernel/src/main/java/org/kframework/utils/ExitOnTimeoutThread.java @@ -6,25 +6,24 @@ /** * A daemon thread that awaits given timeout, then exits Java process. * - * @author Denis Bogdanas - * Created on 30-Oct-19. + * @author Denis Bogdanas Created on 30-Oct-19. */ public class ExitOnTimeoutThread extends Thread { - private final long timeoutMillis; + private final long timeoutMillis; - public ExitOnTimeoutThread(long timeoutMillis) { - this.timeoutMillis = timeoutMillis; - setDaemon(true); - } + public ExitOnTimeoutThread(long timeoutMillis) { + this.timeoutMillis = timeoutMillis; + setDaemon(true); + } - @Override - public void run() { - try { - Thread.sleep(timeoutMillis); - System.err.println("K process timeout..."); - Main.exit(124); //bash timeout exit code is 124 - } catch (InterruptedException e) { - //normal termination, ignoring - } + @Override + public void run() { + try { + Thread.sleep(timeoutMillis); + System.err.println("K process timeout..."); + Main.exit(124); // bash timeout exit code is 124 + } catch (InterruptedException e) { + // normal termination, ignoring } + } } diff --git a/kernel/src/main/java/org/kframework/utils/IndentingFormatter.java b/kernel/src/main/java/org/kframework/utils/IndentingFormatter.java index ea4113d0f82..23b5c726b2f 100644 --- a/kernel/src/main/java/org/kframework/utils/IndentingFormatter.java +++ b/kernel/src/main/java/org/kframework/utils/IndentingFormatter.java @@ -1,47 +1,47 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; -import javax.annotation.Nonnull; import java.util.Formatter; +import javax.annotation.Nonnull; /** * An extension of {@code java.util.Formatter} that indents every new line with specified prefix. * - * @author Denis Bogdanas - * Created on 14-Apr-19. + * @author Denis Bogdanas Created on 14-Apr-19. */ public class IndentingFormatter { - public static final String ENDL = "\n"; - private final Formatter formatter; - private final String endlReplacement; + public static final String ENDL = "\n"; + private final Formatter formatter; + private final String endlReplacement; - public IndentingFormatter(@Nonnull Formatter formatter, @Nonnull String indent) { - this.formatter = formatter; - this.endlReplacement = indent.isEmpty() ? ENDL : ENDL + indent; - } + public IndentingFormatter(@Nonnull Formatter formatter, @Nonnull String indent) { + this.formatter = formatter; + this.endlReplacement = indent.isEmpty() ? ENDL : ENDL + indent; + } - public Formatter format(String format, Object... args) { - if (endlReplacement.equals(ENDL)) { - return formatter.format(format, args); - } else { - String newFormat = buildNewFormat(format); - Object[] newArgs = buildNewArgs(args); - return formatter.format(newFormat, newArgs); - } + public Formatter format(String format, Object... args) { + if (endlReplacement.equals(ENDL)) { + return formatter.format(format, args); + } else { + String newFormat = buildNewFormat(format); + Object[] newArgs = buildNewArgs(args); + return formatter.format(newFormat, newArgs); } + } - public String buildNewFormat(String format) { - return format.replaceAll("\\R", endlReplacement); - } + public String buildNewFormat(String format) { + return format.replaceAll("\\R", endlReplacement); + } - public Object[] buildNewArgs(Object[] args) { - Object[] newArgs = new Object[args.length]; - for (int i = 0; i < args.length; i++) { - newArgs[i] = args[i] instanceof String - ? ((String) args[i]).replaceAll("\\R", endlReplacement) - : args[i]; - } - return newArgs; + public Object[] buildNewArgs(Object[] args) { + Object[] newArgs = new Object[args.length]; + for (int i = 0; i < args.length; i++) { + newArgs[i] = + args[i] instanceof String + ? ((String) args[i]).replaceAll("\\R", endlReplacement) + : args[i]; } + return newArgs; + } } diff --git a/kernel/src/main/java/org/kframework/utils/InterrupterRunnable.java b/kernel/src/main/java/org/kframework/utils/InterrupterRunnable.java index 9e31a10780b..7b758a2c9c4 100644 --- a/kernel/src/main/java/org/kframework/utils/InterrupterRunnable.java +++ b/kernel/src/main/java/org/kframework/utils/InterrupterRunnable.java @@ -2,20 +2,20 @@ package org.kframework.utils; /** - * A runnable that interrupts the given thread when invoked, then awaits termination for the given wait time, in ms. + * A runnable that interrupts the given thread when invoked, then awaits termination for the given + * wait time, in ms. * - * @author Denis Bogdanas - * Created on 24-Dec-18. + * @author Denis Bogdanas Created on 24-Dec-18. */ public record InterrupterRunnable(Thread thread, long waitTimeMillis) implements Runnable { - @Override - public void run() { - thread.interrupt(); - try { - thread.join(waitTimeMillis); - } catch (InterruptedException e) { - e.printStackTrace(); - } + @Override + public void run() { + thread.interrupt(); + try { + thread.join(waitTimeMillis); + } catch (InterruptedException e) { + e.printStackTrace(); } + } } diff --git a/kernel/src/main/java/org/kframework/utils/RunProcess.java b/kernel/src/main/java/org/kframework/utils/RunProcess.java index 204d70fb350..9cd82eb58bb 100644 --- a/kernel/src/main/java/org/kframework/utils/RunProcess.java +++ b/kernel/src/main/java/org/kframework/utils/RunProcess.java @@ -1,80 +1,80 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; -import org.kframework.utils.errorsystem.KEMException; - -import org.apache.commons.io.IOUtils; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.util.Map; import java.util.function.Supplier; +import org.apache.commons.io.IOUtils; +import org.kframework.utils.errorsystem.KEMException; // instantiate processes public class RunProcess { - /** - * Returns a thread that pipes all incoming data from {@param in} to {@param out}. - * @param in A function that returns the input stream to be piped to {@param out} - * @param out The output stream to pipe data to. - * @return A {@link Thread} that will pipe all data from {@param in} to {@param out} until EOF is reached. - */ - public static Thread getOutputStreamThread(Supplier in, PrintStream out) { - return new Thread(() -> { - try { - IOUtils.copy(in.get(), out); - } catch (IOException ignored) {} - }); - } - - public record ProcessOutput(byte[] stdout, byte[] stderr, int exitCode) { - } - - private RunProcess() {} - - public static ProcessOutput execute(Map environment, ProcessBuilder pb, String... commands) { - try { - if (commands.length <= 0) { - throw KEMException.criticalError("Need command options to run"); - } - - // create process - pb = pb.command(commands); - Map realEnvironment = pb.environment(); - realEnvironment.putAll(environment); - - // start process - Process process = pb.start(); - - ByteArrayOutputStream out, err; - PrintStream outWriter, errWriter; - out = new ByteArrayOutputStream(); - err = new ByteArrayOutputStream(); - outWriter = new PrintStream(out); - errWriter = new PrintStream(err); - - Thread outThread = getOutputStreamThread(process::getInputStream, outWriter); - Thread errThread = getOutputStreamThread(process::getErrorStream, errWriter); - - outThread.start(); - errThread.start(); - - // wait for process to finish - process.waitFor(); - - outThread.join(); - errThread.join(); - outWriter.flush(); - errWriter.flush(); - - return new ProcessOutput(out.toByteArray(), err.toByteArray(), process.exitValue()); - - } catch (IOException | InterruptedException e) { - throw KEMException.criticalError("Error while running process:" + e.getMessage(), e); - } - + /** + * Returns a thread that pipes all incoming data from {@param in} to {@param out}. + * + * @param in A function that returns the input stream to be piped to {@param out} + * @param out The output stream to pipe data to. + * @return A {@link Thread} that will pipe all data from {@param in} to {@param out} until EOF is + * reached. + */ + public static Thread getOutputStreamThread(Supplier in, PrintStream out) { + return new Thread( + () -> { + try { + IOUtils.copy(in.get(), out); + } catch (IOException ignored) { + } + }); + } + + public record ProcessOutput(byte[] stdout, byte[] stderr, int exitCode) {} + + private RunProcess() {} + + public static ProcessOutput execute( + Map environment, ProcessBuilder pb, String... commands) { + try { + if (commands.length <= 0) { + throw KEMException.criticalError("Need command options to run"); + } + + // create process + pb = pb.command(commands); + Map realEnvironment = pb.environment(); + realEnvironment.putAll(environment); + + // start process + Process process = pb.start(); + + ByteArrayOutputStream out, err; + PrintStream outWriter, errWriter; + out = new ByteArrayOutputStream(); + err = new ByteArrayOutputStream(); + outWriter = new PrintStream(out); + errWriter = new PrintStream(err); + + Thread outThread = getOutputStreamThread(process::getInputStream, outWriter); + Thread errThread = getOutputStreamThread(process::getErrorStream, errWriter); + + outThread.start(); + errThread.start(); + + // wait for process to finish + process.waitFor(); + + outThread.join(); + errThread.join(); + outWriter.flush(); + errWriter.flush(); + + return new ProcessOutput(out.toByteArray(), err.toByteArray(), process.exitValue()); + + } catch (IOException | InterruptedException e) { + throw KEMException.criticalError("Error while running process:" + e.getMessage(), e); } - + } } diff --git a/kernel/src/main/java/org/kframework/utils/Stopwatch.java b/kernel/src/main/java/org/kframework/utils/Stopwatch.java index f0d295ab8b7..ecebd58df8c 100644 --- a/kernel/src/main/java/org/kframework/utils/Stopwatch.java +++ b/kernel/src/main/java/org/kframework/utils/Stopwatch.java @@ -1,61 +1,56 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; -import org.kframework.main.GlobalOptions; -import org.kframework.utils.inject.RequestScoped; - import com.google.inject.Inject; import java.util.Formatter; +import org.kframework.main.GlobalOptions; +import org.kframework.utils.inject.RequestScoped; -/** - * To use, access {@link #instance()} after calling {@link #init(GlobalOptions) init()}. - */ +/** To use, access {@link #instance()} after calling {@link #init(GlobalOptions) init()}. */ @RequestScoped public class Stopwatch { - private final long start; - private long lastIntermediate; - Formatter f = new Formatter(System.out); - private final GlobalOptions options; - - @Inject - public Stopwatch(GlobalOptions options) { - this.options = options != null ? options : new GlobalOptions(); - start = System.currentTimeMillis(); - lastIntermediate = start; - } - - public void start() { - printIntermediate("Init"); - } - - public void printIntermediate(String message) { - long current = System.currentTimeMillis(); - if (options.verbose) - f.format("%-60s = %s%n", message, milisecondsToTime(current - lastIntermediate)); - lastIntermediate = current; - } - - public void printTotal(String message) { - printIntermediate("Cleanup"); - if (options.verbose) - f.format("%-60s = %s%n", message, milisecondsToTime(lastIntermediate - start)); - } - - private static String milisecondsToTime(long miliseconds) { - long h = miliseconds / 3600000; - long m = miliseconds % 3600000 / 60000; - double s = miliseconds % 60000 / 1000.; - if (h > 0) - return String.format("%dh %02dm %02ds", h, m, (long) s); - if (m > 0) - return String.format("%02dm %02ds", m, (long) s); - return String.format("%6.3fs", s); - } - - public long getIntermediateMilliseconds() { - long endd = System.currentTimeMillis(); - long rez = lastIntermediate - endd; - lastIntermediate = endd; - return rez; - } + private final long start; + private long lastIntermediate; + Formatter f = new Formatter(System.out); + private final GlobalOptions options; + + @Inject + public Stopwatch(GlobalOptions options) { + this.options = options != null ? options : new GlobalOptions(); + start = System.currentTimeMillis(); + lastIntermediate = start; + } + + public void start() { + printIntermediate("Init"); + } + + public void printIntermediate(String message) { + long current = System.currentTimeMillis(); + if (options.verbose) + f.format("%-60s = %s%n", message, milisecondsToTime(current - lastIntermediate)); + lastIntermediate = current; + } + + public void printTotal(String message) { + printIntermediate("Cleanup"); + if (options.verbose) + f.format("%-60s = %s%n", message, milisecondsToTime(lastIntermediate - start)); + } + + private static String milisecondsToTime(long miliseconds) { + long h = miliseconds / 3600000; + long m = miliseconds % 3600000 / 60000; + double s = miliseconds % 60000 / 1000.; + if (h > 0) return String.format("%dh %02dm %02ds", h, m, (long) s); + if (m > 0) return String.format("%02dm %02ds", m, (long) s); + return String.format("%6.3fs", s); + } + + public long getIntermediateMilliseconds() { + long endd = System.currentTimeMillis(); + long rez = lastIntermediate - endd; + lastIntermediate = endd; + return rez; + } } diff --git a/kernel/src/main/java/org/kframework/utils/errorsystem/KExceptionManager.java b/kernel/src/main/java/org/kframework/utils/errorsystem/KExceptionManager.java index 96afe4b6f2a..ac3643e5506 100644 --- a/kernel/src/main/java/org/kframework/utils/errorsystem/KExceptionManager.java +++ b/kernel/src/main/java/org/kframework/utils/errorsystem/KExceptionManager.java @@ -2,6 +2,12 @@ package org.kframework.utils.errorsystem; import com.google.inject.Inject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Set; import org.kframework.attributes.HasLocation; import org.kframework.attributes.Location; import org.kframework.attributes.Source; @@ -11,159 +17,204 @@ import org.kframework.utils.errorsystem.KException.KExceptionGroup; import org.kframework.utils.inject.RequestScoped; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; - @RequestScoped public class KExceptionManager { - private final List exceptions = Collections.synchronizedList(new ArrayList<>()); - - public final GlobalOptions options; - - @Inject - public KExceptionManager(GlobalOptions options) { - this.options = options; - } - - public void installForUncaughtExceptions() { - Thread.setDefaultUncaughtExceptionHandler((t, e) -> { - String message = "Uncaught exception thrown of type " + e.getClass().getSimpleName(); - if (!options.debug()) { - message += ".\nPlease rerun your program with the --debug flag to generate a stack trace, " - + "and file a bug report at https://github.com/runtimeverification/k/issues"; - } - exceptions.add(new KException(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, e)); - print(); + private final List exceptions = Collections.synchronizedList(new ArrayList<>()); + + public final GlobalOptions options; + + @Inject + public KExceptionManager(GlobalOptions options) { + this.options = options; + } + + public void installForUncaughtExceptions() { + Thread.setDefaultUncaughtExceptionHandler( + (t, e) -> { + String message = "Uncaught exception thrown of type " + e.getClass().getSimpleName(); + if (!options.debug()) { + message += + ".\nPlease rerun your program with the --debug flag to generate a stack trace, " + + "and file a bug report at https://github.com/runtimeverification/k/issues"; + } + exceptions.add(new KException(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, e)); + print(); }); - } - - private void printStackTrace(KException e) { - if (e.getException() != null && - (options.debugWarnings || (options.debug() && e.getType() == ExceptionType.ERROR))) { - e.getException().printStackTrace(); - } - } - - public void addKException(KException e) { - registerInternal(e, false); - } - - public void addAllKException(Collection kex) { - for (KException e : kex) - registerInternal(e, false); - } - - public void registerCompilerWarning(ExceptionType type, String message) { - register(type, KExceptionGroup.COMPILER, message, null, null, null); - } - - public void registerCompilerWarning(ExceptionType type, Set errors, String message, HasLocation node) { - register(errors, type, KExceptionGroup.COMPILER, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public void registerCompilerWarning(ExceptionType type, String message, HasLocation node) { - register(type, KExceptionGroup.COMPILER, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public void registerCriticalWarning(ExceptionType type, String message) { - register(type, KExceptionGroup.CRITICAL, message, null, null, null); - } - - public void registerCriticalWarning(ExceptionType type, String message, Throwable e) { - register(type, KExceptionGroup.CRITICAL, message, e, null, null); - } - - public void registerCriticalWarning(ExceptionType type, String message, HasLocation node) { - register(type, KExceptionGroup.CRITICAL, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public void registerInternalWarning(ExceptionType type, String message) { - register(type, KExceptionGroup.INTERNAL, message, null, null, null); - } - - public void registerInternalWarning(ExceptionType type, String message, HasLocation node) { - register(type, KExceptionGroup.INTERNAL, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public void registerInternalWarning(ExceptionType type, String message, Throwable e) { - register(type, KExceptionGroup.INTERNAL, message, e, null, null); - } - - public void registerOuterParserWarning(ExceptionType type, String message, Throwable e, Source source, Location location) { - register(type, KExceptionGroup.OUTER_PARSER, message, e, location, source); - } - - public void registerInnerParserWarning(ExceptionType type, String message) { - register(type, KExceptionGroup.INNER_PARSER, message, null, null, null); - } - - private void register(ExceptionType type, KExceptionGroup group, String message, - Throwable e, Location location, Source source) { - registerInternal(new KException(type, group, message, source, location, e), true); - } - - private void register(Set errors, ExceptionType type, KExceptionGroup group, String message, - Throwable e, Location location, Source source) { - if (!options.includesExceptionType(type)) - return; - KException exception = new KException(type, group, message, source, location, e); - if (exception.type == ExceptionType.ERROR || options.warnings2errors) { - errors.add(new KEMException(exception, ExceptionType.ERROR)); - } else { - registerInternal(exception, false); - } - } - - - private void registerInternal(KException exception, boolean _throw) { - if (!options.includesExceptionType(exception.type)) - return; - if (_throw && (exception.type == ExceptionType.ERROR || options.warnings2errors)) { - throw new KEMException(exception, ExceptionType.ERROR); - } else if (options.warnings2errors) { - exceptions.add(new KException(ExceptionType.ERROR, exception.exceptionGroup, exception.getMessage(), exception.getSource(), exception.getLocation(), exception.getException())); - } else { - exceptions.add(exception); - } - } - - public void print() { - Collections.sort(exceptions, - Comparator.comparing(KException::getSource, Comparator.nullsLast(Comparator.naturalOrder())) + } + + private void printStackTrace(KException e) { + if (e.getException() != null + && (options.debugWarnings || (options.debug() && e.getType() == ExceptionType.ERROR))) { + e.getException().printStackTrace(); + } + } + + public void addKException(KException e) { + registerInternal(e, false); + } + + public void addAllKException(Collection kex) { + for (KException e : kex) registerInternal(e, false); + } + + public void registerCompilerWarning(ExceptionType type, String message) { + register(type, KExceptionGroup.COMPILER, message, null, null, null); + } + + public void registerCompilerWarning( + ExceptionType type, Set errors, String message, HasLocation node) { + register( + errors, + type, + KExceptionGroup.COMPILER, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public void registerCompilerWarning(ExceptionType type, String message, HasLocation node) { + register( + type, + KExceptionGroup.COMPILER, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public void registerCriticalWarning(ExceptionType type, String message) { + register(type, KExceptionGroup.CRITICAL, message, null, null, null); + } + + public void registerCriticalWarning(ExceptionType type, String message, Throwable e) { + register(type, KExceptionGroup.CRITICAL, message, e, null, null); + } + + public void registerCriticalWarning(ExceptionType type, String message, HasLocation node) { + register( + type, + KExceptionGroup.CRITICAL, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public void registerInternalWarning(ExceptionType type, String message) { + register(type, KExceptionGroup.INTERNAL, message, null, null, null); + } + + public void registerInternalWarning(ExceptionType type, String message, HasLocation node) { + register( + type, + KExceptionGroup.INTERNAL, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public void registerInternalWarning(ExceptionType type, String message, Throwable e) { + register(type, KExceptionGroup.INTERNAL, message, e, null, null); + } + + public void registerOuterParserWarning( + ExceptionType type, String message, Throwable e, Source source, Location location) { + register(type, KExceptionGroup.OUTER_PARSER, message, e, location, source); + } + + public void registerInnerParserWarning(ExceptionType type, String message) { + register(type, KExceptionGroup.INNER_PARSER, message, null, null, null); + } + + private void register( + ExceptionType type, + KExceptionGroup group, + String message, + Throwable e, + Location location, + Source source) { + registerInternal(new KException(type, group, message, source, location, e), true); + } + + private void register( + Set errors, + ExceptionType type, + KExceptionGroup group, + String message, + Throwable e, + Location location, + Source source) { + if (!options.includesExceptionType(type)) return; + KException exception = new KException(type, group, message, source, location, e); + if (exception.type == ExceptionType.ERROR || options.warnings2errors) { + errors.add(new KEMException(exception, ExceptionType.ERROR)); + } else { + registerInternal(exception, false); + } + } + + private void registerInternal(KException exception, boolean _throw) { + if (!options.includesExceptionType(exception.type)) return; + if (_throw && (exception.type == ExceptionType.ERROR || options.warnings2errors)) { + throw new KEMException(exception, ExceptionType.ERROR); + } else if (options.warnings2errors) { + exceptions.add( + new KException( + ExceptionType.ERROR, + exception.exceptionGroup, + exception.getMessage(), + exception.getSource(), + exception.getLocation(), + exception.getException())); + } else { + exceptions.add(exception); + } + } + + public void print() { + Collections.sort( + exceptions, + Comparator.comparing(KException::getSource, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(KException::getLocation, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(e -> e.toString(options.verbose))); - KException last = null; - synchronized (exceptions) { - for (KException e : exceptions) { - if (last != null && last.toString(options.verbose).equals(e.toString(options.verbose))) { - continue; - } - printStackTrace(e); - String msg = options.noExcWrap ? e.toString(options.verbose) - : StringUtil.splitLines(e.toString(options.verbose)); - System.err.println(msg); - last = e; - } - exceptions.clear(); - } - } - - public void registerThrown(KEMException e) { - KException exception = e.exception; - if (!options.includesExceptionType(exception.type)) - return; - if (options.warnings2errors) { - exceptions.add(new KException(ExceptionType.ERROR, exception.exceptionGroup, exception.getMessage(), exception.getSource(), exception.getLocation(), exception.getException())); - } else { - exceptions.add(exception); + KException last = null; + synchronized (exceptions) { + for (KException e : exceptions) { + if (last != null && last.toString(options.verbose).equals(e.toString(options.verbose))) { + continue; } - } - - public List getExceptions() { - return exceptions; - } + printStackTrace(e); + String msg = + options.noExcWrap + ? e.toString(options.verbose) + : StringUtil.splitLines(e.toString(options.verbose)); + System.err.println(msg); + last = e; + } + exceptions.clear(); + } + } + + public void registerThrown(KEMException e) { + KException exception = e.exception; + if (!options.includesExceptionType(exception.type)) return; + if (options.warnings2errors) { + exceptions.add( + new KException( + ExceptionType.ERROR, + exception.exceptionGroup, + exception.getMessage(), + exception.getSource(), + exception.getLocation(), + exception.getException())); + } else { + exceptions.add(exception); + } + } + + public List getExceptions() { + return exceptions; + } } diff --git a/kernel/src/main/java/org/kframework/utils/file/DefinitionDir.java b/kernel/src/main/java/org/kframework/utils/file/DefinitionDir.java index 0da1a7c2a9c..ea0140f6c2f 100644 --- a/kernel/src/main/java/org/kframework/utils/file/DefinitionDir.java +++ b/kernel/src/main/java/org/kframework/utils/file/DefinitionDir.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.file; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface DefinitionDir {} diff --git a/kernel/src/main/java/org/kframework/utils/file/Environment.java b/kernel/src/main/java/org/kframework/utils/file/Environment.java index 055503f2240..4c27ba82865 100644 --- a/kernel/src/main/java/org/kframework/utils/file/Environment.java +++ b/kernel/src/main/java/org/kframework/utils/file/Environment.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.file; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface Environment {} diff --git a/kernel/src/main/java/org/kframework/utils/file/FileUtil.java b/kernel/src/main/java/org/kframework/utils/file/FileUtil.java index 49c5514c3cd..57ee63a0b0b 100644 --- a/kernel/src/main/java/org/kframework/utils/file/FileUtil.java +++ b/kernel/src/main/java/org/kframework/utils/file/FileUtil.java @@ -2,19 +2,6 @@ package org.kframework.utils.file; import com.google.inject.Inject; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.io.IOUtils; -import org.apache.commons.io.input.BoundedInputStream; -import org.apache.commons.lang3.tuple.Pair; -import org.kframework.attributes.Location; -import org.kframework.main.GlobalOptions; -import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.errorsystem.KException.ExceptionType; -import org.kframework.utils.errorsystem.KExceptionManager; -import org.kframework.utils.inject.RequestScoped; - -import javax.annotation.Nullable; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -35,286 +22,298 @@ import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.BoundedInputStream; +import org.apache.commons.lang3.tuple.Pair; +import org.kframework.attributes.Location; +import org.kframework.main.GlobalOptions; +import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.errorsystem.KException.ExceptionType; +import org.kframework.utils.errorsystem.KExceptionManager; +import org.kframework.utils.inject.RequestScoped; @RequestScoped public class FileUtil { - private final File tempDir; - private final File kompiledDir; - private final File workingDir; - private final GlobalOptions options; - private final Map env; - - @Inject - public FileUtil( - @TempDir File tempDir, - @WorkingDir File workingDir, - @KompiledDir @Nullable File kompiledDir, - GlobalOptions options, - @Environment Map env) { - this.tempDir = tempDir; - this.workingDir = workingDir; - this.kompiledDir = kompiledDir; - this.options = options; - this.env = env; - } - - public static FileUtil testFileUtil() { - File workingDir = new File("."); - return new FileUtil(workingDir, workingDir, workingDir, new GlobalOptions(), System.getenv()); - } - - public ProcessBuilder getProcessBuilder() { - ProcessBuilder pb = new ProcessBuilder().directory(workingDir); - pb.environment().clear(); - pb.environment().putAll(env); - return pb; - } - - public Map getEnv() { - return env; - } - - public void deleteTempDir(KExceptionManager kem) { - if (!options.debug()) { - try { - FileUtils.deleteDirectory(tempDir); - } catch (IOException e) { - kem.registerCriticalWarning(ExceptionType.UNDELETED_TEMP_DIR, "Failed to delete temporary directory", e); - } - } - } - - /** - * Get language name in uppercase (main module name) given the filename of definition. - */ - public static String getMainModule(String filename) { - return FilenameUtils.getBaseName(filename).toUpperCase(); - } - - // generate an unique name for a folder with the name dirName - public static String generateUniqueFolderName(String dirName) { - DateFormat df = new SimpleDateFormat("-yyyy-MM-dd-HH-mm-ss-SSS-"); - Date today = Calendar.getInstance().getTime(); - String reportDate = df.format(today); - return dirName + reportDate + UUID.randomUUID(); - } - - /** - * Loads the properties from the given file into the given Properties object. - */ - public static void loadProperties(Properties properties, Class cls, String resourcePath) throws IOException { - try (InputStream inStream = cls.getResourceAsStream(resourcePath)) { - if (inStream == null) { - throw new IOException("Could not find resource " + resourcePath); - } - properties.load(inStream); - } - } - - public void saveToDefinitionDirectory(String file, String content) { - save(resolveDefinitionDirectory(file), content); - } - - public String loadFromWorkingDirectory(String file) { - return load(resolveWorkingDirectory(file)); - } - - public void saveToWorkingDirectory(String file, String content) { - save(resolveWorkingDirectory(file), content); - } - - public void saveToWorkingDirectory(String file, byte[] content) { - save(resolveWorkingDirectory(file), content); - } - - public String loadFromKompiled(String file) { - return load(resolveKompiled(file)); - } - - public void saveToKompiled(String file, String content) { - save(resolveKompiled(file), content); - } - - public String loadFromTemp(String file) { - return load(resolveTemp(file)); - } - - public byte[] loadBytesFromTemp(String file) { - return loadBytes(resolveTemp(file)); - } - - public void saveToTemp(String file, String content) { - save(resolveTemp(file), content); - } - - public void saveToTemp(String file, byte[] content) { - save(resolveTemp(file), content); - } - - public String loadFromKIncludeDir(String file) { - return load(resolveKInclude(file)); - } - - public File resolveTemp(String file) { - if (!tempDir.exists() && !tempDir.mkdirs()) { - throw KEMException.criticalError("Could not create temporary directory " + tempDir); - } - return new File(tempDir, file); - } - - public File resolveKompiled(String file) { - return new File(kompiledDir, file); - } - - public File resolveDefinitionDirectory(String file) { - return kompiledDir == null ? null : new File(kompiledDir.getParentFile(), file); - } - - public File resolveWorkingDirectory(String file) { - return resolveWorkingDirectory(new File(file)); - } - - public File resolveWorkingDirectory(File file) { - if (file.isAbsolute()) return file; - return new File(workingDir, file.getPath()); - } - - public File resolveKInclude(String file) { - return new File(JarInfo.getKIncludeDir().toFile(), file); - } - - // don't use this if you want a file in the include directory. Use resolveKInclude. - public File resolveKBase(String file) { - return new File(JarInfo.getKBase(), file); - } - - public void copyTempFileToDefinitionDirectory(String fromPath) { - copyFileToDirectory(resolveTemp(fromPath), resolveDefinitionDirectory(".")); - } - - public void copyTempFileToKompiledDirectory(String fromPath) { - copyFileToDirectory(resolveTemp(fromPath), resolveKompiled(".")); - } - - public void copyTempFileToKompiledFile(String fromPath, String toPath) { - copyFile(resolveTemp(fromPath), resolveKompiled(toPath)); - } - - private void copyFile(File from, File to) { - try { - FileUtils.copyFile(from, to); - } catch (IOException e) { - throw KEMException.criticalError("Could not copy " + from + " to " + to, e); - } - } - - public void copyFileToDirectory(File from, File toDir) { - try { - FileUtils.copyFileToDirectory(from, toDir); - } catch (IOException e) { - throw KEMException.criticalError("Could not copy " + from + " to directory " + toDir, e); - } - } - - public static void save(File file, String content) { - try { - File dir = file.getAbsoluteFile().getParentFile(); - if (!dir.exists() && !dir.mkdirs()) { - throw KEMException.criticalError("Could not create directory " + dir); - } - FileUtils.writeStringToFile(file, content); - } catch (IOException e) { - throw KEMException.criticalError("Could not write to file " + file.getAbsolutePath(), e); - } - } - - public static void save(File file, byte[] content) { - try { - File dir = file.getAbsoluteFile().getParentFile(); - if (!dir.exists() && !dir.mkdirs()) { - throw KEMException.criticalError("Could not create directory " + dir); - } - FileUtils.writeByteArrayToFile(file, content); - } catch (IOException e) { - throw KEMException.criticalError("Could not write to file " + file.getAbsolutePath(), e); - } - } - - public static String load(File file) { - try { - return FileUtils.readFileToString(file); - } catch (IOException e) { - throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); - } - } - - /** - * Loads the given fragment of a file to String. - *

- * Source: https://stackoverflow.com/a/4305478/4182868 - */ - public static String loadFragment(File file, int pos, int len) { - try (FileInputStream stream = new FileInputStream(file)) { - stream.skip(pos); - return IOUtils.toString(new BoundedInputStream(stream, len)); - } catch (IOException e) { - throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); - } - } - - public static String loadFragment(File file, Location location) { - try (Stream lines = new BufferedReader(new InputStreamReader(new FileInputStream(file))).lines() - .skip(location.startLine() - 1) - .limit(location.endLine() - location.startLine() + 1)) { - return lines.collect(Collectors.joining("\n")); - } catch (IOException e) { - throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); - } - } - - public static byte[] loadBytes(File file) { - try { - return FileUtils.readFileToByteArray(file); - } catch (IOException e) { - throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); - } - } - - public static Pair pipeOutputToInput() { - try { - PipedOutputStream out = new PipedOutputStream(); - PipedInputStream in = new PipedInputStream(out); - return Pair.of(in, out); - } catch (IOException e) { - throw KEMException.internalError("Error creating input/output pipe", e); - } - } - - public static Pair pipeInputToOutput() { - try { - PipedInputStream in = new PipedInputStream(); - PipedOutputStream out = new PipedOutputStream(in); - return Pair.of(out, in); - } catch (IOException e) { - throw KEMException.internalError("Error creating input/output pipe", e); - } - } - - public static String read(Reader reader) { - try { - return IOUtils.toString(reader); - } catch (IOException e) { - throw KEMException.internalError("Error reading from " + reader, e); - } - } - - public Reader readFromWorkingDirectory(String path) { - File f = resolveWorkingDirectory(path); - try { - return new FileReader(f); - } catch (FileNotFoundException e) { - throw KEMException.criticalError("Could not read from file " + f.getAbsolutePath(), e); - } - } + private final File tempDir; + private final File kompiledDir; + private final File workingDir; + private final GlobalOptions options; + private final Map env; + + @Inject + public FileUtil( + @TempDir File tempDir, + @WorkingDir File workingDir, + @KompiledDir @Nullable File kompiledDir, + GlobalOptions options, + @Environment Map env) { + this.tempDir = tempDir; + this.workingDir = workingDir; + this.kompiledDir = kompiledDir; + this.options = options; + this.env = env; + } + + public static FileUtil testFileUtil() { + File workingDir = new File("."); + return new FileUtil(workingDir, workingDir, workingDir, new GlobalOptions(), System.getenv()); + } + + public ProcessBuilder getProcessBuilder() { + ProcessBuilder pb = new ProcessBuilder().directory(workingDir); + pb.environment().clear(); + pb.environment().putAll(env); + return pb; + } + + public Map getEnv() { + return env; + } + + public void deleteTempDir(KExceptionManager kem) { + if (!options.debug()) { + try { + FileUtils.deleteDirectory(tempDir); + } catch (IOException e) { + kem.registerCriticalWarning( + ExceptionType.UNDELETED_TEMP_DIR, "Failed to delete temporary directory", e); + } + } + } + + /** Get language name in uppercase (main module name) given the filename of definition. */ + public static String getMainModule(String filename) { + return FilenameUtils.getBaseName(filename).toUpperCase(); + } + + // generate an unique name for a folder with the name dirName + public static String generateUniqueFolderName(String dirName) { + DateFormat df = new SimpleDateFormat("-yyyy-MM-dd-HH-mm-ss-SSS-"); + Date today = Calendar.getInstance().getTime(); + String reportDate = df.format(today); + return dirName + reportDate + UUID.randomUUID(); + } + + /** Loads the properties from the given file into the given Properties object. */ + public static void loadProperties(Properties properties, Class cls, String resourcePath) + throws IOException { + try (InputStream inStream = cls.getResourceAsStream(resourcePath)) { + if (inStream == null) { + throw new IOException("Could not find resource " + resourcePath); + } + properties.load(inStream); + } + } + + public void saveToDefinitionDirectory(String file, String content) { + save(resolveDefinitionDirectory(file), content); + } + + public String loadFromWorkingDirectory(String file) { + return load(resolveWorkingDirectory(file)); + } + + public void saveToWorkingDirectory(String file, String content) { + save(resolveWorkingDirectory(file), content); + } + + public void saveToWorkingDirectory(String file, byte[] content) { + save(resolveWorkingDirectory(file), content); + } + + public String loadFromKompiled(String file) { + return load(resolveKompiled(file)); + } + + public void saveToKompiled(String file, String content) { + save(resolveKompiled(file), content); + } + + public String loadFromTemp(String file) { + return load(resolveTemp(file)); + } + + public byte[] loadBytesFromTemp(String file) { + return loadBytes(resolveTemp(file)); + } + + public void saveToTemp(String file, String content) { + save(resolveTemp(file), content); + } + + public void saveToTemp(String file, byte[] content) { + save(resolveTemp(file), content); + } + + public String loadFromKIncludeDir(String file) { + return load(resolveKInclude(file)); + } + + public File resolveTemp(String file) { + if (!tempDir.exists() && !tempDir.mkdirs()) { + throw KEMException.criticalError("Could not create temporary directory " + tempDir); + } + return new File(tempDir, file); + } + + public File resolveKompiled(String file) { + return new File(kompiledDir, file); + } + + public File resolveDefinitionDirectory(String file) { + return kompiledDir == null ? null : new File(kompiledDir.getParentFile(), file); + } + + public File resolveWorkingDirectory(String file) { + return resolveWorkingDirectory(new File(file)); + } + + public File resolveWorkingDirectory(File file) { + if (file.isAbsolute()) return file; + return new File(workingDir, file.getPath()); + } + + public File resolveKInclude(String file) { + return new File(JarInfo.getKIncludeDir().toFile(), file); + } + + // don't use this if you want a file in the include directory. Use resolveKInclude. + public File resolveKBase(String file) { + return new File(JarInfo.getKBase(), file); + } + + public void copyTempFileToDefinitionDirectory(String fromPath) { + copyFileToDirectory(resolveTemp(fromPath), resolveDefinitionDirectory(".")); + } + + public void copyTempFileToKompiledDirectory(String fromPath) { + copyFileToDirectory(resolveTemp(fromPath), resolveKompiled(".")); + } + + public void copyTempFileToKompiledFile(String fromPath, String toPath) { + copyFile(resolveTemp(fromPath), resolveKompiled(toPath)); + } + + private void copyFile(File from, File to) { + try { + FileUtils.copyFile(from, to); + } catch (IOException e) { + throw KEMException.criticalError("Could not copy " + from + " to " + to, e); + } + } + + public void copyFileToDirectory(File from, File toDir) { + try { + FileUtils.copyFileToDirectory(from, toDir); + } catch (IOException e) { + throw KEMException.criticalError("Could not copy " + from + " to directory " + toDir, e); + } + } + + public static void save(File file, String content) { + try { + File dir = file.getAbsoluteFile().getParentFile(); + if (!dir.exists() && !dir.mkdirs()) { + throw KEMException.criticalError("Could not create directory " + dir); + } + FileUtils.writeStringToFile(file, content); + } catch (IOException e) { + throw KEMException.criticalError("Could not write to file " + file.getAbsolutePath(), e); + } + } + + public static void save(File file, byte[] content) { + try { + File dir = file.getAbsoluteFile().getParentFile(); + if (!dir.exists() && !dir.mkdirs()) { + throw KEMException.criticalError("Could not create directory " + dir); + } + FileUtils.writeByteArrayToFile(file, content); + } catch (IOException e) { + throw KEMException.criticalError("Could not write to file " + file.getAbsolutePath(), e); + } + } + + public static String load(File file) { + try { + return FileUtils.readFileToString(file); + } catch (IOException e) { + throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); + } + } + + /** + * Loads the given fragment of a file to String. + * + *

Source: https://stackoverflow.com/a/4305478/4182868 + */ + public static String loadFragment(File file, int pos, int len) { + try (FileInputStream stream = new FileInputStream(file)) { + stream.skip(pos); + return IOUtils.toString(new BoundedInputStream(stream, len)); + } catch (IOException e) { + throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); + } + } + + public static String loadFragment(File file, Location location) { + try (Stream lines = + new BufferedReader(new InputStreamReader(new FileInputStream(file))) + .lines() + .skip(location.startLine() - 1) + .limit(location.endLine() - location.startLine() + 1)) { + return lines.collect(Collectors.joining("\n")); + } catch (IOException e) { + throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); + } + } + + public static byte[] loadBytes(File file) { + try { + return FileUtils.readFileToByteArray(file); + } catch (IOException e) { + throw KEMException.criticalError("Could not read from file " + file.getAbsolutePath(), e); + } + } + + public static Pair pipeOutputToInput() { + try { + PipedOutputStream out = new PipedOutputStream(); + PipedInputStream in = new PipedInputStream(out); + return Pair.of(in, out); + } catch (IOException e) { + throw KEMException.internalError("Error creating input/output pipe", e); + } + } + + public static Pair pipeInputToOutput() { + try { + PipedInputStream in = new PipedInputStream(); + PipedOutputStream out = new PipedOutputStream(in); + return Pair.of(out, in); + } catch (IOException e) { + throw KEMException.internalError("Error creating input/output pipe", e); + } + } + + public static String read(Reader reader) { + try { + return IOUtils.toString(reader); + } catch (IOException e) { + throw KEMException.internalError("Error reading from " + reader, e); + } + } + + public Reader readFromWorkingDirectory(String path) { + File f = resolveWorkingDirectory(path); + try { + return new FileReader(f); + } catch (FileNotFoundException e) { + throw KEMException.criticalError("Could not read from file " + f.getAbsolutePath(), e); + } + } } diff --git a/kernel/src/main/java/org/kframework/utils/file/JarInfo.java b/kernel/src/main/java/org/kframework/utils/file/JarInfo.java index b3b58d0b1bd..418ebcf343c 100644 --- a/kernel/src/main/java/org/kframework/utils/file/JarInfo.java +++ b/kernel/src/main/java/org/kframework/utils/file/JarInfo.java @@ -1,93 +1,98 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.file; -import org.apache.commons.io.FileUtils; - -import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.errorsystem.KExceptionManager; - import com.google.inject.Inject; - import java.io.File; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.*; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Date; import java.util.jar.Manifest; +import org.apache.commons.io.FileUtils; +import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.errorsystem.KExceptionManager; public class JarInfo { - private static final String JAR_PATH = "k-distribution/target/release/k/lib/kframework/java/JAR_FILENAME_PLACEHOLDER.jar"; + private static final String JAR_PATH = + "k-distribution/target/release/k/lib/kframework/java/JAR_FILENAME_PLACEHOLDER.jar"; - /** - * Returns the K installation directory - * - * @return The path to the K installation - */ - public static String getKBase() { - // String env = System.getenv("K_BASE"); - String path = new File(JarInfo.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getAbsolutePath(); - if (!path.endsWith(".jar") || new File(path).getParentFile().getName().equals("target")) - path = new File(path).getParentFile().getParentFile().getParentFile().getAbsolutePath() + "/" + JAR_PATH; - String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8); - File parent = new File(decodedPath).getParentFile().getParentFile().getParentFile().getParentFile(); - return parent.getAbsolutePath(); - } + /** + * Returns the K installation directory + * + * @return The path to the K installation + */ + public static String getKBase() { + // String env = System.getenv("K_BASE"); + String path = + new File(JarInfo.class.getProtectionDomain().getCodeSource().getLocation().getPath()) + .getAbsolutePath(); + if (!path.endsWith(".jar") || new File(path).getParentFile().getName().equals("target")) + path = + new File(path).getParentFile().getParentFile().getParentFile().getAbsolutePath() + + "/" + + JAR_PATH; + String decodedPath = URLDecoder.decode(path, StandardCharsets.UTF_8); + File parent = + new File(decodedPath).getParentFile().getParentFile().getParentFile().getParentFile(); + return parent.getAbsolutePath(); + } - /** - * Returns the absolute path of the includes directory. - * Paths are computed relative to the location this class is running from. - * When it is run from a jar file it assumes it is in a k installation - * at lib/java/*.jar. - * When it is run from a .class file it assumes it is running within the - * K source project, from a class in kernel/target/classes/, and - * returns a path to k-distribution/include - * - * @return - */ - public static Path getKIncludeDir() { - Path path; - try { - path = Paths.get(JarInfo.class.getProtectionDomain().getCodeSource().getLocation().toURI()); - } catch (URISyntaxException e) { - return null; - } - if (!path.toFile().getAbsolutePath().endsWith(".jar") || path.getParent().getFileName().toString().equals("target")) { - return path.getParent().resolve("../../k-distribution/include/kframework"); - } else { - return path.getParent().resolve("../../../include/kframework"); - } + /** + * Returns the absolute path of the includes directory. Paths are computed relative to the + * location this class is running from. When it is run from a jar file it assumes it is in a k + * installation at lib/java/*.jar. When it is run from a .class file it assumes it is running + * within the K source project, from a class in kernel/target/classes/, and returns a path to + * k-distribution/include + * + * @return + */ + public static Path getKIncludeDir() { + Path path; + try { + path = Paths.get(JarInfo.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + } catch (URISyntaxException e) { + return null; + } + if (!path.toFile().getAbsolutePath().endsWith(".jar") + || path.getParent().getFileName().toString().equals("target")) { + return path.getParent().resolve("../../k-distribution/include/kframework"); + } else { + return path.getParent().resolve("../../../include/kframework"); } + } - private final KExceptionManager kem; + private final KExceptionManager kem; - @Inject - public JarInfo(KExceptionManager kem) { - this.kem = kem; - } + @Inject + public JarInfo(KExceptionManager kem) { + this.kem = kem; + } - public void printVersionMessage() { - String kBase = getKBase(); - URL url = JarInfo.class.getResource("versionMarker"); - try { - URLConnection conn = url.openConnection(); - Manifest mf = ((JarURLConnection)conn).getManifest(); + public void printVersionMessage() { + String kBase = getKBase(); + URL url = JarInfo.class.getResource("versionMarker"); + try { + URLConnection conn = url.openConnection(); + Manifest mf = ((JarURLConnection) conn).getManifest(); - String versionDate = new Date(Long.parseLong(mf.getMainAttributes().getValue("Implementation-Date"))).toString(); + String versionDate = + new Date(Long.parseLong(mf.getMainAttributes().getValue("Implementation-Date"))) + .toString(); - // Use the output of 'git describe' if we're building K from a Git repository, or fall back to - // the release version if we're not (e.g. from a release tarball). - String version = mf.getMainAttributes().getValue("Implementation-Git-Describe"); - if (version.isEmpty()) { - version = "v" + FileUtils.readFileToString(new File(kBase + "/lib/kframework/version")).trim(); - } + // Use the output of 'git describe' if we're building K from a Git repository, or fall back to + // the release version if we're not (e.g. from a release tarball). + String version = mf.getMainAttributes().getValue("Implementation-Git-Describe"); + if (version.isEmpty()) { + version = + "v" + FileUtils.readFileToString(new File(kBase + "/lib/kframework/version")).trim(); + } - System.out.println("K version: " + version); - System.out.println("Build date: " + versionDate); - } catch (IOException e) { - throw KEMException.internalError("Could not load version info."); - } + System.out.println("K version: " + version); + System.out.println("Build date: " + versionDate); + } catch (IOException e) { + throw KEMException.internalError("Could not load version info."); } + } } diff --git a/kernel/src/main/java/org/kframework/utils/file/KompiledDir.java b/kernel/src/main/java/org/kframework/utils/file/KompiledDir.java index 1727b5b79a0..a1fba22b674 100644 --- a/kernel/src/main/java/org/kframework/utils/file/KompiledDir.java +++ b/kernel/src/main/java/org/kframework/utils/file/KompiledDir.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.file; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface KompiledDir {} diff --git a/kernel/src/main/java/org/kframework/utils/file/TTYInfo.java b/kernel/src/main/java/org/kframework/utils/file/TTYInfo.java index c0a9f6cc016..a0fc3e2ead9 100644 --- a/kernel/src/main/java/org/kframework/utils/file/TTYInfo.java +++ b/kernel/src/main/java/org/kframework/utils/file/TTYInfo.java @@ -2,10 +2,9 @@ package org.kframework.utils.file; /** - * Encapsulates information about whether stdin, stdout, and stderr are - * connected to terminals. Essentially, each boolean in this class is - * true if and only if the corresponding stream is one for which - * ultimately the isatty function returns true. + * Encapsulates information about whether stdin, stdout, and stderr are connected to terminals. + * Essentially, each boolean in this class is true if and only if the corresponding stream is one + * for which ultimately the isatty function returns true. * * @author dwightguth */ diff --git a/kernel/src/main/java/org/kframework/utils/file/TempDir.java b/kernel/src/main/java/org/kframework/utils/file/TempDir.java index 3795db45a43..84531c112ae 100644 --- a/kernel/src/main/java/org/kframework/utils/file/TempDir.java +++ b/kernel/src/main/java/org/kframework/utils/file/TempDir.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.file; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface TempDir {} diff --git a/kernel/src/main/java/org/kframework/utils/file/WorkingDir.java b/kernel/src/main/java/org/kframework/utils/file/WorkingDir.java index 9e0702672f8..f22a7461d6c 100644 --- a/kernel/src/main/java/org/kframework/utils/file/WorkingDir.java +++ b/kernel/src/main/java/org/kframework/utils/file/WorkingDir.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.file; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface WorkingDir {} diff --git a/kernel/src/main/java/org/kframework/utils/inject/Annotations.java b/kernel/src/main/java/org/kframework/utils/inject/Annotations.java index 585dfa0012b..364282bf226 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/Annotations.java +++ b/kernel/src/main/java/org/kframework/utils/inject/Annotations.java @@ -5,87 +5,84 @@ public class Annotations { - public static Main main(Class annotation) { - return new Main() { - - @Override - public Class annotationType() { - return Main.class; - } - - @Override - public Class value() { - return annotation; - } - - public int hashCode() { - // This is specified in java.lang.Annotation. - return (127 * "value".hashCode()) ^ annotation.hashCode(); - } - - public boolean equals(Object o) { - if (!(o instanceof Main other)) { - return false; - } - return annotation.equals(other.value()); - } - - }; - } - - public static Spec1 spec1(Class annotation) { - return new Spec1() { - - @Override - public Class annotationType() { - return Spec1.class; - } - - @Override - public Class value() { - return annotation; - } - - public int hashCode() { - // This is specified in java.lang.Annotation. - return (127 * "value".hashCode()) ^ annotation.hashCode(); - } - - public boolean equals(Object o) { - if (!(o instanceof Spec1 other)) { - return false; - } - return annotation.equals(other.value()); - } - - }; - } - - public static Spec2 spec2(Class annotation) { - return new Spec2() { - - @Override - public Class annotationType() { - return Spec2.class; - } - - @Override - public Class value() { - return annotation; - } - - public int hashCode() { - // This is specified in java.lang.Annotation. - return (127 * "value".hashCode()) ^ annotation.hashCode(); - } - - public boolean equals(Object o) { - if (!(o instanceof Spec2 other)) { - return false; - } - return annotation.equals(other.value()); - } - - }; - } + public static Main main(Class annotation) { + return new Main() { + + @Override + public Class annotationType() { + return Main.class; + } + + @Override + public Class value() { + return annotation; + } + + public int hashCode() { + // This is specified in java.lang.Annotation. + return (127 * "value".hashCode()) ^ annotation.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof Main other)) { + return false; + } + return annotation.equals(other.value()); + } + }; + } + + public static Spec1 spec1(Class annotation) { + return new Spec1() { + + @Override + public Class annotationType() { + return Spec1.class; + } + + @Override + public Class value() { + return annotation; + } + + public int hashCode() { + // This is specified in java.lang.Annotation. + return (127 * "value".hashCode()) ^ annotation.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof Spec1 other)) { + return false; + } + return annotation.equals(other.value()); + } + }; + } + + public static Spec2 spec2(Class annotation) { + return new Spec2() { + + @Override + public Class annotationType() { + return Spec2.class; + } + + @Override + public Class value() { + return annotation; + } + + public int hashCode() { + // This is specified in java.lang.Annotation. + return (127 * "value".hashCode()) ^ annotation.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof Spec2 other)) { + return false; + } + return annotation.equals(other.value()); + } + }; + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/Builtins.java b/kernel/src/main/java/org/kframework/utils/inject/Builtins.java index cf10a7f1022..de7c3188d7f 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/Builtins.java +++ b/kernel/src/main/java/org/kframework/utils/inject/Builtins.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface Builtins {} diff --git a/kernel/src/main/java/org/kframework/utils/inject/CommonModule.java b/kernel/src/main/java/org/kframework/utils/inject/CommonModule.java index bb1a47f6d2c..ea40ba31302 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/CommonModule.java +++ b/kernel/src/main/java/org/kframework/utils/inject/CommonModule.java @@ -1,10 +1,14 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; +import static org.fusesource.jansi.internal.CLibrary.*; + import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; +import java.io.File; +import java.util.Map; import org.kframework.main.GlobalOptions; import org.kframework.main.Tool; import org.kframework.utils.file.Environment; @@ -13,61 +17,67 @@ import org.kframework.utils.file.TempDir; import org.kframework.utils.file.WorkingDir; -import java.io.File; -import java.util.Map; +public class CommonModule extends AbstractModule { -import static org.fusesource.jansi.internal.CLibrary.*; + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + SimpleScope requestScope = new SimpleScope(); + bindScope(RequestScoped.class, requestScope); + DefinitionScope definitionScope = new DefinitionScope(); + bindScope(DefinitionScoped.class, definitionScope); + bind(SimpleScope.class).annotatedWith(Names.named("requestScope")).toInstance(requestScope); + bind(DefinitionScope.class).toInstance(definitionScope); + bind(File.class) + .annotatedWith(WorkingDir.class) + .toProvider(SimpleScope.seededKeyProvider()) + .in(RequestScoped.class); + bind(new TypeLiteral>() {}) + .annotatedWith(Environment.class) + .toProvider(SimpleScope.seededKeyProvider()) + .in(RequestScoped.class); + bind(Long.class) + .annotatedWith(StartTime.class) + .toProvider(SimpleScope.seededKeyProvider()) + .in(RequestScoped.class); + } -public class CommonModule extends AbstractModule { + @Provides + @TempDir + @RequestScoped + File tempDir(Tool tool, GlobalOptions go) { + if (go.tempDir != null) + return new File( + go.tempDir, FileUtil.generateUniqueFolderName("." + tool.name().toLowerCase())); + return new File( + System.getProperty("java.io.tmpdir"), + FileUtil.generateUniqueFolderName("." + tool.name().toLowerCase())); + } - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - SimpleScope requestScope = new SimpleScope(); - bindScope(RequestScoped.class, requestScope); - DefinitionScope definitionScope = new DefinitionScope(); - bindScope(DefinitionScoped.class, definitionScope); - bind(SimpleScope.class).annotatedWith(Names.named("requestScope")).toInstance(requestScope); - bind(DefinitionScope.class).toInstance(definitionScope); - bind(File.class).annotatedWith(WorkingDir.class) - .toProvider(SimpleScope.seededKeyProvider()).in(RequestScoped.class); - bind(new TypeLiteral>() {}).annotatedWith(Environment.class) - .toProvider(SimpleScope.seededKeyProvider()).in(RequestScoped.class); - bind(Long.class).annotatedWith(StartTime.class) - .toProvider(SimpleScope.seededKeyProvider()).in(RequestScoped.class); - } + @Provides + ProcessBuilder pb(@WorkingDir File workingDir, @Environment Map env) { + return new FileUtil(null, workingDir, null, null, env).getProcessBuilder(); + } - @Provides @TempDir @RequestScoped - File tempDir(Tool tool, GlobalOptions go) { - if (go.tempDir != null) - return new File(go.tempDir, FileUtil.generateUniqueFolderName("." + tool.name().toLowerCase())); - return new File(System.getProperty("java.io.tmpdir"), FileUtil.generateUniqueFolderName("." + tool.name().toLowerCase())); + @Provides + @RequestScoped + TTYInfo ttyInfo(@Environment Map env) { + boolean stdin, stdout, stderr; + if (env.containsKey("NAILGUN_TTY_0")) { + stdin = !env.get("NAILGUN_TTY_0").equals("0"); + } else { + stdin = isatty(0) != 0; } - - @Provides - ProcessBuilder pb(@WorkingDir File workingDir, @Environment Map env) { - return new FileUtil(null, workingDir, null, null, env).getProcessBuilder(); + if (env.containsKey("NAILGUN_TTY_1")) { + stdout = !env.get("NAILGUN_TTY_1").equals("0"); + } else { + stdout = isatty(1) != 0; } - - @Provides @RequestScoped - TTYInfo ttyInfo(@Environment Map env) { - boolean stdin, stdout, stderr; - if (env.containsKey("NAILGUN_TTY_0")) { - stdin = !env.get("NAILGUN_TTY_0").equals("0"); - } else { - stdin = isatty(0) != 0; - } - if (env.containsKey("NAILGUN_TTY_1")) { - stdout = !env.get("NAILGUN_TTY_1").equals("0"); - } else { - stdout = isatty(1) != 0; - } - if (env.containsKey("NAILGUN_TTY_2")) { - stderr = !env.get("NAILGUN_TTY_2").equals("0"); - } else { - stderr = isatty(2) != 0; - } - return new TTYInfo(stdin, stdout, stderr); + if (env.containsKey("NAILGUN_TTY_2")) { + stderr = !env.get("NAILGUN_TTY_2").equals("0"); + } else { + stderr = isatty(2) != 0; } - + return new TTYInfo(stdin, stdout, stderr); + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/Concrete.java b/kernel/src/main/java/org/kframework/utils/inject/Concrete.java index 7aad03e5728..bbcb74290be 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/Concrete.java +++ b/kernel/src/main/java/org/kframework/utils/inject/Concrete.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface Concrete {} diff --git a/kernel/src/main/java/org/kframework/utils/inject/DefinitionLoadingModule.java b/kernel/src/main/java/org/kframework/utils/inject/DefinitionLoadingModule.java index 9f3f60084de..b003e200e0c 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/DefinitionLoadingModule.java +++ b/kernel/src/main/java/org/kframework/utils/inject/DefinitionLoadingModule.java @@ -1,115 +1,124 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; +import static org.kframework.utils.errorsystem.KException.ExceptionType.*; + import com.google.inject.AbstractModule; import com.google.inject.Provider; import com.google.inject.Provides; +import java.io.File; +import java.util.Map; import org.kframework.kompile.CompiledDefinition; import org.kframework.kompile.KompileOptions; import org.kframework.main.GlobalOptions; import org.kframework.utils.BinaryLoader; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KExceptionManager; -import org.kframework.utils.file.DefinitionDir; import org.kframework.utils.file.Environment; import org.kframework.utils.file.FileUtil; import org.kframework.utils.file.KompiledDir; import org.kframework.utils.file.WorkingDir; import org.kframework.utils.options.DefinitionLoadingOptions; -import java.io.File; -import java.io.FilenameFilter; -import java.util.Map; - -import static org.kframework.utils.errorsystem.KException.ExceptionType.*; - public class DefinitionLoadingModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - } + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + } - @Provides @DefinitionScoped - CompiledDefinition koreDefinition(BinaryLoader loader, FileUtil files) { - return loader.loadOrDie(CompiledDefinition.class, files.resolveKompiled("compiled.bin")); - } + @Provides + @DefinitionScoped + CompiledDefinition koreDefinition(BinaryLoader loader, FileUtil files) { + return loader.loadOrDie(CompiledDefinition.class, files.resolveKompiled("compiled.bin")); + } + @Provides + @RequestScoped + KompileOptions kompileOptions(Provider compiledDef) { + // a hack, but it's good enough for what we need from it, which is a temporary solution + KompileOptions res = compiledDef.get().kompileOptions; + return res; + } - @Provides @RequestScoped - KompileOptions kompileOptions(Provider compiledDef) { - // a hack, but it's good enough for what we need from it, which is a temporary solution - KompileOptions res = compiledDef.get().kompileOptions; - return res; - } - - @Provides @KompiledDir - File directory(DefinitionLoadingOptions options, @WorkingDir File workingDir, @Environment Map env) { - File directory = null; - if (options.inputDirectory != null) { - if (options.directory != null) - throw KEMException.criticalError("Cannot use both --directory and --definition at the same time."); - File f = new File(options.inputDirectory); - if (f.isAbsolute()) { - directory = f; - } else { - directory = new File(workingDir, options.inputDirectory); - } - } else if (env.get("KRUN_KOMPILED_DIR") != null) { - File f = new File(env.get("KRUN_KOMPILED_DIR")); - if (f.isAbsolute()) { - directory = f; - } else { - directory = new File(workingDir, env.get("KRUN_KOMPILED_DIR")); - } + @Provides + @KompiledDir + File directory( + DefinitionLoadingOptions options, + @WorkingDir File workingDir, + @Environment Map env) { + File directory = null; + if (options.inputDirectory != null) { + if (options.directory != null) + throw KEMException.criticalError( + "Cannot use both --directory and --definition at the same time."); + File f = new File(options.inputDirectory); + if (f.isAbsolute()) { + directory = f; + } else { + directory = new File(workingDir, options.inputDirectory); + } + } else if (env.get("KRUN_KOMPILED_DIR") != null) { + File f = new File(env.get("KRUN_KOMPILED_DIR")); + if (f.isAbsolute()) { + directory = f; + } else { + directory = new File(workingDir, env.get("KRUN_KOMPILED_DIR")); + } + } else { + File whereDir; + if (options.directory == null) { + if (env.get("KRUN_COMPILED_DEF") != null) { + File f = new File(env.get("KRUN_COMPILED_DEF")); + if (f.isAbsolute()) { + whereDir = f; + } else { + whereDir = new File(workingDir, env.get("KRUN_COMPILED_DEF")); + } } else { - File whereDir; - if (options.directory == null) { - if (env.get("KRUN_COMPILED_DEF") != null) { - File f = new File(env.get("KRUN_COMPILED_DEF")); - if (f.isAbsolute()) { - whereDir = f; - } else { - whereDir = new File(workingDir, env.get("KRUN_COMPILED_DEF")); - } - } else { - whereDir = workingDir; - } - } else { - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - kem.registerCriticalWarning(DEPRECATED_DIRECTORY_FLAG, "Using --directory is deprecated. Use --output-definition instead."); - kem.print(); - File f = new File(options.directory); - if (f.isAbsolute()) { - whereDir = f; - } else { - whereDir = new File(workingDir, options.directory); - } - } - File[] dirs = whereDir.listFiles((current, name) -> new File(current, name).isDirectory()); - - if (dirs != null) { - for (File dir : dirs) { - if (dir.getAbsolutePath().endsWith("-kompiled")) { - if (directory != null) { - throw KEMException.criticalError("Multiple compiled definitions found in the " - + "current working directory: " + directory.getAbsolutePath() + " and " + - dir.getAbsolutePath()); - } else { - directory = dir; - } - } - } - } + whereDir = workingDir; + } + } else { + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + kem.registerCriticalWarning( + DEPRECATED_DIRECTORY_FLAG, + "Using --directory is deprecated. Use --output-definition instead."); + kem.print(); + File f = new File(options.directory); + if (f.isAbsolute()) { + whereDir = f; + } else { + whereDir = new File(workingDir, options.directory); + } + } + File[] dirs = whereDir.listFiles((current, name) -> new File(current, name).isDirectory()); - if (directory == null) { - throw KEMException.criticalError("Could not find a compiled definition. " + - "Use --definition to specify one."); + if (dirs != null) { + for (File dir : dirs) { + if (dir.getAbsolutePath().endsWith("-kompiled")) { + if (directory != null) { + throw KEMException.criticalError( + "Multiple compiled definitions found in the " + + "current working directory: " + + directory.getAbsolutePath() + + " and " + + dir.getAbsolutePath()); + } else { + directory = dir; } + } } - if (!directory.isDirectory()) { - throw KEMException.criticalError("Does not exist or not a directory: " + directory.getAbsolutePath()); - } - return directory; + } + + if (directory == null) { + throw KEMException.criticalError( + "Could not find a compiled definition. " + "Use --definition to specify one."); + } + } + if (!directory.isDirectory()) { + throw KEMException.criticalError( + "Does not exist or not a directory: " + directory.getAbsolutePath()); } + return directory; + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/DefinitionScope.java b/kernel/src/main/java/org/kframework/utils/inject/DefinitionScope.java index 101a57145d9..35466b1c34c 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/DefinitionScope.java +++ b/kernel/src/main/java/org/kframework/utils/inject/DefinitionScope.java @@ -3,76 +3,74 @@ import static com.google.common.base.Preconditions.checkState; -import java.io.File; -import java.util.LinkedHashMap; -import java.util.Map; - import com.google.common.collect.Maps; import com.google.inject.Key; import com.google.inject.OutOfScopeException; import com.google.inject.Provider; import com.google.inject.Scope; import com.google.inject.Scopes; +import java.io.File; +import java.util.LinkedHashMap; +import java.util.Map; public class DefinitionScope implements Scope { - private final InheritableThreadLocal currentDefinitionId = new InheritableThreadLocal<>(); + private final InheritableThreadLocal currentDefinitionId = new InheritableThreadLocal<>(); - private final LinkedHashMap, Object>> values = new LinkedHashMap, Object>>() { + private final LinkedHashMap, Object>> values = + new LinkedHashMap, Object>>() { protected boolean removeEldestEntry(Map.Entry, Object>> eldest) { - return size() > Runtime.getRuntime().availableProcessors() * 2; + return size() > Runtime.getRuntime().availableProcessors() * 2; } - }; - - public void enter(File definitionId) { - checkState(currentDefinitionId.get() == null, "A scoping block is already in progress"); - currentDefinitionId.set(definitionId); - } + }; - public void exit() { - checkState(currentDefinitionId.get() != null, "No scoping block in progress"); - currentDefinitionId.remove(); - } + public void enter(File definitionId) { + checkState(currentDefinitionId.get() == null, "A scoping block is already in progress"); + currentDefinitionId.set(definitionId); + } - @Override - public Provider scope(Key key, Provider unscoped) { - return new Provider() { - public T get() { - Map, Object> scopedObjects = getScopedObjectMap(key); + public void exit() { + checkState(currentDefinitionId.get() != null, "No scoping block in progress"); + currentDefinitionId.remove(); + } - synchronized(scopedObjects) { - @SuppressWarnings("unchecked") - T current = (T) scopedObjects.get(key); - if (current == null && !scopedObjects.containsKey(key)) { - current = unscoped.get(); + @Override + public Provider scope(Key key, Provider unscoped) { + return new Provider() { + public T get() { + Map, Object> scopedObjects = getScopedObjectMap(key); - // don't remember proxies; these exist only to serve circular dependencies - if (Scopes.isCircularProxy(current)) { - return current; - } + synchronized (scopedObjects) { + @SuppressWarnings("unchecked") + T current = (T) scopedObjects.get(key); + if (current == null && !scopedObjects.containsKey(key)) { + current = unscoped.get(); - scopedObjects.put(key, current); - } - return current; - } + // don't remember proxies; these exist only to serve circular dependencies + if (Scopes.isCircularProxy(current)) { + return current; } - }; - } - private Map, Object> getScopedObjectMap(Key key) { - File definitionId = currentDefinitionId.get(); - if (definitionId == null) { - throw new OutOfScopeException("Cannot access " + key - + " outside of a scoping block"); - } - synchronized(values) { - Map, Object> scopedObjects = values.get(definitionId); - if (scopedObjects == null) { - scopedObjects = Maps.newHashMap(); - values.put(definitionId, scopedObjects); - } - return scopedObjects; + scopedObjects.put(key, current); + } + return current; } } + }; + } + private Map, Object> getScopedObjectMap(Key key) { + File definitionId = currentDefinitionId.get(); + if (definitionId == null) { + throw new OutOfScopeException("Cannot access " + key + " outside of a scoping block"); + } + synchronized (values) { + Map, Object> scopedObjects = values.get(definitionId); + if (scopedObjects == null) { + scopedObjects = Maps.newHashMap(); + values.put(definitionId, scopedObjects); + } + return scopedObjects; + } + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/DefinitionScoped.java b/kernel/src/main/java/org/kframework/utils/inject/DefinitionScoped.java index f2ac29226d1..459a301a660 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/DefinitionScoped.java +++ b/kernel/src/main/java/org/kframework/utils/inject/DefinitionScoped.java @@ -3,14 +3,13 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; - import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.Target; - import com.google.inject.ScopeAnnotation; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; -@Target({ TYPE, METHOD }) @Retention(RUNTIME) @ScopeAnnotation +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +@ScopeAnnotation public @interface DefinitionScoped {} diff --git a/kernel/src/main/java/org/kframework/utils/inject/GraphInjector.java b/kernel/src/main/java/org/kframework/utils/inject/GraphInjector.java index b1f6b8383d4..a31dff0f33d 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/GraphInjector.java +++ b/kernel/src/main/java/org/kframework/utils/inject/GraphInjector.java @@ -1,34 +1,32 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.grapher.graphviz.GraphvizGrapher; +import com.google.inject.grapher.graphviz.GraphvizModule; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.Arrays; - -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.grapher.graphviz.GraphvizGrapher; -import com.google.inject.grapher.graphviz.GraphvizModule; - import org.kframework.main.Main; public class GraphInjector { - public static void main(String[] args) throws IOException { - String[] args2 = Arrays.copyOfRange(args, 1, args.length); - Injector injector = Main.getInjector(args[0]); - graph("injector.dot", injector); - } + public static void main(String[] args) throws IOException { + String[] args2 = Arrays.copyOfRange(args, 1, args.length); + Injector injector = Main.getInjector(args[0]); + graph("injector.dot", injector); + } - private static void graph(String filename, Injector demoInjector) throws IOException { - PrintWriter out = new PrintWriter(new File(filename), StandardCharsets.UTF_8); + private static void graph(String filename, Injector demoInjector) throws IOException { + PrintWriter out = new PrintWriter(new File(filename), StandardCharsets.UTF_8); - Injector injector = Guice.createInjector(new GraphvizModule()); - GraphvizGrapher grapher = injector.getInstance(GraphvizGrapher.class); - grapher.setOut(out); - grapher.setRankdir("TB"); - grapher.graph(demoInjector); - } + Injector injector = Guice.createInjector(new GraphvizModule()); + GraphvizGrapher grapher = injector.getInstance(GraphvizGrapher.class); + grapher.setOut(out); + grapher.setRankdir("TB"); + grapher.graph(demoInjector); + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/JCommanderModule.java b/kernel/src/main/java/org/kframework/utils/inject/JCommanderModule.java index a8d4693ddc1..9d4b7978b4d 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/JCommanderModule.java +++ b/kernel/src/main/java/org/kframework/utils/inject/JCommanderModule.java @@ -6,76 +6,86 @@ import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.beust.jcommander.JCommander; +import com.beust.jcommander.ParameterException; +import com.beust.jcommander.internal.Console; +import com.google.inject.AbstractModule; +import com.google.inject.BindingAnnotation; +import com.google.inject.Provides; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.Set; - import org.kframework.kompile.KompileUsageFormatter; import org.kframework.main.Tool; import org.kframework.utils.Stopwatch; -import org.kframework.utils.StringUtil; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KExceptionManager; -import com.beust.jcommander.internal.Console; -import com.beust.jcommander.JCommander; -import com.beust.jcommander.ParameterException; -import com.google.inject.AbstractModule; -import com.google.inject.BindingAnnotation; -import com.google.inject.Provides; +public class JCommanderModule extends AbstractModule { -public class JCommanderModule extends AbstractModule { + @BindingAnnotation + @Target({FIELD, PARAMETER, METHOD}) + @Retention(RUNTIME) + public @interface Usage {} - @BindingAnnotation @Target({FIELD, PARAMETER, METHOD}) @Retention(RUNTIME) - public @interface Usage {} + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(String[].class) + .annotatedWith(Options.class) + .toProvider(SimpleScope.seededKeyProvider()) + .in(RequestScoped.class); + } - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(String[].class).annotatedWith(Options.class) - .toProvider(SimpleScope.seededKeyProvider()).in(RequestScoped.class); + @Provides + @RequestScoped + JCommander jcommander( + @Options String[] args, + Tool tool, + @Options Set options, + KExceptionManager kem, + Stopwatch sw) { + try { + JCommander jc = new JCommander(options.toArray(new Object[options.size()]), args); + jc.setProgramName(tool.name().toLowerCase()); + jc.setUsageFormatter(new KompileUsageFormatter(jc)); + sw.printIntermediate("Parse command line options"); + return jc; + } catch (ParameterException e) { + throw KEMException.criticalError(e.getMessage()); } + } - @Provides @RequestScoped - JCommander jcommander(@Options String[] args, Tool tool, @Options Set options, KExceptionManager kem, Stopwatch sw) { - try { - JCommander jc = new JCommander(options.toArray(new Object[options.size()]), args); - jc.setProgramName(tool.name().toLowerCase()); - jc.setUsageFormatter(new KompileUsageFormatter(jc)); - sw.printIntermediate("Parse command line options"); - return jc; - } catch (ParameterException e) { - throw KEMException.criticalError(e.getMessage()); - } - } - - void usage(JCommander jc, StringBuilder sb) { - Console defaultConsole = jc.getConsole(); - jc.setConsole(new Console() { - @Override - public void print(String msg) { - sb.append(msg); - } + void usage(JCommander jc, StringBuilder sb) { + Console defaultConsole = jc.getConsole(); + jc.setConsole( + new Console() { + @Override + public void print(String msg) { + sb.append(msg); + } - @Override - public void println(String msg) { - sb.append(msg).append('\n'); - } + @Override + public void println(String msg) { + sb.append(msg).append('\n'); + } - @Override - public char[] readPassword(boolean echoInput) { - return defaultConsole.readPassword(echoInput); - } + @Override + public char[] readPassword(boolean echoInput) { + return defaultConsole.readPassword(echoInput); + } }); - jc.usage(); - jc.setConsole(defaultConsole); - } + jc.usage(); + jc.setConsole(defaultConsole); + } - @Provides @Usage @RequestScoped - String usage(JCommander jc) { - StringBuilder sb = new StringBuilder(); - usage(jc, sb); - //for some reason the usage pattern indents commands inconsistently, so we need to adjust it - return sb.toString().replaceAll(" ", " "); - } + @Provides + @Usage + @RequestScoped + String usage(JCommander jc) { + StringBuilder sb = new StringBuilder(); + usage(jc, sb); + // for some reason the usage pattern indents commands inconsistently, so we need to adjust it + return sb.toString().replaceAll(" ", " "); + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/Main.java b/kernel/src/main/java/org/kframework/utils/inject/Main.java index 493268625f7..d05b74cf5dd 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/Main.java +++ b/kernel/src/main/java/org/kframework/utils/inject/Main.java @@ -1,18 +1,19 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface Main { - Class value() default Main.class; + Class value() default Main.class; } diff --git a/kernel/src/main/java/org/kframework/utils/inject/Options.java b/kernel/src/main/java/org/kframework/utils/inject/Options.java index d61a708ed2f..21c39d72ac2 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/Options.java +++ b/kernel/src/main/java/org/kframework/utils/inject/Options.java @@ -1,15 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; -import static java.lang.annotation.RetentionPolicy.RUNTIME; -import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import com.google.inject.BindingAnnotation; import java.lang.annotation.Retention; import java.lang.annotation.Target; -import com.google.inject.BindingAnnotation; - -@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) +@BindingAnnotation +@Target({FIELD, PARAMETER, METHOD}) +@Retention(RUNTIME) public @interface Options {} diff --git a/kernel/src/main/java/org/kframework/utils/inject/OuterParsingModule.java b/kernel/src/main/java/org/kframework/utils/inject/OuterParsingModule.java index cdb86466444..d35d7618580 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/OuterParsingModule.java +++ b/kernel/src/main/java/org/kframework/utils/inject/OuterParsingModule.java @@ -1,8 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; +import static org.kframework.utils.errorsystem.KException.ExceptionType.*; + import com.google.inject.AbstractModule; import com.google.inject.Provides; +import java.io.File; import org.apache.commons.io.FilenameUtils; import org.kframework.main.GlobalOptions; import org.kframework.utils.errorsystem.KEMException; @@ -14,48 +17,60 @@ import org.kframework.utils.options.OuterParsingOptions; import org.kframework.utils.options.OutputDirectoryOptions; -import java.io.File; - -import static org.kframework.utils.errorsystem.KException.ExceptionType.*; - /** - * Provides the information needed for tools that parse definitions from source to have access to {@link FileUtil}. + * Provides the information needed for tools that parse definitions from source to have access to + * {@link FileUtil}. * - * Used currently by kompile, and kdep. + *

Used currently by kompile, and kdep. */ public class OuterParsingModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - } + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + } - @Provides - @DefinitionDir - File definitionDir(@KompiledDir File kDir) { - return kDir.getParentFile(); - } + @Provides + @DefinitionDir + File definitionDir(@KompiledDir File kDir) { + return kDir.getParentFile(); + } - @Provides @KompiledDir - File kompiledDir(OuterParsingOptions options, @WorkingDir File workingDir, OutputDirectoryOptions output) { - if (output.outputDirectory != null) { - if (output.directory != null) - throw KEMException.criticalError("Cannot use both --directory and --output-definition at the same time."); - File f = new File(output.outputDirectory); - if (f.isAbsolute()) - return f; - return new File(workingDir, output.outputDirectory); - } else if (output.directory != null) { - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - kem.registerCompilerWarning(DEPRECATED_DIRECTORY_FLAG, "The --directory option is deprecated. Please use --output-definition instead."); - kem.print(); - File f = new File(output.directory); - if (!f.isAbsolute()) - f = new File(workingDir, output.directory).getAbsoluteFile(); + @Provides + @KompiledDir + File kompiledDir( + OuterParsingOptions options, @WorkingDir File workingDir, OutputDirectoryOptions output) { + if (output.outputDirectory != null) { + if (output.directory != null) + throw KEMException.criticalError( + "Cannot use both --directory and --output-definition at the same time."); + File f = new File(output.outputDirectory); + if (f.isAbsolute()) return f; + return new File(workingDir, output.outputDirectory); + } else if (output.directory != null) { + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + kem.registerCompilerWarning( + DEPRECATED_DIRECTORY_FLAG, + "The --directory option is deprecated. Please use --output-definition instead."); + kem.print(); + File f = new File(output.directory); + if (!f.isAbsolute()) f = new File(workingDir, output.directory).getAbsoluteFile(); - return new File(f,FilenameUtils.removeExtension(options.mainDefinitionFile(new FileUtil(null, workingDir, null, null, null)).getName()) + "-kompiled"); - } - // bootstrap the part of FileUtil we need - return new File(workingDir, FilenameUtils.removeExtension(options.mainDefinitionFile(new FileUtil(null, workingDir, null, null, null)).getName()) + "-kompiled"); + return new File( + f, + FilenameUtils.removeExtension( + options + .mainDefinitionFile(new FileUtil(null, workingDir, null, null, null)) + .getName()) + + "-kompiled"); } + // bootstrap the part of FileUtil we need + return new File( + workingDir, + FilenameUtils.removeExtension( + options + .mainDefinitionFile(new FileUtil(null, workingDir, null, null, null)) + .getName()) + + "-kompiled"); + } } diff --git a/kernel/src/main/java/org/kframework/utils/inject/RequestScoped.java b/kernel/src/main/java/org/kframework/utils/inject/RequestScoped.java index 19ebe46e5fd..fc921c7156e 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/RequestScoped.java +++ b/kernel/src/main/java/org/kframework/utils/inject/RequestScoped.java @@ -3,14 +3,13 @@ import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; - -import java.lang.annotation.Retention; - import static java.lang.annotation.RetentionPolicy.RUNTIME; -import java.lang.annotation.Target; - import com.google.inject.ScopeAnnotation; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; -@Target({ TYPE, METHOD }) @Retention(RUNTIME) @ScopeAnnotation +@Target({TYPE, METHOD}) +@Retention(RUNTIME) +@ScopeAnnotation public @interface RequestScoped {} diff --git a/kernel/src/main/java/org/kframework/utils/inject/SimpleScope.java b/kernel/src/main/java/org/kframework/utils/inject/SimpleScope.java index 7555a85ade8..359744339b2 100644 --- a/kernel/src/main/java/org/kframework/utils/inject/SimpleScope.java +++ b/kernel/src/main/java/org/kframework/utils/inject/SimpleScope.java @@ -10,12 +10,10 @@ import com.google.inject.Provider; import com.google.inject.Scope; import com.google.inject.Scopes; - import java.util.Map; /** - * Scopes a single execution of a block of code. Apply this scope with a - * try/finally block: + * Scopes a single execution of a block of code. Apply this scope with a try/finally block: * *

  * 
@@ -31,12 +29,11 @@
  * 
  * 
* - * The scope can be initialized with one or more seed values by calling - * seed(key, value) before the injector will be called upon to - * provide for this key. A typical use is for a servlet filter to enter/exit the - * scope, representing a Request Scope, and seed HttpServletRequest and - * HttpServletResponse. For each key inserted with seed(), you must include a - * corresponding binding: + * The scope can be initialized with one or more seed values by calling seed(key, value) + * before the injector will be called upon to provide for this key. A typical use is for a + * servlet filter to enter/exit the scope, representing a Request Scope, and seed HttpServletRequest + * and HttpServletResponse. For each key inserted with seed(), you must include a corresponding + * binding: * *
  * 
@@ -51,84 +48,85 @@
  */
 public class SimpleScope implements Scope {
 
-    private static final Provider SEEDED_KEY_PROVIDER = new Provider() {
+  private static final Provider SEEDED_KEY_PROVIDER =
+      new Provider() {
         public Object get() {
-            throw new IllegalStateException(
-                    "If you got here then it means that"
-                            + " your code asked for scoped object which should have been"
-                            + " explicitly seeded in this scope by calling"
-                            + " SimpleScope.seed(), but was not.");
+          throw new IllegalStateException(
+              "If you got here then it means that"
+                  + " your code asked for scoped object which should have been"
+                  + " explicitly seeded in this scope by calling"
+                  + " SimpleScope.seed(), but was not.");
         }
-    };
-    private final InheritableThreadLocal, Object>> values = new InheritableThreadLocal, Object>>();
+      };
+  private final InheritableThreadLocal, Object>> values =
+      new InheritableThreadLocal, Object>>();
 
-    public void enter() {
-        checkState(values.get() == null,
-                "A scoping block is already in progress");
-        values.set(Maps.newHashMap());
-    }
+  public void enter() {
+    checkState(values.get() == null, "A scoping block is already in progress");
+    values.set(Maps.newHashMap());
+  }
 
-    public void exit() {
-        checkState(values.get() != null, "No scoping block in progress");
-        values.remove();
-    }
+  public void exit() {
+    checkState(values.get() != null, "No scoping block in progress");
+    values.remove();
+  }
 
-    public  void seed(Key key, T value) {
-        Map, Object> scopedObjects = getScopedObjectMap(key);
-        checkState(
-                !scopedObjects.containsKey(key),
-                "A value for the key %s was "
-                        + "already seeded in this scope. Old value: %s New value: %s",
-                key, scopedObjects.get(key), value);
-        scopedObjects.put(key, value);
-    }
+  public  void seed(Key key, T value) {
+    Map, Object> scopedObjects = getScopedObjectMap(key);
+    checkState(
+        !scopedObjects.containsKey(key),
+        "A value for the key %s was " + "already seeded in this scope. Old value: %s New value: %s",
+        key,
+        scopedObjects.get(key),
+        value);
+    scopedObjects.put(key, value);
+  }
 
-    public  void seed(Class clazz, T value) {
-        seed(Key.get(clazz), value);
-    }
+  public  void seed(Class clazz, T value) {
+    seed(Key.get(clazz), value);
+  }
 
-    public  Provider scope(final Key key, final Provider unscoped) {
-        return new Provider() {
-            public T get() {
-                Map, Object> scopedObjects = getScopedObjectMap(key);
-
-                synchronized (scopedObjects) {
-                    @SuppressWarnings("unchecked")
-                    T current = (T) scopedObjects.get(key);
-                    if (current == null && !scopedObjects.containsKey(key)) {
-                        current = unscoped.get();
+  public  Provider scope(final Key key, final Provider unscoped) {
+    return new Provider() {
+      public T get() {
+        Map, Object> scopedObjects = getScopedObjectMap(key);
 
-                        // don't remember proxies; these exist only to serve
-                        // circular dependencies
-                        if (Scopes.isCircularProxy(current)) {
-                            return current;
-                        }
+        synchronized (scopedObjects) {
+          @SuppressWarnings("unchecked")
+          T current = (T) scopedObjects.get(key);
+          if (current == null && !scopedObjects.containsKey(key)) {
+            current = unscoped.get();
 
-                        scopedObjects.put(key, current);
-                    }
-                    return current;
-                }
+            // don't remember proxies; these exist only to serve
+            // circular dependencies
+            if (Scopes.isCircularProxy(current)) {
+              return current;
             }
-        };
-    }
 
-    private  Map, Object> getScopedObjectMap(Key key) {
-        Map, Object> scopedObjects = values.get();
-        if (scopedObjects == null) {
-            throw new OutOfScopeException("Cannot access " + key
-                    + " outside of a scoping block");
+            scopedObjects.put(key, current);
+          }
+          return current;
         }
-        return scopedObjects;
-    }
+      }
+    };
+  }
 
-    /**
-     * Returns a provider that always throws exception complaining that the
-     * object in question must be seeded before it can be injected.
-     *
-     * @return typed provider
-     */
-    @SuppressWarnings({ "unchecked" })
-    public static  Provider seededKeyProvider() {
-        return (Provider) SEEDED_KEY_PROVIDER;
+  private  Map, Object> getScopedObjectMap(Key key) {
+    Map, Object> scopedObjects = values.get();
+    if (scopedObjects == null) {
+      throw new OutOfScopeException("Cannot access " + key + " outside of a scoping block");
     }
+    return scopedObjects;
+  }
+
+  /**
+   * Returns a provider that always throws exception complaining that the object in question must be
+   * seeded before it can be injected.
+   *
+   * @return typed provider
+   */
+  @SuppressWarnings({"unchecked"})
+  public static  Provider seededKeyProvider() {
+    return (Provider) SEEDED_KEY_PROVIDER;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/utils/inject/Spec1.java b/kernel/src/main/java/org/kframework/utils/inject/Spec1.java
index 540294df69a..0ac4bff41fa 100644
--- a/kernel/src/main/java/org/kframework/utils/inject/Spec1.java
+++ b/kernel/src/main/java/org/kframework/utils/inject/Spec1.java
@@ -1,16 +1,17 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.utils.inject;
 
-import com.google.inject.BindingAnnotation;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
 
+import com.google.inject.BindingAnnotation;
 import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
+@BindingAnnotation
+@Target({FIELD, PARAMETER, METHOD})
+@Retention(RUNTIME)
 public @interface Spec1 {
-    Class value() default Spec1.class;
+  Class value() default Spec1.class;
 }
diff --git a/kernel/src/main/java/org/kframework/utils/inject/Spec2.java b/kernel/src/main/java/org/kframework/utils/inject/Spec2.java
index 0f87ff7cc4b..044d8843789 100644
--- a/kernel/src/main/java/org/kframework/utils/inject/Spec2.java
+++ b/kernel/src/main/java/org/kframework/utils/inject/Spec2.java
@@ -1,16 +1,17 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.utils.inject;
 
-import com.google.inject.BindingAnnotation;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
 
+import com.google.inject.BindingAnnotation;
 import java.lang.annotation.Annotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
-@BindingAnnotation @Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME)
+@BindingAnnotation
+@Target({FIELD, PARAMETER, METHOD})
+@Retention(RUNTIME)
 public @interface Spec2 {
-    Class value() default Spec2.class;
+  Class value() default Spec2.class;
 }
diff --git a/kernel/src/main/java/org/kframework/utils/inject/StartTime.java b/kernel/src/main/java/org/kframework/utils/inject/StartTime.java
index 937fdb0ac28..d140e00f271 100644
--- a/kernel/src/main/java/org/kframework/utils/inject/StartTime.java
+++ b/kernel/src/main/java/org/kframework/utils/inject/StartTime.java
@@ -1,17 +1,17 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.utils.inject;
 
-import com.google.inject.BindingAnnotation;
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.*;
 
+import com.google.inject.BindingAnnotation;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
-import static java.lang.annotation.ElementType.*;
-import static java.lang.annotation.RetentionPolicy.*;
-
 /**
- * @author Denis Bogdanas
- * Created on 20-Nov-19.
+ * @author Denis Bogdanas Created on 20-Nov-19.
  */
-@BindingAnnotation @Target({FIELD, PARAMETER, METHOD}) @Retention(RUNTIME)
+@BindingAnnotation
+@Target({FIELD, PARAMETER, METHOD})
+@Retention(RUNTIME)
 public @interface StartTime {}
diff --git a/kernel/src/main/java/org/kframework/utils/options/BackendOptions.java b/kernel/src/main/java/org/kframework/utils/options/BackendOptions.java
index 14c57e748d1..ef3ff409909 100644
--- a/kernel/src/main/java/org/kframework/utils/options/BackendOptions.java
+++ b/kernel/src/main/java/org/kframework/utils/options/BackendOptions.java
@@ -2,14 +2,15 @@
 package org.kframework.utils.options;
 
 import com.beust.jcommander.Parameter;
-import com.google.inject.Inject;
-
 import java.io.Serializable;
 
 public class BackendOptions implements Serializable {
 
-    public BackendOptions() {}
+  public BackendOptions() {}
 
-    @Parameter(names="--dry-run", description="Compile program into KORE format but do not run. Only used in Haskell and LLVM backend.")
-    public boolean dryRun = false;
+  @Parameter(
+      names = "--dry-run",
+      description =
+          "Compile program into KORE format but do not run. Only used in Haskell and LLVM backend.")
+  public boolean dryRun = false;
 }
diff --git a/kernel/src/main/java/org/kframework/utils/options/BaseEnumConverter.java b/kernel/src/main/java/org/kframework/utils/options/BaseEnumConverter.java
index c2407f6a6ed..b11ee946c7a 100644
--- a/kernel/src/main/java/org/kframework/utils/options/BaseEnumConverter.java
+++ b/kernel/src/main/java/org/kframework/utils/options/BaseEnumConverter.java
@@ -1,44 +1,42 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.utils.options;
 
+import com.beust.jcommander.ParameterException;
+import com.beust.jcommander.converters.BaseConverter;
 import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
 
-import com.beust.jcommander.ParameterException;
-import com.beust.jcommander.converters.BaseConverter;
-
 /**
- * Helper class used to abstract functionality of converting enums in JCommander.
- * We use this because JCommander has bugs and feature issues regarding casing and hyphens
- * in enum names.
- * @author dwightguth
+ * Helper class used to abstract functionality of converting enums in JCommander. We use this
+ * because JCommander has bugs and feature issues regarding casing and hyphens in enum names.
  *
+ * @author dwightguth
  */
 public abstract class BaseEnumConverter> extends BaseConverter {
 
-    public BaseEnumConverter(String optionName) {
-        super(optionName);
-    }
+  public BaseEnumConverter(String optionName) {
+    super(optionName);
+  }
 
-    @Override
-    public T convert(String arg) {
-        try {
-            return Enum.valueOf(enumClass(), arg.toUpperCase().replaceAll("-", "_"));
-        } catch (IllegalArgumentException e) {
-            EnumSet values = EnumSet.allOf(enumClass());
-            Set validValues = new HashSet<>();
-            for (T value : values) {
-                validValues.add(friendlyName(value));
-            }
-            throw new ParameterException("Invalid value for " + getOptionName() + " parameter. Allowed values:" +
-                    validValues);
-        }
+  @Override
+  public T convert(String arg) {
+    try {
+      return Enum.valueOf(enumClass(), arg.toUpperCase().replaceAll("-", "_"));
+    } catch (IllegalArgumentException e) {
+      EnumSet values = EnumSet.allOf(enumClass());
+      Set validValues = new HashSet<>();
+      for (T value : values) {
+        validValues.add(friendlyName(value));
+      }
+      throw new ParameterException(
+          "Invalid value for " + getOptionName() + " parameter. Allowed values:" + validValues);
     }
+  }
 
-    public abstract Class enumClass();
+  public abstract Class enumClass();
 
-    public static String friendlyName(Enum arg) {
-        return arg.name().toLowerCase().replaceAll("_", "-");
-    }
+  public static String friendlyName(Enum arg) {
+    return arg.name().toLowerCase().replaceAll("_", "-");
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/utils/options/DefinitionLoadingOptions.java b/kernel/src/main/java/org/kframework/utils/options/DefinitionLoadingOptions.java
index a4d1c9c4f8b..2f43e31aa4a 100644
--- a/kernel/src/main/java/org/kframework/utils/options/DefinitionLoadingOptions.java
+++ b/kernel/src/main/java/org/kframework/utils/options/DefinitionLoadingOptions.java
@@ -2,21 +2,28 @@
 package org.kframework.utils.options;
 
 import com.beust.jcommander.Parameter;
-import com.google.inject.Inject;
 
 public class DefinitionLoadingOptions {
 
-    public DefinitionLoadingOptions() {}
+  public DefinitionLoadingOptions() {}
 
-    @Parameter(names={"--directory", "-d"}, description="[DEPRECATED] Path to the directory in which the kompiled " +
-            "K definition resides. The default is the unique, only directory with the suffix '-kompiled' " +
-            "in the current directory.", descriptionKey = "path", hidden = true)
-    public String directory;
+  @Parameter(
+      names = {"--directory", "-d"},
+      description =
+          "[DEPRECATED] Path to the directory in which the kompiled K definition resides. The"
+              + " default is the unique, only directory with the suffix '-kompiled' in the current"
+              + " directory.",
+      descriptionKey = "path",
+      hidden = true)
+  public String directory;
 
-    @Parameter(names={"--definition"}, description="Exact path to the kompiled directory.", descriptionKey = "path")
-    public String inputDirectory;
+  @Parameter(
+      names = {"--definition"},
+      description = "Exact path to the kompiled directory.",
+      descriptionKey = "path")
+  public String inputDirectory;
 
-    public DefinitionLoadingOptions(String dir) {
-        this.directory = dir;
-    }
+  public DefinitionLoadingOptions(String dir) {
+    this.directory = dir;
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/utils/options/DurationConverter.java b/kernel/src/main/java/org/kframework/utils/options/DurationConverter.java
index 343a224ec16..7a70c12f621 100644
--- a/kernel/src/main/java/org/kframework/utils/options/DurationConverter.java
+++ b/kernel/src/main/java/org/kframework/utils/options/DurationConverter.java
@@ -3,7 +3,6 @@
 
 import com.beust.jcommander.IStringConverter;
 import com.beust.jcommander.ParameterException;
-
 import java.time.Duration;
 
 /**
@@ -13,30 +12,32 @@
  */
 public class DurationConverter implements IStringConverter {
 
-    @Override
-    public Duration convert(String value) {
-        int num;
-        String unit;
-        try {
-            //kudos to https://stackoverflow.com/a/3552805/4182868
-            String numPart = value.split("[a-z]")[0];
-            num = Integer.parseInt(numPart);
-            unit = value.substring(numPart.length());
-        } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
-            throw durationException(value);
-        }
-        return switch (unit) {
-            case "ms" -> Duration.ofMillis(num);
-            case "s" -> Duration.ofSeconds(num);
-            case "m" -> Duration.ofMinutes(num);
-            case "h" -> Duration.ofHours(num);
-            case "d" -> Duration.ofDays(num);
-            default -> throw durationException(value);
-        };
+  @Override
+  public Duration convert(String value) {
+    int num;
+    String unit;
+    try {
+      // kudos to https://stackoverflow.com/a/3552805/4182868
+      String numPart = value.split("[a-z]")[0];
+      num = Integer.parseInt(numPart);
+      unit = value.substring(numPart.length());
+    } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
+      throw durationException(value);
     }
+    return switch (unit) {
+      case "ms" -> Duration.ofMillis(num);
+      case "s" -> Duration.ofSeconds(num);
+      case "m" -> Duration.ofMinutes(num);
+      case "h" -> Duration.ofHours(num);
+      case "d" -> Duration.ofDays(num);
+      default -> throw durationException(value);
+    };
+  }
 
-    private ParameterException durationException(String value) {
-        return new ParameterException(String.format(
-                "Invalid value for duration '%s', valid value examples: 10ms, 10s, 10m, 10h or 10d", value));
-    }
+  private ParameterException durationException(String value) {
+    return new ParameterException(
+        String.format(
+            "Invalid value for duration '%s', valid value examples: 10ms, 10s, 10m, 10h or 10d",
+            value));
+  }
 }
diff --git a/kernel/src/main/java/org/kframework/utils/options/EnumSetConverter.java b/kernel/src/main/java/org/kframework/utils/options/EnumSetConverter.java
index 42a309496d4..d5a464fdcc2 100644
--- a/kernel/src/main/java/org/kframework/utils/options/EnumSetConverter.java
+++ b/kernel/src/main/java/org/kframework/utils/options/EnumSetConverter.java
@@ -1,31 +1,30 @@
 // Copyright (c) K Team. All Rights Reserved.
 package org.kframework.utils.options;
 
+import com.beust.jcommander.converters.BaseConverter;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Set;
 
-import com.beust.jcommander.converters.BaseConverter;
+public abstract class EnumSetConverter, C extends BaseEnumConverter>
+    extends BaseConverter> {
 
-public abstract class EnumSetConverter, C extends BaseEnumConverter> extends BaseConverter>{
+  public EnumSetConverter(String optionName) {
+    super(optionName);
+  }
 
-    public EnumSetConverter(String optionName) {
-        super(optionName);
-    }
+  private final StringListConverter converter = new StringListConverter();
 
-    private final StringListConverter converter = new StringListConverter();
-
-    @Override
-    public Set convert(String val) {
-        List values = converter.convert(val);
-        Set set = EnumSet.noneOf(enumConverter().enumClass());
-        for (String value : values) {
-            T t = enumConverter().convert(value);
-            set.add(t);
-        }
-        return set;
+  @Override
+  public Set convert(String val) {
+    List values = converter.convert(val);
+    Set set = EnumSet.noneOf(enumConverter().enumClass());
+    for (String value : values) {
+      T t = enumConverter().convert(value);
+      set.add(t);
     }
+    return set;
+  }
 
-    public abstract C enumConverter();
-
+  public abstract C enumConverter();
 }
diff --git a/kernel/src/main/java/org/kframework/utils/options/InnerParsingOptions.java b/kernel/src/main/java/org/kframework/utils/options/InnerParsingOptions.java
index 82f98421bc4..19dda052663 100644
--- a/kernel/src/main/java/org/kframework/utils/options/InnerParsingOptions.java
+++ b/kernel/src/main/java/org/kframework/utils/options/InnerParsingOptions.java
@@ -3,21 +3,24 @@
 
 import com.beust.jcommander.Parameter;
 import com.google.inject.Inject;
-
 import java.io.Serializable;
 
 /**
  * Provides the options needed for tools to perform inner parsing of definitions from source.
  *
- * Used currently by kompile, and kprove.
+ * 

Used currently by kompile, and kprove. */ public class InnerParsingOptions implements Serializable { - public InnerParsingOptions() {} + public InnerParsingOptions() {} - @Inject - public InnerParsingOptions(Void v) {} + @Inject + public InnerParsingOptions(Void v) {} - @Parameter(names="--profile-rule-parsing", description="Store in this file time taken in ms to parse each rule in the semantics.", descriptionKey = "file", hidden = true) - public String profileRules; + @Parameter( + names = "--profile-rule-parsing", + description = "Store in this file time taken in ms to parse each rule in the semantics.", + descriptionKey = "file", + hidden = true) + public String profileRules; } diff --git a/kernel/src/main/java/org/kframework/utils/options/OnOffConverter.java b/kernel/src/main/java/org/kframework/utils/options/OnOffConverter.java index 4e4f9f78ffa..1f8a5ec51d8 100644 --- a/kernel/src/main/java/org/kframework/utils/options/OnOffConverter.java +++ b/kernel/src/main/java/org/kframework/utils/options/OnOffConverter.java @@ -6,18 +6,19 @@ public class OnOffConverter extends BaseConverter { - public OnOffConverter(String optionName) { - super(optionName); - } + public OnOffConverter(String optionName) { + super(optionName); + } - @Override - public Boolean convert(String arg0) { - if (arg0.equals("on")) { - return true; - } else if (arg0.equals("off")) { - return false; - } else { - throw new ParameterException("\"" + getOptionName() + "\": must be either \"on\" or \"off\"."); - } + @Override + public Boolean convert(String arg0) { + if (arg0.equals("on")) { + return true; + } else if (arg0.equals("off")) { + return false; + } else { + throw new ParameterException( + "\"" + getOptionName() + "\": must be either \"on\" or \"off\"."); } + } } diff --git a/kernel/src/main/java/org/kframework/utils/options/OuterParsingOptions.java b/kernel/src/main/java/org/kframework/utils/options/OuterParsingOptions.java index f5f5b4c6b25..8600c2fa734 100644 --- a/kernel/src/main/java/org/kframework/utils/options/OuterParsingOptions.java +++ b/kernel/src/main/java/org/kframework/utils/options/OuterParsingOptions.java @@ -3,52 +3,62 @@ import com.beust.jcommander.Parameter; import com.google.inject.Inject; -import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.file.FileUtil; - import java.io.File; import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import org.kframework.utils.errorsystem.KEMException; +import org.kframework.utils.file.FileUtil; /** * Provides the options needed for tools to perform outer parsing of definitions from source. * - * Used currently by kompile, and kdep. + *

Used currently by kompile, and kdep. */ public class OuterParsingOptions implements Serializable { - public OuterParsingOptions() {} + public OuterParsingOptions() {} - @Inject - public OuterParsingOptions(Void v) {} + @Inject + public OuterParsingOptions(Void v) {} - public OuterParsingOptions(File mainDefinitionFile) { - this.mainDefinitionFile = mainDefinitionFile; - } + public OuterParsingOptions(File mainDefinitionFile) { + this.mainDefinitionFile = mainDefinitionFile; + } - @Parameter(description="") - private String mainParameter; + @Parameter(description = "") + private String mainParameter; - private File mainDefinitionFile; + private File mainDefinitionFile; - public synchronized File mainDefinitionFile(FileUtil files) { - if (mainDefinitionFile == null) { - if (mainParameter == null) { - throw KEMException.criticalError("You have to provide exactly one main file in order to do outer parsing."); - } - mainDefinitionFile = files.resolveWorkingDirectory(mainParameter); - } - return mainDefinitionFile; + public synchronized File mainDefinitionFile(FileUtil files) { + if (mainDefinitionFile == null) { + if (mainParameter == null) { + throw KEMException.criticalError( + "You have to provide exactly one main file in order to do outer parsing."); + } + mainDefinitionFile = files.resolveWorkingDirectory(mainParameter); } + return mainDefinitionFile; + } + @Parameter( + names = "-I", + description = "Add a directory to the search path for requires statements.", + descriptionKey = "path") + public List includes = new ArrayList<>(); - @Parameter(names="-I", description="Add a directory to the search path for requires statements.", descriptionKey = "path") - public List includes = new ArrayList<>(); - - @Parameter(names="--no-prelude", description="Do not implicitly require prelude.md.", hidden = true) - public boolean noPrelude = false; + @Parameter( + names = "--no-prelude", + description = "Do not implicitly require prelude.md.", + hidden = true) + public boolean noPrelude = false; - @Parameter(names="--md-selector", description="Preprocessor: for .md files, select only the md code blocks that match the selector expression. Ex:'k&(!a|b)'.", descriptionKey = "expression") - public String mdSelector = "k"; + @Parameter( + names = "--md-selector", + description = + "Preprocessor: for .md files, select only the md code blocks that match the selector" + + " expression. Ex:'k&(!a|b)'.", + descriptionKey = "expression") + public String mdSelector = "k"; } diff --git a/kernel/src/main/java/org/kframework/utils/options/OutputDirectoryOptions.java b/kernel/src/main/java/org/kframework/utils/options/OutputDirectoryOptions.java index 6d2fb6bc82b..c13ca4e47fd 100644 --- a/kernel/src/main/java/org/kframework/utils/options/OutputDirectoryOptions.java +++ b/kernel/src/main/java/org/kframework/utils/options/OutputDirectoryOptions.java @@ -3,23 +3,28 @@ import com.beust.jcommander.Parameter; import com.google.inject.Inject; - import java.io.Serializable; public class OutputDirectoryOptions implements Serializable { - public OutputDirectoryOptions() {} + public OutputDirectoryOptions() {} - @Inject - public OutputDirectoryOptions(Void v) {} + @Inject + public OutputDirectoryOptions(Void v) {} - @Parameter(names={"--directory", "-d"}, - description="[DEPRECATED] Path to the directory in which the output resides. An output can be either a " + - "kompiled K definition or a document which depends on the type of backend. The default is the " + - "directory containing the main definition file.", descriptionKey = "path", hidden = true) - public String directory; + @Parameter( + names = {"--directory", "-d"}, + description = + "[DEPRECATED] Path to the directory in which the output resides. An output can be either" + + " a kompiled K definition or a document which depends on the type of backend. The" + + " default is the directory containing the main definition file.", + descriptionKey = "path", + hidden = true) + public String directory; - @Parameter(names={"--output-definition", "-o"}, - description="Path to the exact directory in which the output resides.", descriptionKey = "path") - public String outputDirectory; + @Parameter( + names = {"--output-definition", "-o"}, + description = "Path to the exact directory in which the output resides.", + descriptionKey = "path") + public String outputDirectory; } diff --git a/kernel/src/main/java/org/kframework/utils/options/SMTOptions.java b/kernel/src/main/java/org/kframework/utils/options/SMTOptions.java index 9fd7cc13a32..fea26d8858e 100644 --- a/kernel/src/main/java/org/kframework/utils/options/SMTOptions.java +++ b/kernel/src/main/java/org/kframework/utils/options/SMTOptions.java @@ -2,53 +2,76 @@ package org.kframework.utils.options; import com.beust.jcommander.Parameter; -import com.google.inject.Inject; - import java.io.Serializable; public class SMTOptions implements Serializable { - public SMTOptions() {} + public SMTOptions() {} - @Parameter(names="--smt", converter=SMTSolverConverter.class, description="SMT solver to use for checking constraints. is one of [z3|none].", descriptionKey = "executable", hidden = true) - public SMTSolver smt = SMTSolver.Z3; + @Parameter( + names = "--smt", + converter = SMTSolverConverter.class, + description = "SMT solver to use for checking constraints. is one of [z3|none].", + descriptionKey = "executable", + hidden = true) + public SMTSolver smt = SMTSolver.Z3; - public static class SMTSolverConverter extends BaseEnumConverter { + public static class SMTSolverConverter extends BaseEnumConverter { - public SMTSolverConverter(String optionName) { - super(optionName); - } + public SMTSolverConverter(String optionName) { + super(optionName); + } - @Override - public Class enumClass() { - return SMTSolver.class; - } + @Override + public Class enumClass() { + return SMTSolver.class; } + } - @Parameter(names="--ignore-missing-smtlib-warning", - description="Suppress warning when SMTLib translation fails.", hidden = true) - public boolean ignoreMissingSMTLibWarning = false; + @Parameter( + names = "--ignore-missing-smtlib-warning", + description = "Suppress warning when SMTLib translation fails.", + hidden = true) + public boolean ignoreMissingSMTLibWarning = false; - @Parameter(names="--floats-as-po", - description="Abstracts floating-point values as a partial order relation.", hidden = true) - public boolean floatsAsPO = false; + @Parameter( + names = "--floats-as-po", + description = "Abstracts floating-point values as a partial order relation.", + hidden = true) + public boolean floatsAsPO = false; - @Parameter(names="--maps-as-int-array", description="Abstracts map values as an array of ints.", hidden = true) - public boolean mapAsIntArray = false; + @Parameter( + names = "--maps-as-int-array", + description = "Abstracts map values as an array of ints.", + hidden = true) + public boolean mapAsIntArray = false; - @Parameter(names={"--smt-prelude", "--smt_prelude"}, - description="Path to the SMT prelude file.", descriptionKey = "path", hidden = true) - public String smtPrelude; + @Parameter( + names = {"--smt-prelude", "--smt_prelude"}, + description = "Path to the SMT prelude file.", + descriptionKey = "path", + hidden = true) + public String smtPrelude; - @Parameter(names="--smt-timeout", descriptionKey = "milliseconds", - description="Timeout for calls to the SMT solver, in milliseconds.", hidden = true) - public Integer smtTimeout = null; + @Parameter( + names = "--smt-timeout", + descriptionKey = "milliseconds", + description = "Timeout for calls to the SMT solver, in milliseconds.", + hidden = true) + public Integer smtTimeout = null; - @Parameter(names="--z3-jni", description="Invokes Z3 as JNI library. Default is external process. " + - "JNI is slightly faster, but can potentially lead to JVM crash.", hidden = true) - public boolean z3JNI = false; + @Parameter( + names = "--z3-jni", + description = + "Invokes Z3 as JNI library. Default is external process. " + + "JNI is slightly faster, but can potentially lead to JVM crash.", + hidden = true) + public boolean z3JNI = false; - @Parameter(names="--z3-tactic", descriptionKey = "solver", - description="The path to solver tactic to use to check satisfiability in Z3.", hidden = true) - public String z3Tactic; + @Parameter( + names = "--z3-tactic", + descriptionKey = "solver", + description = "The path to solver tactic to use to check satisfiability in Z3.", + hidden = true) + public String z3Tactic; } diff --git a/kernel/src/main/java/org/kframework/utils/options/SMTSolver.java b/kernel/src/main/java/org/kframework/utils/options/SMTSolver.java index 2980a32b7a0..3bdf859c5c0 100644 --- a/kernel/src/main/java/org/kframework/utils/options/SMTSolver.java +++ b/kernel/src/main/java/org/kframework/utils/options/SMTSolver.java @@ -4,18 +4,14 @@ /** * Enum storing information about which SMT solver is being used * - * TODO(dwightguth): create a proper SMT interface and put this class in that package + *

TODO(dwightguth): create a proper SMT interface and put this class in that package + * * @author dwightguth */ public enum SMTSolver { - /** - * No SMT. Interpreter may fail to reason about certain types of situations. - */ - NONE, - - /** - * The Microsoft Z3 SMT solver. - */ - Z3, + /** No SMT. Interpreter may fail to reason about certain types of situations. */ + NONE, + /** The Microsoft Z3 SMT solver. */ + Z3, } diff --git a/kernel/src/main/java/org/kframework/utils/options/StringListConverter.java b/kernel/src/main/java/org/kframework/utils/options/StringListConverter.java index 683fbac2979..02cda6c5210 100644 --- a/kernel/src/main/java/org/kframework/utils/options/StringListConverter.java +++ b/kernel/src/main/java/org/kframework/utils/options/StringListConverter.java @@ -1,36 +1,33 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.options; +import com.beust.jcommander.IStringConverter; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.beust.jcommander.IStringConverter; - /** - * This class is designed to support the specification of a list of strings - * using a single string in cases where using a list of strings would be - * infeasible. For example, in krun, simulation options are passed by - * passing a set of krun options as parameter to a special krun option. - * We can't use variable arity because then --simulation --directory foo - * would be interpreted as two options instead of one with two words. - * @author dwightguth + * This class is designed to support the specification of a list of strings using a single string in + * cases where using a list of strings would be infeasible. For example, in krun, simulation options + * are passed by passing a set of krun options as parameter to a special krun option. We can't use + * variable arity because then --simulation --directory foo would be interpreted as two options + * instead of one with two words. * + * @author dwightguth */ public class StringListConverter implements IStringConverter> { - @Override - public List convert(String val) { - //split on whitespace not preceded by a backslash - String[] parts = val.split("(? result = new ArrayList<>(); - for (String part : parts) { - result.add(part.trim().replaceAll("\\\\(\\s)", "$1")); - } - return result; + @Override + public List convert(String val) { + // split on whitespace not preceded by a backslash + String[] parts = val.split("(? result = new ArrayList<>(); + for (String part : parts) { + result.add(part.trim().replaceAll("\\\\(\\s)", "$1")); + } + return result; + } } diff --git a/kernel/src/test/java/org/kframework/compile/ConstantFoldingTest.java b/kernel/src/test/java/org/kframework/compile/ConstantFoldingTest.java index 22d8697cc75..8b29224c6ea 100644 --- a/kernel/src/test/java/org/kframework/compile/ConstantFoldingTest.java +++ b/kernel/src/test/java/org/kframework/compile/ConstantFoldingTest.java @@ -1,19 +1,18 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.junit.Assert.*; +import static org.kframework.kore.KORE.*; + +import java.math.BigInteger; +import java.util.function.BiFunction; +import java.util.function.Function; import org.junit.Before; import org.junit.Test; import org.kframework.mpfr.BigFloat; import org.kframework.mpfr.BinaryMathContext; import org.kframework.utils.errorsystem.KEMException; -import java.math.BigInteger; -import java.util.function.BiFunction; -import java.util.function.Function; - -import static org.junit.Assert.*; -import static org.kframework.kore.KORE.*; - public class ConstantFoldingTest { private ConstantFolding cf; @@ -30,7 +29,8 @@ public void testNot() { assertEquals(false, cf.BOOL_not(true)); } - public void assertBinBoolOp(boolean a, boolean b, boolean c, boolean d, BiFunction f) { + public void assertBinBoolOp( + boolean a, boolean b, boolean c, boolean d, BiFunction f) { assertEquals(a, f.apply(false, false)); assertEquals(b, f.apply(false, true)); assertEquals(c, f.apply(true, false)); @@ -101,12 +101,12 @@ public void testChr() { assertEquals("\udbff\udfff", cf.STRING_chr(BigInteger.valueOf(0x10ffff))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testChrError1() { cf.STRING_chr(BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testChrError2() { cf.STRING_chr(BigInteger.valueOf(0x110000)); } @@ -120,12 +120,12 @@ public void testOrd() { assertEquals(BigInteger.valueOf(0x10ffff), cf.STRING_ord("\udbff\udfff")); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testOrdError1() { cf.STRING_ord(""); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testOrdError2() { cf.STRING_ord("foo"); } @@ -143,22 +143,22 @@ public void testSubstr() { assertEquals("o", cf.STRING_substr("foo", BigInteger.valueOf(1), BigInteger.valueOf(2))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testSubstrError1() { cf.STRING_substr("foo", BigInteger.valueOf(1), BigInteger.valueOf(4)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testSubstrError2() { cf.STRING_substr("foo", BigInteger.valueOf(4), BigInteger.valueOf(5)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testSubstrError3() { cf.STRING_substr("foo", BigInteger.valueOf(3), BigInteger.valueOf(1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testSubstError4() { cf.STRING_substr("foo", BigInteger.valueOf(-1), BigInteger.valueOf(1)); } @@ -174,12 +174,12 @@ public void testFind() { assertEquals(BigInteger.valueOf(-1), cf.STRING_find("foo", "oo", BigInteger.valueOf(2))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testFindError1() { cf.STRING_find("foo", "f", BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testFindError2() { cf.STRING_find("foo", "f", BigInteger.valueOf(4)); } @@ -195,77 +195,100 @@ public void testRFind() { assertEquals(BigInteger.valueOf(1), cf.STRING_rfind("foo", "oo", BigInteger.valueOf(2))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testRFindError1() { cf.STRING_rfind("foo", "f", BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testRFindError2() { cf.STRING_rfind("foo", "f", BigInteger.valueOf(4)); } @Test public void testFindChar() { - assertEquals(BigInteger.valueOf(0), cf.STRING_findChar("sandwich", "sw", BigInteger.valueOf(0))); - assertEquals(BigInteger.valueOf(4), cf.STRING_findChar("sandwich", "sw", BigInteger.valueOf(1))); - assertEquals(BigInteger.valueOf(-1), cf.STRING_findChar("sandwich", "s", BigInteger.valueOf(1))); + assertEquals( + BigInteger.valueOf(0), cf.STRING_findChar("sandwich", "sw", BigInteger.valueOf(0))); + assertEquals( + BigInteger.valueOf(4), cf.STRING_findChar("sandwich", "sw", BigInteger.valueOf(1))); + assertEquals( + BigInteger.valueOf(-1), cf.STRING_findChar("sandwich", "s", BigInteger.valueOf(1))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testFindCharError1() { cf.STRING_findChar("foo", "f", BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testFindCharError2() { cf.STRING_findChar("foo", "f", BigInteger.valueOf(4)); } @Test public void testRFindChar() { - assertEquals(BigInteger.valueOf(0), cf.STRING_rfindChar("sandwich", "sw", BigInteger.valueOf(0))); - assertEquals(BigInteger.valueOf(0), cf.STRING_rfindChar("sandwich", "sw", BigInteger.valueOf(1))); - assertEquals(BigInteger.valueOf(4), cf.STRING_rfindChar("sandwich", "sw", BigInteger.valueOf(7))); - assertEquals(BigInteger.valueOf(-1), cf.STRING_rfindChar("sandwich", "w", BigInteger.valueOf(1))); + assertEquals( + BigInteger.valueOf(0), cf.STRING_rfindChar("sandwich", "sw", BigInteger.valueOf(0))); + assertEquals( + BigInteger.valueOf(0), cf.STRING_rfindChar("sandwich", "sw", BigInteger.valueOf(1))); + assertEquals( + BigInteger.valueOf(4), cf.STRING_rfindChar("sandwich", "sw", BigInteger.valueOf(7))); + assertEquals( + BigInteger.valueOf(-1), cf.STRING_rfindChar("sandwich", "w", BigInteger.valueOf(1))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testRFindCharError1() { cf.STRING_rfindChar("foo", "f", BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testRFindCharError2() { cf.STRING_rfindChar("foo", "f", BigInteger.valueOf(4)); } @Test public void testFloat2String() { - assertEquals("Infinityp53x11", cf.STRING_float2string(FloatBuiltin.of(BigFloat.positiveInfinity(53), 11))); + assertEquals( + "Infinityp53x11", + cf.STRING_float2string(FloatBuiltin.of(BigFloat.positiveInfinity(53), 11))); assertEquals("NaNp53x11", cf.STRING_float2string(FloatBuiltin.of(BigFloat.NaN(53), 11))); assertEquals("0e+00p53x11", cf.STRING_float2string(FloatBuiltin.of(BigFloat.zero(53), 11))); - assertEquals("-0e+00p53x11", cf.STRING_float2string(FloatBuiltin.of(BigFloat.negativeZero(53), 11))); - assertEquals("-Infinityp53x11", cf.STRING_float2string(FloatBuiltin.of(BigFloat.negativeInfinity(53), 11))); - assertEquals("1.0000000000000001e-01p53x11", cf.STRING_float2string(FloatBuiltin.of(new BigFloat(0.1, BinaryMathContext.BINARY64), 11))); + assertEquals( + "-0e+00p53x11", cf.STRING_float2string(FloatBuiltin.of(BigFloat.negativeZero(53), 11))); + assertEquals( + "-Infinityp53x11", + cf.STRING_float2string(FloatBuiltin.of(BigFloat.negativeInfinity(53), 11))); + assertEquals( + "1.0000000000000001e-01p53x11", + cf.STRING_float2string(FloatBuiltin.of(new BigFloat(0.1, BinaryMathContext.BINARY64), 11))); } @Test public void testString2Float() { - assertEquals(FloatBuiltin.of(BigFloat.positiveInfinity(53), 11), cf.STRING_string2float("Infinity")); - assertEquals(FloatBuiltin.of(BigFloat.positiveInfinity(24), 8), cf.STRING_string2float("Infinityf")); - assertEquals(FloatBuiltin.of(BigFloat.positiveInfinity(10), 10), cf.STRING_string2float("Infinityp10x10")); + assertEquals( + FloatBuiltin.of(BigFloat.positiveInfinity(53), 11), cf.STRING_string2float("Infinity")); + assertEquals( + FloatBuiltin.of(BigFloat.positiveInfinity(24), 8), cf.STRING_string2float("Infinityf")); + assertEquals( + FloatBuiltin.of(BigFloat.positiveInfinity(10), 10), + cf.STRING_string2float("Infinityp10x10")); assertEquals(FloatBuiltin.of(BigFloat.NaN(53), 11), cf.STRING_string2float("NaN")); assertEquals(FloatBuiltin.of(BigFloat.zero(53), 11), cf.STRING_string2float("0.0")); assertEquals(FloatBuiltin.of(BigFloat.zero(53), 11), cf.STRING_string2float("0e+00")); assertEquals(FloatBuiltin.of(BigFloat.zero(53), 11), cf.STRING_string2float("0e-00")); assertEquals(FloatBuiltin.of(BigFloat.negativeZero(53), 11), cf.STRING_string2float("-0.0")); - assertEquals(FloatBuiltin.of(BigFloat.negativeInfinity(53), 11), cf.STRING_string2float("-Infinity")); - assertEquals(FloatBuiltin.of(new BigFloat(0.1, BinaryMathContext.BINARY64), 11), cf.STRING_string2float("0.1")); - assertEquals(FloatBuiltin.of(new BigFloat(0.1f, BinaryMathContext.BINARY32), 8), cf.STRING_string2float("0.1f")); + assertEquals( + FloatBuiltin.of(BigFloat.negativeInfinity(53), 11), cf.STRING_string2float("-Infinity")); + assertEquals( + FloatBuiltin.of(new BigFloat(0.1, BinaryMathContext.BINARY64), 11), + cf.STRING_string2float("0.1")); + assertEquals( + FloatBuiltin.of(new BigFloat(0.1f, BinaryMathContext.BINARY32), 8), + cf.STRING_string2float("0.1f")); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2FloatError() { cf.STRING_string2float("0.0.0"); } @@ -275,7 +298,8 @@ public void testInt2String() { assertEquals("0", cf.STRING_int2string(BigInteger.valueOf(0))); assertEquals("1", cf.STRING_int2string(BigInteger.valueOf(1))); assertEquals("-1", cf.STRING_int2string(BigInteger.valueOf(-1))); - assertEquals("100000000000000000000", cf.STRING_int2string(new BigInteger("100000000000000000000"))); + assertEquals( + "100000000000000000000", cf.STRING_int2string(new BigInteger("100000000000000000000"))); } @Test @@ -284,10 +308,11 @@ public void testString2Int() { assertEquals(BigInteger.valueOf(1), cf.STRING_string2int("1")); assertEquals(BigInteger.valueOf(1), cf.STRING_string2int("+1")); assertEquals(BigInteger.valueOf(-1), cf.STRING_string2int("-1")); - assertEquals(new BigInteger("100000000000000000000"), cf.STRING_string2int("100000000000000000000")); + assertEquals( + new BigInteger("100000000000000000000"), cf.STRING_string2int("100000000000000000000")); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2IntError() { cf.STRING_string2int("0.0"); } @@ -302,12 +327,12 @@ public void testBase2String() { assertEquals("10", cf.STRING_base2string(BigInteger.valueOf(36), BigInteger.valueOf(36))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testBase2StringError1() { cf.STRING_base2string(BigInteger.valueOf(0), BigInteger.valueOf(1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testBase2StringError2() { cf.STRING_base2string(BigInteger.valueOf(0), BigInteger.valueOf(37)); } @@ -323,27 +348,27 @@ public void testString2Base() { assertEquals(BigInteger.valueOf(36), cf.STRING_string2base("10", BigInteger.valueOf(36))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2BaseError1() { cf.STRING_string2base("0", BigInteger.valueOf(1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2BaseError2() { cf.STRING_string2base("0", BigInteger.valueOf(37)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2BaseError3() { cf.STRING_string2base("8", BigInteger.valueOf(8)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2BaseError4() { cf.STRING_string2base("g", BigInteger.valueOf(16)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testString2BaseError5() { cf.STRING_string2base("0.0", BigInteger.valueOf(2)); } @@ -364,12 +389,12 @@ public void testReplace() { assertEquals("foo", cf.STRING_replace("foo", "bar", "baz", BigInteger.valueOf(0))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testReplaceError1() { cf.STRING_replace("foo", "oo", "ar", BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testReplaceError2() { cf.STRING_replace("foo", "oo", "ar", BigInteger.valueOf(Long.MAX_VALUE)); } @@ -465,33 +490,42 @@ public void testIntNot() { public void testIntPow() { assertEquals(BigInteger.valueOf(1), cf.INT_pow(BigInteger.valueOf(10), BigInteger.valueOf(0))); assertEquals(BigInteger.valueOf(10), cf.INT_pow(BigInteger.valueOf(10), BigInteger.valueOf(1))); - assertEquals(BigInteger.valueOf(100), cf.INT_pow(BigInteger.valueOf(10), BigInteger.valueOf(2))); + assertEquals( + BigInteger.valueOf(100), cf.INT_pow(BigInteger.valueOf(10), BigInteger.valueOf(2))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntPowError() { cf.INT_pow(BigInteger.valueOf(10), BigInteger.valueOf(-1)); } @Test public void testIntPowMod() { - assertEquals(BigInteger.valueOf(1), cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(0), BigInteger.valueOf(7))); - assertEquals(BigInteger.valueOf(3), cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(1), BigInteger.valueOf(7))); - assertEquals(BigInteger.valueOf(2), cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(2), BigInteger.valueOf(7))); - assertEquals(BigInteger.valueOf(5), cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(-1), BigInteger.valueOf(7))); - } - - @Test(expected=KEMException.class) + assertEquals( + BigInteger.valueOf(1), + cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(0), BigInteger.valueOf(7))); + assertEquals( + BigInteger.valueOf(3), + cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(1), BigInteger.valueOf(7))); + assertEquals( + BigInteger.valueOf(2), + cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(2), BigInteger.valueOf(7))); + assertEquals( + BigInteger.valueOf(5), + cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(-1), BigInteger.valueOf(7))); + } + + @Test(expected = KEMException.class) public void testIntPowModError1() { cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(1), BigInteger.valueOf(0)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntPowModError2() { cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(1), BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntPowModError3() { cf.INT_powmod(BigInteger.valueOf(10), BigInteger.valueOf(-1), BigInteger.valueOf(5)); } @@ -505,12 +539,15 @@ public void testIntMul() { public void testIntTDiv() { assertEquals(BigInteger.valueOf(2), cf.INT_tdiv(BigInteger.valueOf(10), BigInteger.valueOf(5))); assertEquals(BigInteger.valueOf(2), cf.INT_tdiv(BigInteger.valueOf(7), BigInteger.valueOf(3))); - assertEquals(BigInteger.valueOf(-2), cf.INT_tdiv(BigInteger.valueOf(7), BigInteger.valueOf(-3))); - assertEquals(BigInteger.valueOf(-2), cf.INT_tdiv(BigInteger.valueOf(-7), BigInteger.valueOf(3))); - assertEquals(BigInteger.valueOf(2), cf.INT_tdiv(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); + assertEquals( + BigInteger.valueOf(-2), cf.INT_tdiv(BigInteger.valueOf(7), BigInteger.valueOf(-3))); + assertEquals( + BigInteger.valueOf(-2), cf.INT_tdiv(BigInteger.valueOf(-7), BigInteger.valueOf(3))); + assertEquals( + BigInteger.valueOf(2), cf.INT_tdiv(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntTDivError() { cf.INT_tdiv(BigInteger.valueOf(10), BigInteger.valueOf(0)); } @@ -519,12 +556,14 @@ public void testIntTDivError() { public void testIntTMod() { assertEquals(BigInteger.valueOf(0), cf.INT_tmod(BigInteger.valueOf(10), BigInteger.valueOf(5))); assertEquals(BigInteger.valueOf(1), cf.INT_tmod(BigInteger.valueOf(7), BigInteger.valueOf(3))); - assertEquals(BigInteger.valueOf(-1), cf.INT_tmod(BigInteger.valueOf(-7), BigInteger.valueOf(3))); + assertEquals( + BigInteger.valueOf(-1), cf.INT_tmod(BigInteger.valueOf(-7), BigInteger.valueOf(3))); assertEquals(BigInteger.valueOf(1), cf.INT_tmod(BigInteger.valueOf(7), BigInteger.valueOf(-3))); - assertEquals(BigInteger.valueOf(-1), cf.INT_tmod(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); + assertEquals( + BigInteger.valueOf(-1), cf.INT_tmod(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntTModError() { cf.INT_tmod(BigInteger.valueOf(10), BigInteger.valueOf(0)); } @@ -533,12 +572,15 @@ public void testIntTModError() { public void testIntEDiv() { assertEquals(BigInteger.valueOf(2), cf.INT_ediv(BigInteger.valueOf(10), BigInteger.valueOf(5))); assertEquals(BigInteger.valueOf(2), cf.INT_ediv(BigInteger.valueOf(7), BigInteger.valueOf(3))); - assertEquals(BigInteger.valueOf(-2), cf.INT_ediv(BigInteger.valueOf(7), BigInteger.valueOf(-3))); - assertEquals(BigInteger.valueOf(-3), cf.INT_ediv(BigInteger.valueOf(-7), BigInteger.valueOf(3))); - assertEquals(BigInteger.valueOf(3), cf.INT_ediv(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); + assertEquals( + BigInteger.valueOf(-2), cf.INT_ediv(BigInteger.valueOf(7), BigInteger.valueOf(-3))); + assertEquals( + BigInteger.valueOf(-3), cf.INT_ediv(BigInteger.valueOf(-7), BigInteger.valueOf(3))); + assertEquals( + BigInteger.valueOf(3), cf.INT_ediv(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntEDivError() { cf.INT_ediv(BigInteger.valueOf(10), BigInteger.valueOf(0)); } @@ -549,10 +591,11 @@ public void testIntEMod() { assertEquals(BigInteger.valueOf(1), cf.INT_emod(BigInteger.valueOf(7), BigInteger.valueOf(3))); assertEquals(BigInteger.valueOf(2), cf.INT_emod(BigInteger.valueOf(-7), BigInteger.valueOf(3))); assertEquals(BigInteger.valueOf(1), cf.INT_emod(BigInteger.valueOf(7), BigInteger.valueOf(-3))); - assertEquals(BigInteger.valueOf(2), cf.INT_emod(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); + assertEquals( + BigInteger.valueOf(2), cf.INT_emod(BigInteger.valueOf(-7), BigInteger.valueOf(-3))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntEModError() { cf.INT_emod(BigInteger.valueOf(10), BigInteger.valueOf(0)); } @@ -575,7 +618,7 @@ public void testShr() { assertEquals(BigInteger.valueOf(8), cf.INT_shr(BigInteger.valueOf(8), BigInteger.valueOf(0))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testShrError() { cf.INT_shr(BigInteger.valueOf(8), BigInteger.valueOf(-2)); } @@ -586,7 +629,7 @@ public void testShl() { assertEquals(BigInteger.valueOf(8), cf.INT_shl(BigInteger.valueOf(8), BigInteger.valueOf(0))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testShlError() { cf.INT_shl(BigInteger.valueOf(32), BigInteger.valueOf(-2)); } @@ -638,55 +681,99 @@ public void testIntLog2() { assertEquals(BigInteger.valueOf(3), cf.INT_log2(BigInteger.valueOf(8))); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntLog2Error1() { cf.INT_log2(BigInteger.valueOf(0)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testIntLog2Error2() { cf.INT_log2(BigInteger.valueOf(-1)); } @Test public void testBitRange() { - assertEquals(BigInteger.valueOf(127), cf.INT_bitRange(BigInteger.valueOf(127), BigInteger.valueOf(0), BigInteger.valueOf(8))); - assertEquals(BigInteger.valueOf(255), cf.INT_bitRange(BigInteger.valueOf(255), BigInteger.valueOf(0), BigInteger.valueOf(8))); - assertEquals(BigInteger.valueOf(64), cf.INT_bitRange(BigInteger.valueOf(128), BigInteger.valueOf(1), BigInteger.valueOf(7))); - assertEquals(BigInteger.valueOf(0), cf.INT_bitRange(BigInteger.valueOf(129), BigInteger.valueOf(1), BigInteger.valueOf(5))); - assertEquals(BigInteger.valueOf(0), cf.INT_bitRange(BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(0))); - assertEquals(BigInteger.valueOf(0), cf.INT_bitRange(new BigInteger("8040201008040201", 16), BigInteger.valueOf(256), BigInteger.valueOf(8))); - assertEquals(BigInteger.valueOf(12), cf.INT_bitRange(new BigInteger("-710567042938717889665411037832208781722350888143921263584927239275773573551204588944105336352942349727184887589413944684473529682801526123805453895275517072855048781056"), BigInteger.valueOf(32), BigInteger.valueOf(8))); - assertEquals(BigInteger.valueOf(56), cf.INT_bitRange(new BigInteger("697754608693466068295273213726275558775348389513141500672185545754018175722916164768735179047222610843044264325669307777729891642448846794142000"), BigInteger.valueOf(64), BigInteger.valueOf(8))); - } - - @Test(expected=KEMException.class) + assertEquals( + BigInteger.valueOf(127), + cf.INT_bitRange(BigInteger.valueOf(127), BigInteger.valueOf(0), BigInteger.valueOf(8))); + assertEquals( + BigInteger.valueOf(255), + cf.INT_bitRange(BigInteger.valueOf(255), BigInteger.valueOf(0), BigInteger.valueOf(8))); + assertEquals( + BigInteger.valueOf(64), + cf.INT_bitRange(BigInteger.valueOf(128), BigInteger.valueOf(1), BigInteger.valueOf(7))); + assertEquals( + BigInteger.valueOf(0), + cf.INT_bitRange(BigInteger.valueOf(129), BigInteger.valueOf(1), BigInteger.valueOf(5))); + assertEquals( + BigInteger.valueOf(0), + cf.INT_bitRange(BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(0))); + assertEquals( + BigInteger.valueOf(0), + cf.INT_bitRange( + new BigInteger("8040201008040201", 16), + BigInteger.valueOf(256), + BigInteger.valueOf(8))); + assertEquals( + BigInteger.valueOf(12), + cf.INT_bitRange( + new BigInteger( + "-710567042938717889665411037832208781722350888143921263584927239275773573551204588944105336352942349727184887589413944684473529682801526123805453895275517072855048781056"), + BigInteger.valueOf(32), + BigInteger.valueOf(8))); + assertEquals( + BigInteger.valueOf(56), + cf.INT_bitRange( + new BigInteger( + "697754608693466068295273213726275558775348389513141500672185545754018175722916164768735179047222610843044264325669307777729891642448846794142000"), + BigInteger.valueOf(64), + BigInteger.valueOf(8))); + } + + @Test(expected = KEMException.class) public void testBitRangeError1() { cf.INT_bitRange(BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testBitRangeError2() { cf.INT_bitRange(BigInteger.valueOf(128), BigInteger.valueOf(-1), BigInteger.valueOf(8)); } @Test public void testSignExtendBitRange() { - assertEquals(BigInteger.valueOf(-1), cf.INT_signExtendBitRange(BigInteger.valueOf(255), BigInteger.valueOf(0), BigInteger.valueOf(8))); - assertEquals(BigInteger.valueOf(127), cf.INT_signExtendBitRange(BigInteger.valueOf(127), BigInteger.valueOf(0), BigInteger.valueOf(8))); - assertEquals(BigInteger.valueOf(-64), cf.INT_signExtendBitRange(BigInteger.valueOf(128), BigInteger.valueOf(1), BigInteger.valueOf(7))); - assertEquals(BigInteger.valueOf(0), cf.INT_signExtendBitRange(BigInteger.valueOf(129), BigInteger.valueOf(1), BigInteger.valueOf(5))); - assertEquals(BigInteger.valueOf(0), cf.INT_signExtendBitRange(BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(0))); - } - - @Test(expected=KEMException.class) + assertEquals( + BigInteger.valueOf(-1), + cf.INT_signExtendBitRange( + BigInteger.valueOf(255), BigInteger.valueOf(0), BigInteger.valueOf(8))); + assertEquals( + BigInteger.valueOf(127), + cf.INT_signExtendBitRange( + BigInteger.valueOf(127), BigInteger.valueOf(0), BigInteger.valueOf(8))); + assertEquals( + BigInteger.valueOf(-64), + cf.INT_signExtendBitRange( + BigInteger.valueOf(128), BigInteger.valueOf(1), BigInteger.valueOf(7))); + assertEquals( + BigInteger.valueOf(0), + cf.INT_signExtendBitRange( + BigInteger.valueOf(129), BigInteger.valueOf(1), BigInteger.valueOf(5))); + assertEquals( + BigInteger.valueOf(0), + cf.INT_signExtendBitRange( + BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(0))); + } + + @Test(expected = KEMException.class) public void testSignExtendBitRangeError1() { - cf.INT_signExtendBitRange(BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(-1)); + cf.INT_signExtendBitRange( + BigInteger.valueOf(128), BigInteger.valueOf(0), BigInteger.valueOf(-1)); } - @Test(expected=KEMException.class) + @Test(expected = KEMException.class) public void testSignExtendBitRangeError2() { - cf.INT_signExtendBitRange(BigInteger.valueOf(128), BigInteger.valueOf(-1), BigInteger.valueOf(8)); + cf.INT_signExtendBitRange( + BigInteger.valueOf(128), BigInteger.valueOf(-1), BigInteger.valueOf(8)); } @Test @@ -755,25 +842,49 @@ public void testIntNe() { @Test public void testPrecision() { - assertEquals(BigInteger.valueOf(2), cf.FLOAT_precision(FloatBuiltin.of(new BigFloat(1.0, new BinaryMathContext(2, 8)), 8))); - assertEquals(BigInteger.valueOf(24), cf.FLOAT_precision(FloatBuiltin.of(new BigFloat(1.0, BinaryMathContext.BINARY32), 8))); + assertEquals( + BigInteger.valueOf(2), + cf.FLOAT_precision(FloatBuiltin.of(new BigFloat(1.0, new BinaryMathContext(2, 8)), 8))); + assertEquals( + BigInteger.valueOf(24), + cf.FLOAT_precision(FloatBuiltin.of(new BigFloat(1.0, BinaryMathContext.BINARY32), 8))); } @Test public void testExponentBits() { - assertEquals(BigInteger.valueOf(8), cf.FLOAT_exponentBits(FloatBuiltin.of(new BigFloat(1.0, new BinaryMathContext(2, 8)), 8))); - assertEquals(BigInteger.valueOf(11), cf.FLOAT_exponentBits(FloatBuiltin.of(new BigFloat(1.0, BinaryMathContext.BINARY64), 11))); + assertEquals( + BigInteger.valueOf(8), + cf.FLOAT_exponentBits(FloatBuiltin.of(new BigFloat(1.0, new BinaryMathContext(2, 8)), 8))); + assertEquals( + BigInteger.valueOf(11), + cf.FLOAT_exponentBits(FloatBuiltin.of(new BigFloat(1.0, BinaryMathContext.BINARY64), 11))); } @Test public void testExponent() { - assertEquals(BigInteger.valueOf(-127), cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(0.0, BinaryMathContext.BINARY32), 8))); - assertEquals(BigInteger.valueOf(-127), cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(-0.0, BinaryMathContext.BINARY32), 8))); - assertEquals(BigInteger.valueOf(128), cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(1.0/0.0, BinaryMathContext.BINARY32), 8))); - assertEquals(BigInteger.valueOf(128), cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(0.0/0.0, BinaryMathContext.BINARY32), 8))); - assertEquals(BigInteger.valueOf(2), cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(4.0, BinaryMathContext.BINARY32), 8))); - assertEquals(BigInteger.valueOf(-127), cf.FLOAT_exponent(FloatBuiltin.of(BigFloat.minValue(24, BinaryMathContext.BINARY32.minExponent), 8))); - assertEquals(BigInteger.valueOf(-126), cf.FLOAT_exponent(FloatBuiltin.of(BigFloat.minNormal(24, BinaryMathContext.BINARY32.minExponent), 8))); + assertEquals( + BigInteger.valueOf(-127), + cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(0.0, BinaryMathContext.BINARY32), 8))); + assertEquals( + BigInteger.valueOf(-127), + cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(-0.0, BinaryMathContext.BINARY32), 8))); + assertEquals( + BigInteger.valueOf(128), + cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(1.0 / 0.0, BinaryMathContext.BINARY32), 8))); + assertEquals( + BigInteger.valueOf(128), + cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(0.0 / 0.0, BinaryMathContext.BINARY32), 8))); + assertEquals( + BigInteger.valueOf(2), + cf.FLOAT_exponent(FloatBuiltin.of(new BigFloat(4.0, BinaryMathContext.BINARY32), 8))); + assertEquals( + BigInteger.valueOf(-127), + cf.FLOAT_exponent( + FloatBuiltin.of(BigFloat.minValue(24, BinaryMathContext.BINARY32.minExponent), 8))); + assertEquals( + BigInteger.valueOf(-126), + cf.FLOAT_exponent( + FloatBuiltin.of(BigFloat.minNormal(24, BinaryMathContext.BINARY32.minExponent), 8))); } private FloatBuiltin _float(float f) { @@ -788,21 +899,21 @@ private FloatBuiltin _double(double f) { public void testSign() { assertEquals(false, cf.FLOAT_sign(_float(0.0f))); assertEquals(true, cf.FLOAT_sign(_float(-0.0f))); - assertEquals(false, cf.FLOAT_sign(_float(1.0f/0.0f))); - assertEquals(true, cf.FLOAT_sign(_float(-1.0f/0.0f))); + assertEquals(false, cf.FLOAT_sign(_float(1.0f / 0.0f))); + assertEquals(true, cf.FLOAT_sign(_float(-1.0f / 0.0f))); assertEquals(false, cf.FLOAT_sign(_float(1.0f))); assertEquals(true, cf.FLOAT_sign(_float(-1.0f))); assertEquals(false, cf.FLOAT_sign(_float(3.0f))); assertEquals(false, cf.FLOAT_sign(_float(0.5f))); - assertEquals(false, cf.FLOAT_sign(_float(0.0f/0.0f))); + assertEquals(false, cf.FLOAT_sign(_float(0.0f / 0.0f))); } @Test public void testIsNaN() { assertEquals(false, cf.FLOAT_isNaN(_float(0.0f))); assertEquals(false, cf.FLOAT_isNaN(_float(-0.0f))); - assertEquals(false, cf.FLOAT_isNaN(_float(1.0f/0.0f))); - assertEquals(true, cf.FLOAT_isNaN(_float(0.0f/0.0f))); + assertEquals(false, cf.FLOAT_isNaN(_float(1.0f / 0.0f))); + assertEquals(true, cf.FLOAT_isNaN(_float(0.0f / 0.0f))); } @Test @@ -810,13 +921,16 @@ public void testFloatNeg() { testUnaryOp(cf::FLOAT_neg, a -> -a); } - private final double[] refs = new double[] {0.0, -0.0, 1.0/0.0, -1.0/0.0, 1.0, -1.0, 3.0, 0.5, 0.0/0.0}; + private final double[] refs = + new double[] {0.0, -0.0, 1.0 / 0.0, -1.0 / 0.0, 1.0, -1.0, 3.0, 0.5, 0.0 / 0.0}; - private void testUnaryOp(Function op, Function refOp) { + private void testUnaryOp( + Function op, Function refOp) { testUnaryOp(op, refOp, Double.MIN_VALUE); } - private void testUnaryOp(Function op, Function refOp, Double epsilon) { + private void testUnaryOp( + Function op, Function refOp, Double epsilon) { for (int i = 0; i < refs.length; i++) { FloatBuiltin result = op.apply(_double(refs[i])); double ref = refOp.apply(refs[i]); @@ -824,12 +938,19 @@ private void testUnaryOp(Function op, Function op, BiFunction refOp) { + private void testBinaryOp( + String operator, + BiFunction op, + BiFunction refOp) { for (int i = 0; i < refs.length; i++) { for (int j = 0; j < refs.length; j++) { FloatBuiltin result = op.apply(_double(refs[i]), _double(refs[j])); double ref = refOp.apply(refs[i], refs[j]); - assertEquals("Operator " + operator + "(" + refs[i] + "," + refs[j] + ") failed", ref, result.doubleValue(), Double.MIN_VALUE); + assertEquals( + "Operator " + operator + "(" + refs[i] + "," + refs[j] + ") failed", + ref, + result.doubleValue(), + Double.MIN_VALUE); } } } @@ -851,27 +972,27 @@ public void testFloatPow() { @Test public void testFloatMul() { - testBinaryOp("*", cf::FLOAT_mul, (a, b) -> a*b); + testBinaryOp("*", cf::FLOAT_mul, (a, b) -> a * b); } @Test public void testFloatDiv() { - testBinaryOp("/", cf::FLOAT_div, (a, b) -> a/b); + testBinaryOp("/", cf::FLOAT_div, (a, b) -> a / b); } @Test public void testFloatRem() { - testBinaryOp("%", cf::FLOAT_rem, (a, b) -> a%b); + testBinaryOp("%", cf::FLOAT_rem, (a, b) -> a % b); } @Test public void testFloatAdd() { - testBinaryOp("+", cf::FLOAT_add, (a, b) -> a+b); + testBinaryOp("+", cf::FLOAT_add, (a, b) -> a + b); } @Test public void testFloatSub() { - testBinaryOp("-", cf::FLOAT_sub, (a, b) -> a-b); + testBinaryOp("-", cf::FLOAT_sub, (a, b) -> a - b); } @Test @@ -886,10 +1007,22 @@ public void testFloatAbs() { @Test public void testRound() { - assertEquals(12.0, cf.FLOAT_round(_double(10.5), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), Double.MIN_VALUE); - assertEquals(8.0, cf.FLOAT_round(_double(9.5), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), Double.MIN_VALUE); - assertEquals(10.5f, cf.FLOAT_round(_double(10.5), BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), Double.MIN_VALUE); - assertEquals(9.5f, cf.FLOAT_round(_double(9.5), BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), Double.MIN_VALUE); + assertEquals( + 12.0, + cf.FLOAT_round(_double(10.5), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), + Double.MIN_VALUE); + assertEquals( + 8.0, + cf.FLOAT_round(_double(9.5), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), + Double.MIN_VALUE); + assertEquals( + 10.5f, + cf.FLOAT_round(_double(10.5), BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), + Double.MIN_VALUE); + assertEquals( + 9.5f, + cf.FLOAT_round(_double(9.5), BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), + Double.MIN_VALUE); } @Test @@ -977,25 +1110,40 @@ private double max(double a, double b) { return Math.max(a, b); } - @Test public void testMaxValue() { - assertEquals(Float.MAX_VALUE, cf.FLOAT_maxValue(BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), Double.MIN_VALUE); - assertEquals(Double.MAX_VALUE, cf.FLOAT_maxValue(BigInteger.valueOf(53), BigInteger.valueOf(11)).doubleValue(), Double.MIN_VALUE); + assertEquals( + Float.MAX_VALUE, + cf.FLOAT_maxValue(BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), + Double.MIN_VALUE); + assertEquals( + Double.MAX_VALUE, + cf.FLOAT_maxValue(BigInteger.valueOf(53), BigInteger.valueOf(11)).doubleValue(), + Double.MIN_VALUE); } @Test public void testMinValue() { - assertEquals(Float.MIN_VALUE, cf.FLOAT_minValue(BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), Double.MIN_VALUE); - assertEquals(Double.MIN_VALUE, cf.FLOAT_minValue(BigInteger.valueOf(53), BigInteger.valueOf(11)).doubleValue(), Double.MIN_VALUE); - } - - private void testComparisonOp(String operator, BiFunction op, BiFunction refOp) { + assertEquals( + Float.MIN_VALUE, + cf.FLOAT_minValue(BigInteger.valueOf(24), BigInteger.valueOf(8)).floatValue(), + Double.MIN_VALUE); + assertEquals( + Double.MIN_VALUE, + cf.FLOAT_minValue(BigInteger.valueOf(53), BigInteger.valueOf(11)).doubleValue(), + Double.MIN_VALUE); + } + + private void testComparisonOp( + String operator, + BiFunction op, + BiFunction refOp) { for (int i = 0; i < refs.length; i++) { for (int j = 0; j < refs.length; j++) { boolean result = op.apply(_double(refs[i]), _double(refs[j])); boolean ref = refOp.apply(refs[i], refs[j]); - assertEquals("Operator " + operator + "(" + refs[i] + "," + refs[j] + ") failed", ref, result); + assertEquals( + "Operator " + operator + "(" + refs[i] + "," + refs[j] + ") failed", ref, result); } } } @@ -1032,10 +1180,26 @@ public void testFloatNe() { @Test public void testInt2Float() { - assertEquals(8.0, cf.FLOAT_int2float(BigInteger.valueOf(9), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), Double.MIN_VALUE); - assertEquals(12.0, cf.FLOAT_int2float(BigInteger.valueOf(11), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), Double.MIN_VALUE); - assertEquals(8.0, cf.FLOAT_int2float(BigInteger.valueOf(10), BigInteger.valueOf(2), BigInteger.valueOf(8)).doubleValue(), Double.MIN_VALUE); - assertEquals(10.0, cf.FLOAT_int2float(BigInteger.valueOf(10), BigInteger.valueOf(24), BigInteger.valueOf(8)).doubleValue(), Double.MIN_VALUE); + assertEquals( + 8.0, + cf.FLOAT_int2float(BigInteger.valueOf(9), BigInteger.valueOf(2), BigInteger.valueOf(8)) + .doubleValue(), + Double.MIN_VALUE); + assertEquals( + 12.0, + cf.FLOAT_int2float(BigInteger.valueOf(11), BigInteger.valueOf(2), BigInteger.valueOf(8)) + .doubleValue(), + Double.MIN_VALUE); + assertEquals( + 8.0, + cf.FLOAT_int2float(BigInteger.valueOf(10), BigInteger.valueOf(2), BigInteger.valueOf(8)) + .doubleValue(), + Double.MIN_VALUE); + assertEquals( + 10.0, + cf.FLOAT_int2float(BigInteger.valueOf(10), BigInteger.valueOf(24), BigInteger.valueOf(8)) + .doubleValue(), + Double.MIN_VALUE); } @Test diff --git a/kernel/src/test/java/org/kframework/kast/KastModuleTest.java b/kernel/src/test/java/org/kframework/kast/KastModuleTest.java index ff4bb0d5afb..8f868a2a4b3 100644 --- a/kernel/src/test/java/org/kframework/kast/KastModuleTest.java +++ b/kernel/src/test/java/org/kframework/kast/KastModuleTest.java @@ -3,24 +3,25 @@ import static org.junit.Assert.*; -import org.junit.Test; -import org.kframework.main.FrontEnd; -import org.kframework.utils.BaseTestCase; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.util.Modules; - import java.util.List; +import org.junit.Test; +import org.kframework.main.FrontEnd; +import org.kframework.utils.BaseTestCase; public class KastModuleTest extends BaseTestCase { - @Test - public void testCreateInjection() { - String[] argv = new String[] { "foo.c" }; - List modules = KastFrontEnd.getModules(); - Injector injector = Guice.createInjector(Modules.override(modules).with(new TestModule(), new DefinitionSpecificTestModule())); - prepInjector(injector, "-kast", argv); - assertTrue(injector.getInstance(FrontEnd.class) instanceof KastFrontEnd); - } + @Test + public void testCreateInjection() { + String[] argv = new String[] {"foo.c"}; + List modules = KastFrontEnd.getModules(); + Injector injector = + Guice.createInjector( + Modules.override(modules).with(new TestModule(), new DefinitionSpecificTestModule())); + prepInjector(injector, "-kast", argv); + assertTrue(injector.getInstance(FrontEnd.class) instanceof KastFrontEnd); + } } diff --git a/kernel/src/test/java/org/kframework/kompile/KompileFrontEndTest.java b/kernel/src/test/java/org/kframework/kompile/KompileFrontEndTest.java index 2f149f96629..d917d1fe3cd 100644 --- a/kernel/src/test/java/org/kframework/kompile/KompileFrontEndTest.java +++ b/kernel/src/test/java/org/kframework/kompile/KompileFrontEndTest.java @@ -1,7 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kompile; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + import com.google.inject.util.Providers; +import java.io.IOException; import org.junit.Test; import org.kframework.main.GlobalOptions; import org.kframework.utils.IOTestCase; @@ -11,38 +15,54 @@ import org.kframework.utils.options.OuterParsingOptions; import org.mockito.Mock; -import java.io.IOException; +public class KompileFrontEndTest extends IOTestCase { -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; + @Mock org.kframework.compile.Backend koreBackend; -public class KompileFrontEndTest extends IOTestCase { + @Mock JarInfo jarInfo; + + @Mock FileUtil files; + + KompileOptions options = new KompileOptions(); + OuterParsingOptions outerOptions = new OuterParsingOptions(); + InnerParsingOptions innerOptions = new InnerParsingOptions(); + GlobalOptions globalOptions = new GlobalOptions(); + + @Test + public void testHelp() throws IOException { + globalOptions.help = true; + new KompileFrontEnd( + options, + outerOptions, + innerOptions, + globalOptions, + "foo", + Providers.of(koreBackend), + sw, + kem, + loader, + jarInfo, + Providers.of(files)) + .main(); + assertEquals("foo", stdout.toString()); + } - @Mock - org.kframework.compile.Backend koreBackend; - - @Mock - JarInfo jarInfo; - - @Mock - FileUtil files; - - KompileOptions options = new KompileOptions(); - OuterParsingOptions outerOptions = new OuterParsingOptions(); - InnerParsingOptions innerOptions = new InnerParsingOptions(); - GlobalOptions globalOptions = new GlobalOptions(); - - @Test - public void testHelp() throws IOException { - globalOptions.help = true; - new KompileFrontEnd(options, outerOptions, innerOptions, globalOptions, "foo", Providers.of(koreBackend), sw, kem, loader, jarInfo, Providers.of(files)).main(); - assertEquals("foo", stdout.toString()); - } - - @Test - public void testVersion() { - globalOptions.version = true; - new KompileFrontEnd(options, outerOptions, innerOptions, globalOptions, "", Providers.of(koreBackend), sw, kem, loader, jarInfo, Providers.of(files)).main(); - verify(jarInfo).printVersionMessage(); - } + @Test + public void testVersion() { + globalOptions.version = true; + new KompileFrontEnd( + options, + outerOptions, + innerOptions, + globalOptions, + "", + Providers.of(koreBackend), + sw, + kem, + loader, + jarInfo, + Providers.of(files)) + .main(); + verify(jarInfo).printVersionMessage(); + } } diff --git a/kernel/src/test/java/org/kframework/kompile/KompileModuleTest.java b/kernel/src/test/java/org/kframework/kompile/KompileModuleTest.java index 8c06faf76b1..f274263bf32 100644 --- a/kernel/src/test/java/org/kframework/kompile/KompileModuleTest.java +++ b/kernel/src/test/java/org/kframework/kompile/KompileModuleTest.java @@ -1,6 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kompile; +import static org.junit.Assert.*; + import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.util.Modules; @@ -9,23 +11,27 @@ import org.kframework.main.FrontEnd; import org.kframework.utils.BaseTestCase; -import static org.junit.Assert.*; - public class KompileModuleTest extends BaseTestCase { - @Test - public void testCreateInjection() { - String[] argv = new String[] { "test.k", "--backend", "test" }; - Injector injector = Guice.createInjector(Modules.override(KompileFrontEnd.getModules()).with(new DefinitionSpecificTestModule(), new TestModule())); - prepInjector(injector, "-kompile", argv); - assertTrue(injector.getInstance(FrontEnd.class) instanceof KompileFrontEnd); - } + @Test + public void testCreateInjection() { + String[] argv = new String[] {"test.k", "--backend", "test"}; + Injector injector = + Guice.createInjector( + Modules.override(KompileFrontEnd.getModules()) + .with(new DefinitionSpecificTestModule(), new TestModule())); + prepInjector(injector, "-kompile", argv); + assertTrue(injector.getInstance(FrontEnd.class) instanceof KompileFrontEnd); + } - @Test - public void testKDep() { - String[] argv = new String[] { "test.k" }; - Injector injector = Guice.createInjector(Modules.override(KDepFrontEnd.getModules()).with(new DefinitionSpecificTestModule(), new TestModule())); - prepInjector(injector, "-kdep", argv); - assertTrue(injector.getInstance(FrontEnd.class) instanceof KDepFrontEnd); - } + @Test + public void testKDep() { + String[] argv = new String[] {"test.k"}; + Injector injector = + Guice.createInjector( + Modules.override(KDepFrontEnd.getModules()) + .with(new DefinitionSpecificTestModule(), new TestModule())); + prepInjector(injector, "-kdep", argv); + assertTrue(injector.getInstance(FrontEnd.class) instanceof KDepFrontEnd); + } } diff --git a/kernel/src/test/java/org/kframework/kompile/KompileOptionsTest.java b/kernel/src/test/java/org/kframework/kompile/KompileOptionsTest.java index dfba3480163..07af31229ff 100644 --- a/kernel/src/test/java/org/kframework/kompile/KompileOptionsTest.java +++ b/kernel/src/test/java/org/kframework/kompile/KompileOptionsTest.java @@ -1,11 +1,14 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kompile; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + import com.beust.jcommander.JCommander; +import java.io.File; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.kframework.backend.Backends; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; @@ -15,54 +18,49 @@ import org.mockito.runners.MockitoJUnitRunner; import org.mockito.stubbing.Answer; -import java.io.File; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - @RunWith(MockitoJUnitRunner.class) public class KompileOptionsTest { - private KompileOptions options; + private KompileOptions options; - @Mock - KExceptionManager kem; + @Mock KExceptionManager kem; - @Mock - FileUtil files; + @Mock FileUtil files; - @Before - public void setUp() { - options = new KompileOptions(); - when(files.resolveWorkingDirectory(Matchers.anyString())).thenAnswer(new Answer() { - @Override - public File answer(InvocationOnMock invocation) throws Throwable { + @Before + public void setUp() { + options = new KompileOptions(); + when(files.resolveWorkingDirectory(Matchers.anyString())) + .thenAnswer( + new Answer() { + @Override + public File answer(InvocationOnMock invocation) throws Throwable { return new File((String) invocation.getArguments()[0]); - } - }); - } + } + }); + } - private void parse(String... args) { - new JCommander(options, args); - options.outerParsing.mainDefinitionFile(files); - options.mainModule(files); - options.syntaxModule(files); - } + private void parse(String... args) { + new JCommander(options, args); + options.outerParsing.mainDefinitionFile(files); + options.mainModule(files); + options.syntaxModule(files); + } - @Test(expected=KEMException.class) - public void testNoDefinition() throws Exception { - parse(); - } + @Test(expected = KEMException.class) + public void testNoDefinition() throws Exception { + parse(); + } - @Test - public void testDefaultModuleName() { - parse("foo.k"); - assertEquals("FOO", options.mainModule(files)); - } + @Test + public void testDefaultModuleName() { + parse("foo.k"); + assertEquals("FOO", options.mainModule(files)); + } - @Test - public void testDefaultSyntaxModuleName() { - parse("--main-module", "BAR", "foo.k"); - assertEquals("BAR-SYNTAX", options.syntaxModule(files)); - } + @Test + public void testDefaultSyntaxModuleName() { + parse("--main-module", "BAR", "foo.k"); + assertEquals("BAR-SYNTAX", options.syntaxModule(files)); + } } diff --git a/kernel/src/test/java/org/kframework/kore/compile/AddParentsCellsTest.java b/kernel/src/test/java/org/kframework/kore/compile/AddParentsCellsTest.java index 42d2fe2bf30..e9b57e960b7 100644 --- a/kernel/src/test/java/org/kframework/kore/compile/AddParentsCellsTest.java +++ b/kernel/src/test/java/org/kframework/kore/compile/AddParentsCellsTest.java @@ -2,234 +2,340 @@ package org.kframework.compile; +import static org.kframework.compile.ConfigurationInfo.Multiplicity.*; +import static org.kframework.kore.KORE.*; import com.google.common.collect.Lists; +import java.util.Arrays; import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.kframework.builtin.KLabels; -import org.kframework.compile.ConfigurationInfo; -import org.kframework.compile.LabelInfo; import org.kframework.kore.*; import org.kframework.utils.errorsystem.KEMException; -import java.util.Arrays; +public class AddParentsCellsTest { + @Rule public final ExpectedException exception = ExpectedException.none(); -import static org.kframework.kore.KORE.*; -import static org.kframework.compile.ConfigurationInfo.Multiplicity.*; + final ConfigurationInfo cfgInfo = + new TestConfiguration() { + { + addCell(null, "TCell", ""); + addCell("TCell", "TSCell", ""); + addCell("TCell", "StateCell", ""); + addCell("TSCell", "tCell", "", STAR); + addCell("TSCell", "SchedulerCell", ""); + addCell("tCell", "KCell", ""); + addCell("tCell", "EnvCell", ""); + addCell("tCell", "MsgCell", "", STAR); + addCell("MsgCell", "MsgIdCell", ""); + } + }; + final LabelInfo labelInfo = + new LabelInfo() { + { + addLabel(Sort("TCell"), ""); + addLabel(Sort("TSCell"), ""); + addLabel(Sort("tCell"), ""); + addLabel(Sort("StateCell"), ""); + addLabel(Sort("SchedulerCell"), ""); + addLabel(Sort("KCell"), ""); + addLabel(Sort("EnvCell"), ""); + addLabel(Sort("MsgCell"), ""); + addLabel(Sort("MsgIdCell"), ""); + } + }; + final AddParentCells pass = new AddParentCells(cfgInfo, labelInfo); -public class AddParentsCellsTest { - @Rule - public final ExpectedException exception = ExpectedException.none(); - - final ConfigurationInfo cfgInfo = new TestConfiguration() {{ - addCell(null, "TCell", ""); - addCell("TCell", "TSCell", ""); - addCell("TCell", "StateCell", ""); - addCell("TSCell", "tCell", "", STAR); - addCell("TSCell", "SchedulerCell", ""); - addCell("tCell", "KCell", ""); - addCell("tCell", "EnvCell", ""); - addCell("tCell", "MsgCell", "", STAR); - addCell("MsgCell", "MsgIdCell", ""); - }}; - final LabelInfo labelInfo = new LabelInfo() {{ - addLabel(Sort("TCell"),""); - addLabel(Sort("TSCell"),""); - addLabel(Sort("tCell"),""); - addLabel(Sort("StateCell"),""); - addLabel(Sort("SchedulerCell"),""); - addLabel(Sort("KCell"),""); - addLabel(Sort("EnvCell"),""); - addLabel(Sort("MsgCell"),""); - addLabel(Sort("MsgIdCell"),""); - }}; - final AddParentCells pass = new AddParentCells(cfgInfo, labelInfo); - - @Test - public void testOneLeafCellNoCompletion() { - K term = cell("", intToToken(2)); - K expected = cell("", intToToken(2)); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testTwoCellsNoCompletion() { - K term = cell("", cell("", intToToken(2))); - K expected = cell("", cell("", intToToken(2))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testTwoCellsCompletion() { - K term = cell("", cell("", intToToken(2))); - K expected = cell("", cell("", cell("", intToToken(2)))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testMultiplicitySeparate() { - K term = cell("", cell("", intToToken(1)), cell("", intToToken(2))); - K expected = cell("", cell("", cell("", intToToken(1))), - cell("", cell("", intToToken(2)))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testMultiplicityShared() { - K term = cell("", cell("", intToToken(1)), cell("", intToToken(2))); - K expected = cell("", cell("", cell("", intToToken(1)), cell("", intToToken(2)))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test(expected = KEMException.class) - public void testAmbiguityError() { - K term = cell("", cell("", intToToken(1)), cell("", intToToken(2)), cell("", intToToken(2))); - pass.concretizeCell(term); - } - - @Test - public void testDeep2() { - Assert.assertEquals(Lists.newArrayList(cell("", cell("", intToToken(1)), cell("", intToToken(2)))), - pass.makeParents(KLabel(""), false, Lists.newArrayList(cell("", intToToken(1)), cell("", intToToken(2))))); - } - - @Test - public void testDeep() { - K term = cell("", cell("", intToToken(1)), cell("", intToToken(2))); - K expected = cell("", cell("", cell("", cell("", intToToken(1))), + @Test + public void testOneLeafCellNoCompletion() { + K term = cell("", intToToken(2)); + K expected = cell("", intToToken(2)); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testTwoCellsNoCompletion() { + K term = cell("", cell("", intToToken(2))); + K expected = cell("", cell("", intToToken(2))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testTwoCellsCompletion() { + K term = cell("", cell("", intToToken(2))); + K expected = cell("", cell("", cell("", intToToken(2)))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testMultiplicitySeparate() { + K term = cell("", cell("", intToToken(1)), cell("", intToToken(2))); + K expected = + cell( + "", + cell("", cell("", intToToken(1))), + cell("", cell("", intToToken(2)))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testMultiplicityShared() { + K term = cell("", cell("", intToToken(1)), cell("", intToToken(2))); + K expected = + cell("", cell("", cell("", intToToken(1)), cell("", intToToken(2)))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test(expected = KEMException.class) + public void testAmbiguityError() { + K term = + cell( + "", + cell("", intToToken(1)), + cell("", intToToken(2)), + cell("", intToToken(2))); + pass.concretizeCell(term); + } + + @Test + public void testDeep2() { + Assert.assertEquals( + Lists.newArrayList(cell("", cell("", intToToken(1)), cell("", intToToken(2)))), + pass.makeParents( + KLabel(""), + false, + Lists.newArrayList(cell("", intToToken(1)), cell("", intToToken(2))))); + } + + @Test + public void testDeep() { + K term = cell("", cell("", intToToken(1)), cell("", intToToken(2))); + K expected = + cell( + "", + cell( + "", + cell("", cell("", intToToken(1))), cell("", cell("", intToToken(2))))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } + Assert.assertEquals(expected, pass.concretizeCell(term)); + } - @Test - public void testRewrites() { - K term = cell("", cell("", intToToken(1)), KRewrite(cell("", intToToken(2)), cell(""))); - K expected = cell("", cell("", + @Test + public void testRewrites() { + K term = + cell("", cell("", intToToken(1)), KRewrite(cell("", intToToken(2)), cell(""))); + K expected = + cell( + "", + cell( + "", cell("", cell("", intToToken(1))), cell("", KRewrite(cell("", intToToken(2)), cell(""))))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } + Assert.assertEquals(expected, pass.concretizeCell(term)); + } - @Test - public void testRewriteWithCells() { - K term = cell("", cell("", intToToken(1)), KRewrite(cells(cell("", intToToken(2)), cell("")), cell(""))); - K expected = cell("", cell("", + @Test + public void testRewriteWithCells() { + K term = + cell( + "", + cell("", intToToken(1)), + KRewrite(cells(cell("", intToToken(2)), cell("")), cell(""))); + K expected = + cell( + "", + cell( + "", cell("", cell("", intToToken(1))), - cell("", KRewrite(cells(cell("", intToToken(2)), cell("")), cell(""))))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testRewriteWithCellVariable() { - K term = cell("", KRewrite(KVariable("KCell", Att().add(Sort.class, Sort("KCell"))), cell("", intToToken(1)))); - K expected = cell("", cell("", - cell("", KRewrite(KVariable("KCell", Att().add(Sort.class, Sort("KCell"))), cell("", intToToken(1)))))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testEmptySide() { - K term = cell("", cell(""), KRewrite(cell(""), cells())); - K expected = cell("", cell("", cell("", cell(""), KRewrite(cell(""), cells())))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testTwoRewritesFit() { - K term = cell("", KRewrite(cells(), cell("", intToToken(1))), - KRewrite(cell("", intToToken(2)), cells())); - K expected = cell("", cell("", cell("", - KRewrite(cells(), cell("", intToToken(1))), - KRewrite(cell("", intToToken(2)), cells())))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testThreeRewritesSplit() { - K term = cell("", - KRewrite(cells(cell(""),cell("")), cells()), - KRewrite(cell(""), cell("")), - KRewrite(cell(""), cell(""))); - K expected = cell("", cell("", - cell("", KRewrite(cells(cell(""),cell("")), cells())), + cell( + "", + KRewrite(cells(cell("", intToToken(2)), cell("")), cell(""))))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testRewriteWithCellVariable() { + K term = + cell( + "", + KRewrite( + KVariable("KCell", Att().add(Sort.class, Sort("KCell"))), + cell("", intToToken(1)))); + K expected = + cell( + "", + cell( + "", + cell( + "", + KRewrite( + KVariable("KCell", Att().add(Sort.class, Sort("KCell"))), + cell("", intToToken(1)))))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testEmptySide() { + K term = cell("", cell(""), KRewrite(cell(""), cells())); + K expected = + cell("", cell("", cell("", cell(""), KRewrite(cell(""), cells())))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testTwoRewritesFit() { + K term = + cell( + "", + KRewrite(cells(), cell("", intToToken(1))), + KRewrite(cell("", intToToken(2)), cells())); + K expected = + cell( + "", + cell( + "", + cell( + "", + KRewrite(cells(), cell("", intToToken(1))), + KRewrite(cell("", intToToken(2)), cells())))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testThreeRewritesSplit() { + K term = + cell( + "", + KRewrite(cells(cell(""), cell("")), cells()), + KRewrite(cell(""), cell("")), + KRewrite(cell(""), cell(""))); + K expected = + cell( + "", + cell( + "", + cell("", KRewrite(cells(cell(""), cell("")), cells())), cell("", KRewrite(cell(""), cell(""))), cell("", KRewrite(cell(""), cell(""))))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } + Assert.assertEquals(expected, pass.concretizeCell(term)); + } - @Test - public void testDotsApart() { - K term = cell("", true, false, cell("", intToToken(1)), cell("", intToToken(2))); - K expected = cell("", true, true, cell("", true, true, + @Test + public void testDotsApart() { + K term = cell("", true, false, cell("", intToToken(1)), cell("", intToToken(2))); + K expected = + cell( + "", + true, + true, + cell( + "", + true, + true, cell("", true, true, cell("", intToToken(1))), cell("", true, true, cell("", intToToken(2))))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testDotsTogether() { - K term = cell("", true, false, cell("", intToToken(0)), cell("",intToToken(2))); - K expected = cell("", true, true, cell("", true, true, - cell("", intToToken(0)), cell("",intToToken(2)))); - Assert.assertEquals(expected, pass.concretizeCell(term)); - } - - @Test - public void testNestedCompletion() { - K term = cell("", - cell("", cell("", intToToken(0)), cell("", intToToken(1))), - cell("", intToToken(2)), - cell("", intToToken(3)), - cell("", intToToken(4)), - cell("", intToToken(5)), - cell("", cell("", intToToken(6)))); - K expected = cell("",cell("", - cell("", cell("", intToToken(0)), cell("", cell("", intToToken(1)))), + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testDotsTogether() { + K term = cell("", true, false, cell("", intToToken(0)), cell("", intToToken(2))); + K expected = + cell( + "", + true, + true, + cell("", true, true, cell("", intToToken(0)), cell("", intToToken(2)))); + Assert.assertEquals(expected, pass.concretizeCell(term)); + } + + @Test + public void testNestedCompletion() { + K term = + cell( + "", + cell("", cell("", intToToken(0)), cell("", intToToken(1))), + cell("", intToToken(2)), + cell("", intToToken(3)), + cell("", intToToken(4)), + cell("", intToToken(5)), + cell("", cell("", intToToken(6)))); + K expected = + cell( + "", + cell( + "", + cell( + "", + cell("", intToToken(0)), + cell("", cell("", intToToken(1)))), cell("", cell("", intToToken(6))), - cell("", cell("", intToToken(2)), cell("", intToToken(3)), + cell( + "", + cell("", intToToken(2)), + cell("", intToToken(3)), cell("", cell("", intToToken(4))), - cell("", cell("", intToToken(5)))) - )); - Assert.assertEquals(expected, pass.concretize(term)); - - } - - @Test - public void testLeafContent() { - K term = cell("", cell("", - KSequence(KApply(KLabel("_+_"), KVariable("I"), KVariable("J")), - KVariable("Rest")))); - K expected = cell("", cell("", cell("", cell("", - KSequence(KApply(KLabel("_+_"), KVariable("I"), KVariable("J")), - KVariable("Rest")))))); - Assert.assertEquals(expected, pass.concretize(term)); - } - - @Test - public void testNonCellItem() { - K term = cell("", KApply(KLabel(".K")), cell("",KVariable("X"))); - K expected = cell("",cells(KApply(KLabel(".K")), cell("", cell("", cell("", KVariable("X")))))); - Assert.assertEquals(expected, pass.concretize(term)); - } - - @Test - public void testNonCellItemRewrite() { - K term = cell("", KRewrite(KApply(KLabel("label")),cells(KApply(KLabel(".K")), cell("",KVariable("X"))))); - exception.expect(KEMException.class); - exception.expectMessage("Can't mix items with different parent cells under a rewrite"); - pass.concretize(term); - } - - KApply cell(String name, K... ks) { - return cell(name, false, false, ks); - } - KApply cell(String name, boolean openLeft, boolean openRight, K... ks) { - return IncompleteCellUtils.make(KLabel(name), openLeft, Arrays.asList(ks), openRight); - } - - KApply cells(K... ks) { - return KApply(KLabels.CELLS, ks); - } + cell("", cell("", intToToken(5)))))); + Assert.assertEquals(expected, pass.concretize(term)); + } + + @Test + public void testLeafContent() { + K term = + cell( + "", + cell( + "", + KSequence( + KApply(KLabel("_+_"), KVariable("I"), KVariable("J")), KVariable("Rest")))); + K expected = + cell( + "", + cell( + "", + cell( + "", + cell( + "", + KSequence( + KApply(KLabel("_+_"), KVariable("I"), KVariable("J")), + KVariable("Rest")))))); + Assert.assertEquals(expected, pass.concretize(term)); + } + + @Test + public void testNonCellItem() { + K term = cell("", KApply(KLabel(".K")), cell("", KVariable("X"))); + K expected = + cell( + "", + cells(KApply(KLabel(".K")), cell("", cell("", cell("", KVariable("X")))))); + Assert.assertEquals(expected, pass.concretize(term)); + } + + @Test + public void testNonCellItemRewrite() { + K term = + cell( + "", + KRewrite( + KApply(KLabel("label")), cells(KApply(KLabel(".K")), cell("", KVariable("X"))))); + exception.expect(KEMException.class); + exception.expectMessage("Can't mix items with different parent cells under a rewrite"); + pass.concretize(term); + } + + KApply cell(String name, K... ks) { + return cell(name, false, false, ks); + } + + KApply cell(String name, boolean openLeft, boolean openRight, K... ks) { + return IncompleteCellUtils.make(KLabel(name), openLeft, Arrays.asList(ks), openRight); + } + + KApply cells(K... ks) { + return KApply(KLabels.CELLS, ks); + } } diff --git a/kernel/src/test/java/org/kframework/kore/compile/CloseCellsTest.java b/kernel/src/test/java/org/kframework/kore/compile/CloseCellsTest.java index b3a02543a55..7bf6cda9d5c 100644 --- a/kernel/src/test/java/org/kframework/kore/compile/CloseCellsTest.java +++ b/kernel/src/test/java/org/kframework/kore/compile/CloseCellsTest.java @@ -1,122 +1,164 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + +import java.util.Arrays; +import org.junit.Assert; import org.junit.Rule; +import org.junit.Test; import org.junit.rules.ExpectedException; import org.kframework.builtin.KLabels; import org.kframework.builtin.Sorts; -import org.kframework.compile.LabelInfo; import org.kframework.kore.*; - -import org.junit.Test; -import org.junit.Assert; import org.kframework.utils.errorsystem.KEMException; -import java.util.Arrays; - -import static org.kframework.kore.KORE.*; - public class CloseCellsTest { - final SortInfo sortInfo = new SortInfo() {{ - addOp(Sort("Map"), "_Map_"); - addOp(Sort("List"), "_List_"); - }}; - final TestConfiguration cfgInfo = new TestConfiguration() {{ - addCell(null, "ThreadCell", "", Multiplicity.STAR); - addCell("ThreadCell", "KCell", "", Sorts.K()); - addCell("ThreadCell", "EnvCell", "", Sort("Map")); - addCell(null, "ListCell", "", Multiplicity.STAR, Sort("List")); - addDefault("EnvCell", cell("", KApply(KLabel(".Map")))); - addDefault("KCell", cell("", stringToToken("defaultK"))); - }}; - final LabelInfo labelInfo = new LabelInfo() {{ - addLabel(Sort("KCell"), ""); - addLabel(Sort("EnvCell"), ""); - addLabel(Sort("ThreadCell"), ""); - addLabel(Sort("ListCell"), ""); - addLabel(Sort("Map"), "_Map_", true, true, true); - addLabel(Sort("List"), "_List_", true, false, true); - }}; - - @Test - public void testSimpleClosure() { - K term = cell("", false, true, KApply(KLabel("_+_"), KVariable("I"), KVariable("J"))); - K expected = ccell("", KSequence(KApply(KLabel("_+_"), KVariable("I"), KVariable("J")), + final SortInfo sortInfo = + new SortInfo() { + { + addOp(Sort("Map"), "_Map_"); + addOp(Sort("List"), "_List_"); + } + }; + final TestConfiguration cfgInfo = + new TestConfiguration() { + { + addCell(null, "ThreadCell", "", Multiplicity.STAR); + addCell("ThreadCell", "KCell", "", Sorts.K()); + addCell("ThreadCell", "EnvCell", "", Sort("Map")); + addCell(null, "ListCell", "", Multiplicity.STAR, Sort("List")); + addDefault("EnvCell", cell("", KApply(KLabel(".Map")))); + addDefault("KCell", cell("", stringToToken("defaultK"))); + } + }; + final LabelInfo labelInfo = + new LabelInfo() { + { + addLabel(Sort("KCell"), ""); + addLabel(Sort("EnvCell"), ""); + addLabel(Sort("ThreadCell"), ""); + addLabel(Sort("ListCell"), ""); + addLabel(Sort("Map"), "_Map_", true, true, true); + addLabel(Sort("List"), "_List_", true, false, true); + } + }; + + @Test + public void testSimpleClosure() { + K term = cell("", false, true, KApply(KLabel("_+_"), KVariable("I"), KVariable("J"))); + K expected = + ccell( + "", + KSequence( + KApply(KLabel("_+_"), KVariable("I"), KVariable("J")), KVariable("_DotVar0"))); + Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); + } + + @Test + public void testCloseMap() { + K term = cell("", true, false, KApply(KLabel("'_|=>_"), intToToken(1), intToToken(2))); + K expected = + ccell( + "", + KApply( + KLabel("_Map_"), + KApply(KLabel("'_|=>_"), intToToken(1), intToToken(2)), KVariable("_DotVar0"))); - Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); - } - - @Test - public void testCloseMap() { - K term = cell("", true, false, KApply(KLabel("'_|=>_"), intToToken(1), intToToken(2))); - K expected = ccell("", KApply(KLabel("_Map_"), KApply(KLabel("'_|=>_"), intToToken(1), intToToken(2)), KVariable("_DotVar0"))); - Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); - } - - @Test - public void testCloseList() { - K term = KApply(KLabels.CELLS, - cell("", true, false, intToToken(1)), - cell("", false, true, intToToken(2)), - cell("", true, true, intToToken(3))); - K expected = KApply(KLabels.CELLS, - ccell("", KApply(KLabel("_List_"), KVariable("_DotVar0"), intToToken(1))), - ccell("", KApply(KLabel("_List_"), intToToken(2), KVariable("_DotVar1"))), - ccell("", KApply(KLabel("_List_"), KVariable("_DotVar2"), KApply(KLabel("_List_"), intToToken(3), KVariable("_DotVar3"))))); - Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); - } - - @Test - public void testCloseCellVar() { - K term = KApply(KLabels.CELLS, + Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); + } + + @Test + public void testCloseList() { + K term = + KApply( + KLabels.CELLS, + cell("", true, false, intToToken(1)), + cell("", false, true, intToToken(2)), + cell("", true, true, intToToken(3))); + K expected = + KApply( + KLabels.CELLS, + ccell("", KApply(KLabel("_List_"), KVariable("_DotVar0"), intToToken(1))), + ccell("", KApply(KLabel("_List_"), intToToken(2), KVariable("_DotVar1"))), + ccell( + "", + KApply( + KLabel("_List_"), + KVariable("_DotVar2"), + KApply(KLabel("_List_"), intToToken(3), KVariable("_DotVar3"))))); + Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); + } + + @Test + public void testCloseCellVar() { + K term = + KApply( + KLabels.CELLS, + cell("", true, false, cell("", intToToken(1))), + cell("", false, true, cell("", intToToken(2))), + cell("", true, true, cell("", intToToken(2)))); + K expected = + KApply( + KLabels.CELLS, + ccell("", ccell("", intToToken(1)), KVariable("_DotVar0")), + ccell("", ccell("", intToToken(2)), KVariable("_DotVar1")), + ccell("", ccell("", intToToken(2)), KVariable("_DotVar2"))); + Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); + } + + @Rule public ExpectedException exception = ExpectedException.none(); + + @Test + public void testClosedCellError1() { + K term = cell("", cell("")); + exception.expect(KEMException.class); + exception.expectMessage("Closed parent cell missing required children [EnvCell]"); + new CloseCells(cfgInfo, sortInfo, labelInfo).close(term); + } + + @Test + public void testCloseCellTerm() { + K term = + KRewrite( + cells(), + cells( cell("", true, false, cell("", intToToken(1))), cell("", false, true, cell("", intToToken(2))), - cell("", true, true, cell("", intToToken(2)))); - K expected = KApply(KLabels.CELLS, - ccell("", ccell("", intToToken(1)), KVariable("_DotVar0")), - ccell("", ccell("", intToToken(2)), KVariable("_DotVar1")), - ccell("", ccell("", intToToken(2)), KVariable("_DotVar2"))); - Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); - } - - @Rule - public ExpectedException exception = ExpectedException.none(); - - @Test - public void testClosedCellError1() { - K term = cell("", cell("")); - exception.expect(KEMException.class); - exception.expectMessage("Closed parent cell missing required children [EnvCell]"); - new CloseCells(cfgInfo, sortInfo, labelInfo).close(term); - } - - @Test - public void testCloseCellTerm() { - K term = KRewrite(cells(), - cells(cell("", true, false, cell("", intToToken(1))), - cell("", false, true, cell("", intToToken(2))), - cell("", true, true, cell("", intToToken(2))))); - K expected = KRewrite(cells(), - cells(ccell("", ccell("", intToToken(1)), ccell("", KApply(KLabel(".Map")))), - ccell("", ccell("", intToToken(2)), ccell("", KApply(KLabel(".Map")))), - ccell("", ccell("", intToToken(2)), ccell("", stringToToken("defaultK"))))); - Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); - } - - KApply cell(String name, K... ks) { - return cell(name, false, false, ks); - } - KApply cell(String name, boolean openLeft, boolean openRight, K... ks) { - return IncompleteCellUtils.make(KLabel(name), openLeft, Arrays.asList(ks), openRight); - } - - KApply ccell(String name, K... ks) { - return KApply(KLabel(name), ks); - } - - - KApply cells(K... ks) { - return KApply(KLabels.CELLS, ks); - } + cell("", true, true, cell("", intToToken(2))))); + K expected = + KRewrite( + cells(), + cells( + ccell( + "", + ccell("", intToToken(1)), + ccell("", KApply(KLabel(".Map")))), + ccell( + "", + ccell("", intToToken(2)), + ccell("", KApply(KLabel(".Map")))), + ccell( + "", + ccell("", intToToken(2)), + ccell("", stringToToken("defaultK"))))); + Assert.assertEquals(expected, new CloseCells(cfgInfo, sortInfo, labelInfo).close(term)); + } + + KApply cell(String name, K... ks) { + return cell(name, false, false, ks); + } + + KApply cell(String name, boolean openLeft, boolean openRight, K... ks) { + return IncompleteCellUtils.make(KLabel(name), openLeft, Arrays.asList(ks), openRight); + } + + KApply ccell(String name, K... ks) { + return KApply(KLabel(name), ks); + } + + KApply cells(K... ks) { + return KApply(KLabels.CELLS, ks); + } } diff --git a/kernel/src/test/java/org/kframework/kore/compile/GenerateSentencesFromConfigDeclTest.java b/kernel/src/test/java/org/kframework/kore/compile/GenerateSentencesFromConfigDeclTest.java index 0d0da8fd386..a81b8d8d54e 100644 --- a/kernel/src/test/java/org/kframework/kore/compile/GenerateSentencesFromConfigDeclTest.java +++ b/kernel/src/test/java/org/kframework/kore/compile/GenerateSentencesFromConfigDeclTest.java @@ -1,7 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.junit.Assert.*; +import static org.kframework.Collections.*; +import static org.kframework.definition.Constructors.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Lists; +import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; import org.junit.Before; import org.junit.Test; import org.kframework.attributes.Att; @@ -24,146 +33,290 @@ import org.kframework.utils.file.FileUtil; import scala.collection.Set; -import java.io.File; -import java.util.Arrays; -import java.util.Collections; -import java.util.Map; - -import static org.junit.Assert.*; -import static org.kframework.Collections.*; -import static org.kframework.definition.Constructors.*; -import static org.kframework.kore.KORE.*; - public class GenerateSentencesFromConfigDeclTest { - Definition def; - FileUtil files; + Definition def; + FileUtil files; - @Before - public void setUp() { - String definitionText; - files = FileUtil.testFileUtil(); - ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); - File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); - definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); + @Before + public void setUp() { + String definitionText; + files = FileUtil.testFileUtil(); + ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); + File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); + definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); - def = - parser.loadDefinition("K", "K", definitionText, - definitionFile, - definitionFile.getParentFile(), - Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), - false, false, false); - } + def = + parser.loadDefinition( + "K", + "K", + definitionText, + definitionFile, + definitionFile.getParentFile(), + Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), + false, + false, + false); + } - @Test - public void testSingleTop() { - Production prod = Production(KLabel(".Opt"), Sort("OptCellContent"), Seq(Terminal(""))); - Production prod2 = Production(KLabel("#SemanticCastToKItem"), Sort("KItem"), Seq(NonTerminal(Sort("KItem")))); - K configuration = cell("threads", Collections.emptyMap(), - cell("thread", Collections.singletonMap("multiplicity", "*"), - cells(cell("k", Collections.emptyMap(), KApply(KLabel("#SemanticCastToKItem"), KList(KToken("$PGM", Sorts.KConfigVar())), Att.empty().add(Production.class, prod2))), - cell("opt", Collections.singletonMap("multiplicity", "?"), - KApply(KLabel(".Opt"), KList(), Att.empty().add(Production.class, prod)))))); - Module m1 = Module("CONFIG", Set(Import(def.getModule("KSEQ").get(), true)), Set(prod), Att()); - RuleGrammarGenerator parserGen = new RuleGrammarGenerator(def); - Module m = RuleGrammarGenerator.getCombinedGrammar(parserGen.getConfigGrammar(m1), true, files).getExtensionModule(); - Set gen = GenerateSentencesFromConfigDecl.gen(configuration, BooleanUtils.FALSE, Att(), m); - Att initializerAtts = Att().add(Att.INITIALIZER()); - Att productionAtts = initializerAtts.add(Att.FUNCTION()); - Set reference = Set(Production(KLabel(""), Sort("ThreadsCell"), - Seq(Terminal(""), NonTerminal(Sort("ThreadCellBag")), Terminal("")), - Att().add(Att.CELL()).add(Att.CELL_NAME(), "threads").add(Att.FORMAT(), "%1%i%n%2%d%n%3")), - SyntaxSort(Seq(), Sort("ThreadCellBag"), Att().add(Att.HOOK(), "BAG.Bag").add(Att.CELL_COLLECTION())), - Production(KLabel("_ThreadCellBag_"), Sort("ThreadCellBag"), - Seq(NonTerminal(Sort("ThreadCellBag")), NonTerminal(Sort("ThreadCellBag"))), - Att().add(Att.ASSOC(),"").add(Att.COMM(),"").add(Att.UNIT(),".ThreadCellBag") - .add(Att.ELEMENT(),"ThreadCellBagItem").add(Att.WRAP_ELEMENT(),"") - .add(Att.FUNCTION()).add(Att.AVOID()).add(Att.BAG()).add(Att.CELL_COLLECTION()).add(Att.HOOK(),"BAG.concat")), - Production(KLabel(".ThreadCellBag"), Sort("ThreadCellBag"), - Seq(Terminal(".ThreadCellBag")), - Att().add(Att.FUNCTION()).add(Att.HOOK(),"BAG.unit")), - Production(Seq(), Sort("ThreadCellBag"), - Seq(NonTerminal(Sort("ThreadCell")))), - Production(KLabel("ThreadCellBagItem"), Sort("ThreadCellBag"), - Seq(Terminal("ThreadCellBagItem"), Terminal("("), NonTerminal(Sort("ThreadCell")), Terminal(")")), - Att().add(Att.FUNCTION()).add(Att.HOOK(),"BAG.element").add(Att.FORMAT(), "%3")), - Production(KLabel(""), Sort("ThreadCell"), - Seq(Terminal(""), NonTerminal(Sort("KCell")), NonTerminal(Sort("OptCell")), Terminal("")), - Att().add(Att.CELL()).add(Att.CELL_NAME(), "thread").add(Att.MULTIPLICITY(),"*").add(Att.FORMAT(), "%1%i%n%2%n%3%d%n%4")), - Production(KLabel(""), Sort("KCell"), - Seq(Terminal(""), NonTerminal(Sort("K")), Terminal("")), - Att().add(Att.CELL()).add(Att.CELL_NAME(), "k").add(Att.MAINCELL()).add(Att.FORMAT(), "%1%i%n%2%d%n%3")), - Production(KLabel(""), Sort("OptCell"), - Seq(Terminal(""), NonTerminal(Sort("OptCellContent")), Terminal("")), - Att().add(Att.CELL()).add(Att.CELL_NAME(), "opt").add(Att.MULTIPLICITY(),"?").add(Att.UNIT(),".OptCell").add(Att.FORMAT(), "%1%i%n%2%d%n%3")), - Production(KLabel(".OptCell"), Sort("OptCell"), - Seq(Terminal(".OptCell"))), - Production(KLabel("initThreadsCell"), Sort("ThreadsCell"), - Seq(Terminal("initThreadsCell"), Terminal("("), NonTerminal(Sort("Map")), Terminal(")")), - productionAtts), - Production(KLabel("initThreadCell"), Sort("ThreadCellBag"), - Seq(Terminal("initThreadCell"), Terminal("("), NonTerminal(Sort("Map")), Terminal(")")), - productionAtts), - Production(KLabel("initKCell"), Sort("KCell"), - Seq(Terminal("initKCell"), Terminal("("), NonTerminal(Sort("Map")), Terminal(")")), - productionAtts), - Production(KLabel("initOptCell"), Sort("OptCell"), - Seq(Terminal("initOptCell")), - productionAtts), - Rule(KRewrite(KApply(KLabel("initThreadsCell"), KVariable("Init")), - IncompleteCellUtils.make(KLabel(""), false, - KApply(KLabel("initThreadCell"), KVariable("Init")), false)), - BooleanUtils.TRUE, BooleanUtils.FALSE, initializerAtts), - Rule(KRewrite(KApply(KLabel("initThreadCell"), KVariable("Init")), - IncompleteCellUtils.make(KLabel(""), false, - Arrays.asList(KApply(KLabel("initKCell"), KVariable("Init")), - KApply(KLabels.CELLS)), false)), - BooleanUtils.TRUE, BooleanUtils.TRUE, initializerAtts), - Rule(KRewrite(KApply(KLabel("initKCell"), KVariable("Init")), - IncompleteCellUtils.make(KLabel(""), false, KApply(KLabel("#SemanticCastToKItem"), KApply(KLabel("project:KItem"), KApply(KLabel("Map:lookup"), - KVariable("Init"), - KToken("$PGM", Sorts.KConfigVar())))), false)), - BooleanUtils.TRUE, BooleanUtils.TRUE, initializerAtts), - Rule(KRewrite(KApply(KLabel("initOptCell")), - IncompleteCellUtils.make(KLabel(""), false, KApply(KLabel(".Opt")), false)), - BooleanUtils.TRUE, BooleanUtils.TRUE, initializerAtts), - Production(KLabel("-fragment"), Sort("ThreadsCellFragment"), - Seq(Terminal("-fragment"),NonTerminal(Sort("ThreadCellBag")),Terminal("-fragment")), - Att().add(Att.CELL_FRAGMENT(),Sort.class,Sort("ThreadsCell"))), - Production(KLabel("-fragment"), Sort("ThreadCellFragment"), - Seq(Terminal("-fragment"),NonTerminal(Sort("KCellOpt")),NonTerminal(Sort("OptCellOpt")),Terminal("-fragment")), - Att().add(Att.CELL_FRAGMENT(),Sort.class,Sort("ThreadCell"))), - Production(Seq(), Sort("OptCellOpt"), Seq(NonTerminal(Sort("OptCell")))), - Production(KLabel("noOptCell"), Sort("OptCellOpt"), Seq(Terminal("noOptCell")),Att().add(Att.CELL_OPT_ABSENT(), Sort.class, Sort("OptCell"))), - Production(Seq(), Sort("KCellOpt"), Seq(NonTerminal(Sort("KCell")))), - Production(KLabel("noKCell"), Sort("KCellOpt"), Seq(Terminal("noKCell")),Att().add(Att.CELL_OPT_ABSENT(), Sort.class, Sort("KCell"))) - ); + @Test + public void testSingleTop() { + Production prod = Production(KLabel(".Opt"), Sort("OptCellContent"), Seq(Terminal(""))); + Production prod2 = + Production(KLabel("#SemanticCastToKItem"), Sort("KItem"), Seq(NonTerminal(Sort("KItem")))); + K configuration = + cell( + "threads", + Collections.emptyMap(), + cell( + "thread", + Collections.singletonMap("multiplicity", "*"), + cells( + cell( + "k", + Collections.emptyMap(), + KApply( + KLabel("#SemanticCastToKItem"), + KList(KToken("$PGM", Sorts.KConfigVar())), + Att.empty().add(Production.class, prod2))), + cell( + "opt", + Collections.singletonMap("multiplicity", "?"), + KApply( + KLabel(".Opt"), KList(), Att.empty().add(Production.class, prod)))))); + Module m1 = Module("CONFIG", Set(Import(def.getModule("KSEQ").get(), true)), Set(prod), Att()); + RuleGrammarGenerator parserGen = new RuleGrammarGenerator(def); + Module m = + RuleGrammarGenerator.getCombinedGrammar(parserGen.getConfigGrammar(m1), true, files) + .getExtensionModule(); + Set gen = + GenerateSentencesFromConfigDecl.gen(configuration, BooleanUtils.FALSE, Att(), m); + Att initializerAtts = Att().add(Att.INITIALIZER()); + Att productionAtts = initializerAtts.add(Att.FUNCTION()); + Set reference = + Set( + Production( + KLabel(""), + Sort("ThreadsCell"), + Seq( + Terminal(""), + NonTerminal(Sort("ThreadCellBag")), + Terminal("")), + Att() + .add(Att.CELL()) + .add(Att.CELL_NAME(), "threads") + .add(Att.FORMAT(), "%1%i%n%2%d%n%3")), + SyntaxSort( + Seq(), + Sort("ThreadCellBag"), + Att().add(Att.HOOK(), "BAG.Bag").add(Att.CELL_COLLECTION())), + Production( + KLabel("_ThreadCellBag_"), + Sort("ThreadCellBag"), + Seq(NonTerminal(Sort("ThreadCellBag")), NonTerminal(Sort("ThreadCellBag"))), + Att() + .add(Att.ASSOC(), "") + .add(Att.COMM(), "") + .add(Att.UNIT(), ".ThreadCellBag") + .add(Att.ELEMENT(), "ThreadCellBagItem") + .add(Att.WRAP_ELEMENT(), "") + .add(Att.FUNCTION()) + .add(Att.AVOID()) + .add(Att.BAG()) + .add(Att.CELL_COLLECTION()) + .add(Att.HOOK(), "BAG.concat")), + Production( + KLabel(".ThreadCellBag"), + Sort("ThreadCellBag"), + Seq(Terminal(".ThreadCellBag")), + Att().add(Att.FUNCTION()).add(Att.HOOK(), "BAG.unit")), + Production(Seq(), Sort("ThreadCellBag"), Seq(NonTerminal(Sort("ThreadCell")))), + Production( + KLabel("ThreadCellBagItem"), + Sort("ThreadCellBag"), + Seq( + Terminal("ThreadCellBagItem"), + Terminal("("), + NonTerminal(Sort("ThreadCell")), + Terminal(")")), + Att().add(Att.FUNCTION()).add(Att.HOOK(), "BAG.element").add(Att.FORMAT(), "%3")), + Production( + KLabel(""), + Sort("ThreadCell"), + Seq( + Terminal(""), + NonTerminal(Sort("KCell")), + NonTerminal(Sort("OptCell")), + Terminal("")), + Att() + .add(Att.CELL()) + .add(Att.CELL_NAME(), "thread") + .add(Att.MULTIPLICITY(), "*") + .add(Att.FORMAT(), "%1%i%n%2%n%3%d%n%4")), + Production( + KLabel(""), + Sort("KCell"), + Seq(Terminal(""), NonTerminal(Sort("K")), Terminal("")), + Att() + .add(Att.CELL()) + .add(Att.CELL_NAME(), "k") + .add(Att.MAINCELL()) + .add(Att.FORMAT(), "%1%i%n%2%d%n%3")), + Production( + KLabel(""), + Sort("OptCell"), + Seq(Terminal(""), NonTerminal(Sort("OptCellContent")), Terminal("")), + Att() + .add(Att.CELL()) + .add(Att.CELL_NAME(), "opt") + .add(Att.MULTIPLICITY(), "?") + .add(Att.UNIT(), ".OptCell") + .add(Att.FORMAT(), "%1%i%n%2%d%n%3")), + Production(KLabel(".OptCell"), Sort("OptCell"), Seq(Terminal(".OptCell"))), + Production( + KLabel("initThreadsCell"), + Sort("ThreadsCell"), + Seq( + Terminal("initThreadsCell"), + Terminal("("), + NonTerminal(Sort("Map")), + Terminal(")")), + productionAtts), + Production( + KLabel("initThreadCell"), + Sort("ThreadCellBag"), + Seq( + Terminal("initThreadCell"), + Terminal("("), + NonTerminal(Sort("Map")), + Terminal(")")), + productionAtts), + Production( + KLabel("initKCell"), + Sort("KCell"), + Seq(Terminal("initKCell"), Terminal("("), NonTerminal(Sort("Map")), Terminal(")")), + productionAtts), + Production( + KLabel("initOptCell"), + Sort("OptCell"), + Seq(Terminal("initOptCell")), + productionAtts), + Rule( + KRewrite( + KApply(KLabel("initThreadsCell"), KVariable("Init")), + IncompleteCellUtils.make( + KLabel(""), + false, + KApply(KLabel("initThreadCell"), KVariable("Init")), + false)), + BooleanUtils.TRUE, + BooleanUtils.FALSE, + initializerAtts), + Rule( + KRewrite( + KApply(KLabel("initThreadCell"), KVariable("Init")), + IncompleteCellUtils.make( + KLabel(""), + false, + Arrays.asList( + KApply(KLabel("initKCell"), KVariable("Init")), KApply(KLabels.CELLS)), + false)), + BooleanUtils.TRUE, + BooleanUtils.TRUE, + initializerAtts), + Rule( + KRewrite( + KApply(KLabel("initKCell"), KVariable("Init")), + IncompleteCellUtils.make( + KLabel(""), + false, + KApply( + KLabel("#SemanticCastToKItem"), + KApply( + KLabel("project:KItem"), + KApply( + KLabel("Map:lookup"), + KVariable("Init"), + KToken("$PGM", Sorts.KConfigVar())))), + false)), + BooleanUtils.TRUE, + BooleanUtils.TRUE, + initializerAtts), + Rule( + KRewrite( + KApply(KLabel("initOptCell")), + IncompleteCellUtils.make( + KLabel(""), false, KApply(KLabel(".Opt")), false)), + BooleanUtils.TRUE, + BooleanUtils.TRUE, + initializerAtts), + Production( + KLabel("-fragment"), + Sort("ThreadsCellFragment"), + Seq( + Terminal("-fragment"), + NonTerminal(Sort("ThreadCellBag")), + Terminal("-fragment")), + Att().add(Att.CELL_FRAGMENT(), Sort.class, Sort("ThreadsCell"))), + Production( + KLabel("-fragment"), + Sort("ThreadCellFragment"), + Seq( + Terminal("-fragment"), + NonTerminal(Sort("KCellOpt")), + NonTerminal(Sort("OptCellOpt")), + Terminal("-fragment")), + Att().add(Att.CELL_FRAGMENT(), Sort.class, Sort("ThreadCell"))), + Production(Seq(), Sort("OptCellOpt"), Seq(NonTerminal(Sort("OptCell")))), + Production( + KLabel("noOptCell"), + Sort("OptCellOpt"), + Seq(Terminal("noOptCell")), + Att().add(Att.CELL_OPT_ABSENT(), Sort.class, Sort("OptCell"))), + Production(Seq(), Sort("KCellOpt"), Seq(NonTerminal(Sort("KCell")))), + Production( + KLabel("noKCell"), + Sort("KCellOpt"), + Seq(Terminal("noKCell")), + Att().add(Att.CELL_OPT_ABSENT(), Sort.class, Sort("KCell")))); - assertEquals("Produced unexpected productions", Set(), gen.$amp$tilde(reference)); - assertEquals("Missing expected productions", Set(), reference.$amp$tilde(gen)); - // Production.equals ignores attributes, but they are important here - nextgen: - for (Sentence g : iterable(gen)) { - for (Sentence r : iterable(reference)) { - if (g.equals(r)) { - assertEquals("Production "+r+" generated with incorrect attributes", r.att(), g.att()); - continue nextgen; - } - } - assert false; // We checked set equality above + assertEquals("Produced unexpected productions", Set(), gen.$amp$tilde(reference)); + assertEquals("Missing expected productions", Set(), reference.$amp$tilde(gen)); + // Production.equals ignores attributes, but they are important here + nextgen: + for (Sentence g : iterable(gen)) { + for (Sentence r : iterable(reference)) { + if (g.equals(r)) { + assertEquals( + "Production " + r + " generated with incorrect attributes", r.att(), g.att()); + continue nextgen; } + } + assert false; // We checked set equality above } + } - private KApply cells(K cell1, K cell2) { - return KApply(KLabels.CELLS, cell1, cell2); - } + private KApply cells(K cell1, K cell2) { + return KApply(KLabels.CELLS, cell1, cell2); + } - private KApply cell(String s, Map att, K body) { - K cellAtt = att.entrySet().stream() - .map(e -> KApply(KLabel("#cellProperty"), + private KApply cell(String s, Map att, K body) { + K cellAtt = + att.entrySet().stream() + .map( + e -> + KApply( + KLabel("#cellProperty"), KToken(e.getKey(), Sort("#CellName")), KToken(StringUtil.enquoteKString(e.getValue()), Sort("KString")))) - .reduce(KApply(KLabel("#cellPropertyListTerminator")), (k1, k2) -> KApply(KLabel("#cellPropertyList"), k2, k1)); - return KApply(KLabel("#configCell"), KToken(s, Sort("#CellName")), cellAtt, body, KToken(s, Sort("#CellName"))); - } + .reduce( + KApply(KLabel("#cellPropertyListTerminator")), + (k1, k2) -> KApply(KLabel("#cellPropertyList"), k2, k1)); + return KApply( + KLabel("#configCell"), + KToken(s, Sort("#CellName")), + cellAtt, + body, + KToken(s, Sort("#CellName"))); + } } diff --git a/kernel/src/test/java/org/kframework/kore/compile/SortCellsTest.java b/kernel/src/test/java/org/kframework/kore/compile/SortCellsTest.java index e74c58df737..ab45cea4e23 100644 --- a/kernel/src/test/java/org/kframework/kore/compile/SortCellsTest.java +++ b/kernel/src/test/java/org/kframework/kore/compile/SortCellsTest.java @@ -1,6 +1,8 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import org.junit.Assert; import org.junit.Test; import org.kframework.builtin.BooleanUtils; @@ -14,311 +16,513 @@ import org.kframework.main.GlobalOptions; import org.kframework.utils.errorsystem.KExceptionManager; -import static org.kframework.kore.KORE.*; - /** * Rearrange partially-completed cells to follow the productions declaring them. * - * The main complexity here is eliminating cell fragment variables that might - * capture multiple cells. In the general case a variable needs to be - * replaced under cells with separate variables in several slots of the - * parent and in other places with an appropriate bag expression. + *

The main complexity here is eliminating cell fragment variables that might capture multiple + * cells. In the general case a variable needs to be replaced under cells with separate variables in + * several slots of the parent and in other places with an appropriate bag expression. */ public class SortCellsTest { - ConfigurationInfo cfgInfo = new TestConfiguration() {{ - addCell(null, "TopCell", ""); - addCell("TopCell", "ThreadCell", "", Multiplicity.STAR); - addCell("ThreadCell", "KCell", "", Sorts.K()); - addCell("ThreadCell", "EnvCell", "", Sort("Map")); - addCell("ThreadCell", "OptCell", "", Multiplicity.OPTIONAL, Sorts.K()); - addUnit("OptCell", KLabel(".OptCell")); - addUnit("ThreadCell", KLabel(".ThreadCellBag")); - addConcat("ThreadCell", KLabel("_ThreadCellBag_")); - }}; - LabelInfo labelInfo = new LabelInfo() {{ - addLabel(Sort("TopCell"), ""); - addLabel(Sort("ThreadCell"), ""); - addLabel(Sort("KCell"), ""); - addLabel(Sort("EnvCell"), ""); - addLabel(Sort("OptCell"), ""); - }}; - - @Test - public void testSimpleSplitting() { - KVariable Y = KVariable("Y", Att().add(Sort.class, Sort("OptCell"))); - K term = KRewrite(cell("", cell(""), KVariable("X"), Y), KVariable("X")); - K expected = KRewrite(cell("", KVariable("X"), cell(""), Y), cell("-fragment", KVariable("X"), app("noEnvCell"), app(".OptCell"))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + ConfigurationInfo cfgInfo = + new TestConfiguration() { + { + addCell(null, "TopCell", ""); + addCell("TopCell", "ThreadCell", "", Multiplicity.STAR); + addCell("ThreadCell", "KCell", "", Sorts.K()); + addCell("ThreadCell", "EnvCell", "", Sort("Map")); + addCell("ThreadCell", "OptCell", "", Multiplicity.OPTIONAL, Sorts.K()); + addUnit("OptCell", KLabel(".OptCell")); + addUnit("ThreadCell", KLabel(".ThreadCellBag")); + addConcat("ThreadCell", KLabel("_ThreadCellBag_")); + } + }; + LabelInfo labelInfo = + new LabelInfo() { + { + addLabel(Sort("TopCell"), ""); + addLabel(Sort("ThreadCell"), ""); + addLabel(Sort("KCell"), ""); + addLabel(Sort("EnvCell"), ""); + addLabel(Sort("OptCell"), ""); + } + }; - /** - * Ensure that a variable does not become a cell fragment if it is annotated - * with a single-cell sort. - */ - @Test - public void testSortedVar() { - KVariable Y = KVariable("Y", Att().add(Sort.class, Sort("OptCell"))); - K term = KRewrite(cell("", cell(""), KVariable("X"), Y), Y); - K expected = KRewrite(cell("", KVariable("X"), cell(""), Y), Y); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testSimpleSplitting() { + KVariable Y = KVariable("Y", Att().add(Sort.class, Sort("OptCell"))); + K term = KRewrite(cell("", cell(""), KVariable("X"), Y), KVariable("X")); + K expected = + KRewrite( + cell("", KVariable("X"), cell(""), Y), + cell("-fragment", KVariable("X"), app("noEnvCell"), app(".OptCell"))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testUselessVariable() { - K term = cell("", cell(""), cell(""), cell(""), KVariable("X")); - K expected = cell("", cell(""), cell(""), cell("")); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + /** + * Ensure that a variable does not become a cell fragment if it is annotated with a single-cell + * sort. + */ + @Test + public void testSortedVar() { + KVariable Y = KVariable("Y", Att().add(Sort.class, Sort("OptCell"))); + K term = KRewrite(cell("", cell(""), KVariable("X"), Y), Y); + K expected = KRewrite(cell("", KVariable("X"), cell(""), Y), Y); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testMultipleSplit() { - K term = KRewrite(cell("", KVariable("X")), KVariable("Y")); - K expected = KRewrite(cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")), KVariable("Y")); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testUselessVariable() { + K term = cell("", cell(""), cell(""), cell(""), KVariable("X")); + K expected = cell("", cell(""), cell(""), cell("")); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testAddOptCell() { - K term = cell("", KVariable("X"), KRewrite(cells(), cell(""))); - K expected = cell("", KVariable("_Gen0"), KVariable("_Gen1"), KRewrite(KApply(KLabel(".OptCell")), cell(""))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testMultipleSplit() { + K term = KRewrite(cell("", KVariable("X")), KVariable("Y")); + K expected = + KRewrite( + cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")), + KVariable("Y")); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testRemoveOptCell() { - K term = cell("", KVariable("X"), KRewrite(cell(""), cells())); - K expected = cell("", KVariable("_Gen0"), KVariable("_Gen1"), KRewrite(cell(""), KApply(KLabel(".OptCell")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testAddOptCell() { + K term = cell("", KVariable("X"), KRewrite(cells(), cell(""))); + K expected = + cell( + "", + KVariable("_Gen0"), + KVariable("_Gen1"), + KRewrite(KApply(KLabel(".OptCell")), cell(""))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testAddStarCell() { - K term = cell("", KRewrite(cells(), cell("", KVariable("X")))); - K expected = cell("", KRewrite(KApply(KLabel(".ThreadCellBag")), cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testRemoveOptCell() { + K term = cell("", KVariable("X"), KRewrite(cell(""), cells())); + K expected = + cell( + "", + KVariable("_Gen0"), + KVariable("_Gen1"), + KRewrite(cell(""), KApply(KLabel(".OptCell")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testRemoveStarCell() { - K term = cell("", KRewrite(cell("", KVariable("X")), cells())); - K expected = cell("", KRewrite(cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")), KApply(KLabel(".ThreadCellBag")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testAddStarCell() { + K term = cell("", KRewrite(cells(), cell("", KVariable("X")))); + K expected = + cell( + "", + KRewrite( + KApply(KLabel(".ThreadCellBag")), + cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } + @Test + public void testRemoveStarCell() { + K term = cell("", KRewrite(cell("", KVariable("X")), cells())); + K expected = + cell( + "", + KRewrite( + cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")), + KApply(KLabel(".ThreadCellBag")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testConcatStarCell() { - K term = cell("", KRewrite(KVariable("Y"), cells(KVariable("Y"), cell("", KVariable("X"))))); - K expected = cell("", KRewrite(KVariable("Y"), KApply(KLabel("_ThreadCellBag_"), KVariable("Y"), cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2"))))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testConcatStarCell() { + K term = + cell("", KRewrite(KVariable("Y"), cells(KVariable("Y"), cell("", KVariable("X"))))); + K expected = + cell( + "", + KRewrite( + KVariable("Y"), + KApply( + KLabel("_ThreadCellBag_"), + KVariable("Y"), + cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2"))))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testConcatStarCellEmptyl() { - K term = cell("", KRewrite(KVariable("Y"), cells())); - K expected = cell("", KRewrite(KVariable("Y"), KApply(KLabel(".ThreadCellBag")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testConcatStarCellEmptyl() { + K term = cell("", KRewrite(KVariable("Y"), cells())); + K expected = cell("", KRewrite(KVariable("Y"), KApply(KLabel(".ThreadCellBag")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - @Test - public void testFragment1() { - K term = cell("",cell("",KVariable("F")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), KSequence(KVariable("F"), KVariable("Rest")))), KVariable("F2"))); - K expected = cell("",app("_ThreadCellBag_", + @Test + public void testFragment1() { + K term = + cell( + "", + cell("", KVariable("F")), + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence(KVariable("F"), KVariable("Rest")))), + KVariable("F2"))); + K expected = + cell( + "", + app( + "_ThreadCellBag_", cell("", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), - KSequence(cell("-fragment", KVariable("_Gen0"), KVariable("_Gen1"), KVariable("_Gen2")), KVariable("Rest")))), - KVariable("_Gen3"), - KVariable("_Gen4")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } - @Test - public void testFragment2() { - K term = cell("",cell("",cell("",KVariable("K")),KVariable("F")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), KSequence(KVariable("F"), KVariable("Rest")))), KVariable("F2"))); - K expected = cell("",app("_ThreadCellBag_", + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence( + cell( + "-fragment", + KVariable("_Gen0"), + KVariable("_Gen1"), + KVariable("_Gen2")), + KVariable("Rest")))), + KVariable("_Gen3"), + KVariable("_Gen4")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } + + @Test + public void testFragment2() { + K term = + cell( + "", + cell("", cell("", KVariable("K")), KVariable("F")), + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence(KVariable("F"), KVariable("Rest")))), + KVariable("F2"))); + K expected = + cell( + "", + app( + "_ThreadCellBag_", cell("", cell("", KVariable("K")), KVariable("_Gen0"), KVariable("_Gen1")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), - KSequence(cell("-fragment", app("noKCell"), KVariable("_Gen0"), KVariable("_Gen1")), KVariable("Rest")))), - KVariable("_Gen2"), - KVariable("_Gen3")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } - @Test - public void testFragment3() { - K term = cell("",cell("",cell("",KVariable("O")),KVariable("F")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), KSequence(KVariable("F"), KVariable("Rest")))), KVariable("F2"))); - K expected = cell("",app("_ThreadCellBag_", + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence( + cell( + "-fragment", + app("noKCell"), + KVariable("_Gen0"), + KVariable("_Gen1")), + KVariable("Rest")))), + KVariable("_Gen2"), + KVariable("_Gen3")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } + + @Test + public void testFragment3() { + K term = + cell( + "", + cell("", cell("", KVariable("O")), KVariable("F")), + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence(KVariable("F"), KVariable("Rest")))), + KVariable("F2"))); + K expected = + cell( + "", + app( + "_ThreadCellBag_", cell("", KVariable("_Gen0"), KVariable("_Gen1"), cell("", KVariable("O"))), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), - KSequence(cell("-fragment", KVariable("_Gen0"), KVariable("_Gen1"), app(".OptCell")), KVariable("Rest")))), - KVariable("_Gen2"), - KVariable("_Gen3")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } - @Test - public void testFragment4() { - K term = cell("",cell("",cell("",KVariable("E")),KVariable("F")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), KSequence(KVariable("F"), KVariable("Rest")))), KVariable("F2"))); - K expected = cell("",app("_ThreadCellBag_", + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence( + cell( + "-fragment", + KVariable("_Gen0"), + KVariable("_Gen1"), + app(".OptCell")), + KVariable("Rest")))), + KVariable("_Gen2"), + KVariable("_Gen3")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } + + @Test + public void testFragment4() { + K term = + cell( + "", + cell("", cell("", KVariable("E")), KVariable("F")), + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence(KVariable("F"), KVariable("Rest")))), + KVariable("F2"))); + K expected = + cell( + "", + app( + "_ThreadCellBag_", cell("", KVariable("_Gen0"), cell("", KVariable("E")), KVariable("_Gen1")), - cell("", cell("", KRewrite(KSequence(KVariable("Rest")), - KSequence(cell("-fragment", KVariable("_Gen0"), app("noEnvCell"), KVariable("_Gen1")), KVariable("Rest")))), - KVariable("_Gen2"), - KVariable("_Gen3")))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + cell( + "", + cell( + "", + KRewrite( + KSequence(KVariable("Rest")), + KSequence( + cell( + "-fragment", + KVariable("_Gen0"), + app("noEnvCell"), + KVariable("_Gen1")), + KVariable("Rest")))), + KVariable("_Gen2"), + KVariable("_Gen3")))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - ConfigurationInfo bagCfgInfo = new TestConfiguration() {{ - addCell(null, "TopCell", ""); - addCell("TopCell", "ThreadCell", "", Multiplicity.STAR, Sorts.K()); - addCell("TopCell", "ExtraCell", ""); - addUnit("ThreadCell", KLabel(".ThreadCellBag")); - addConcat("ThreadCell", KLabel("_ThreadCellBag_")); - }}; - LabelInfo bagLabelInfo = new LabelInfo() {{ - addLabel(Sort("TopCell"), ""); - addLabel(Sort("ThreadCell"), ""); - addLabel(Sort("ExtraCell"), ""); - addLabel(Sorts.K(), "restore"); - addLabel(Sort("ThreadCellBag"),"_ThreadCellBag_"); - }}; - @Test - public void testFragmentBag() { - K term = cell("", KVariable("F"),cell("", KRewrite(KVariable("Rest"),KSequence(KVariable("F"),KVariable("Rest"))))); - K expected = cell("", - app("_ThreadCellBag_", KVariable("_Gen0"), - cell("", KRewrite(KVariable("Rest"), - KSequence(app("-fragment",KVariable("_Gen0"),KVariable("_Gen1")),KVariable("Rest"))))), - KVariable("_Gen1")); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(bagCfgInfo, bagLabelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + ConfigurationInfo bagCfgInfo = + new TestConfiguration() { + { + addCell(null, "TopCell", ""); + addCell("TopCell", "ThreadCell", "", Multiplicity.STAR, Sorts.K()); + addCell("TopCell", "ExtraCell", ""); + addUnit("ThreadCell", KLabel(".ThreadCellBag")); + addConcat("ThreadCell", KLabel("_ThreadCellBag_")); + } + }; + LabelInfo bagLabelInfo = + new LabelInfo() { + { + addLabel(Sort("TopCell"), ""); + addLabel(Sort("ThreadCell"), ""); + addLabel(Sort("ExtraCell"), ""); + addLabel(Sorts.K(), "restore"); + addLabel(Sort("ThreadCellBag"), "_ThreadCellBag_"); + } + }; - @Test - public void testFragmentRewrite() { - K term = cell("", - cell("",KRewrite(app("restore",KVariable("Ctx")), - KVariable("Result"))), - KRewrite(cells(KVariable("_Gen1"), cell("",KVariable("Result"))), - KVariable("Ctx"))); - K expected = cell("", - app("_ThreadCellBag_", - cell("",KRewrite( - app("restore",app("-fragment",KVariable("_Gen0"),KVariable("_Gen2"))), - KVariable("Result"))), - KRewrite(app("_ThreadCellBag_",KVariable("_Gen3"), - cell("",KVariable("Result"))), - KVariable("_Gen0"))), - KRewrite(KVariable("_Gen4"),KVariable("_Gen2"))); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(bagCfgInfo, bagLabelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testFragmentBag() { + K term = + cell( + "", + KVariable("F"), + cell("", KRewrite(KVariable("Rest"), KSequence(KVariable("F"), KVariable("Rest"))))); + K expected = + cell( + "", + app( + "_ThreadCellBag_", + KVariable("_Gen0"), + cell( + "", + KRewrite( + KVariable("Rest"), + KSequence( + app("-fragment", KVariable("_Gen0"), KVariable("_Gen1")), + KVariable("Rest"))))), + KVariable("_Gen1")); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(bagCfgInfo, bagLabelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - /** When a cell fragment variable occurs as an argument to the appropriate cell fragment sort predict, we - * specialize the expansion by splitting it into a conjunction of individual sort predicate tests on - * the variables the cell fragment variable splits into, rather than just using the generic replacement term. - * This is a very special case of statically simplifying predicate applications. - */ - @Test - public void testPredicateExpansion() { - Rule term = new Rule(KRewrite(cell("", cell(""), KVariable("X"), KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), KVariable("X")) - , app("isThreadCellFragment",KVariable("X")) - , BooleanUtils.TRUE - , Att()); - K expectedBody = KRewrite(cell("", KVariable("X"), cell(""), KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), - cell("-fragment", KVariable("X"), app("noEnvCell"), app(".OptCell"))); - Rule expected = new Rule(expectedBody - , BooleanUtils.and(BooleanUtils.TRUE, app("isKCell", KVariable("X"))) - , BooleanUtils.TRUE, Att()); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + @Test + public void testFragmentRewrite() { + K term = + cell( + "", + cell("", KRewrite(app("restore", KVariable("Ctx")), KVariable("Result"))), + KRewrite( + cells(KVariable("_Gen1"), cell("", KVariable("Result"))), KVariable("Ctx"))); + K expected = + cell( + "", + app( + "_ThreadCellBag_", + cell( + "", + KRewrite( + app( + "restore", + app("-fragment", KVariable("_Gen0"), KVariable("_Gen2"))), + KVariable("Result"))), + KRewrite( + app("_ThreadCellBag_", KVariable("_Gen3"), cell("", KVariable("Result"))), + KVariable("_Gen0"))), + KRewrite(KVariable("_Gen4"), KVariable("_Gen2"))); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(bagCfgInfo, bagLabelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - /** Ensure that the splitting in {@linkplain #testPredicateExpansion()} does not happen - * in a term which applies the sort predicate for a different cell fragment sort - * to a cell fragment variable. - */ - @Test - public void testUnrelatedPredicate() { - Rule term = new Rule(KRewrite(cell("", cell(""), KVariable("X"), KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), KVariable("X")) - , app("isTopCellFragment",KVariable("X")) - , BooleanUtils.TRUE - , Att()); - K replacement = app("-fragment", KVariable("X"), app("noEnvCell"), app(".OptCell")); - K expectedBody = KRewrite(cell("", KVariable("X"), cell(""), KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), replacement); - Rule expected = new Rule(expectedBody - , app("isTopCellFragment", replacement) - , BooleanUtils.TRUE, Att()); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); - } + /** + * When a cell fragment variable occurs as an argument to the appropriate cell fragment sort + * predict, we specialize the expansion by splitting it into a conjunction of individual sort + * predicate tests on the variables the cell fragment variable splits into, rather than just using + * the generic replacement term. This is a very special case of statically simplifying predicate + * applications. + */ + @Test + public void testPredicateExpansion() { + Rule term = + new Rule( + KRewrite( + cell( + "", + cell(""), + KVariable("X"), + KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), + KVariable("X")), + app("isThreadCellFragment", KVariable("X")), + BooleanUtils.TRUE, + Att()); + K expectedBody = + KRewrite( + cell( + "", + KVariable("X"), + cell(""), + KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), + cell("-fragment", KVariable("X"), app("noEnvCell"), app(".OptCell"))); + Rule expected = + new Rule( + expectedBody, + BooleanUtils.and(BooleanUtils.TRUE, app("isKCell", KVariable("X"))), + BooleanUtils.TRUE, + Att()); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - /** - * Test that splitting works properly if an item under a parent cell is - * already a collection of multiplicity * cells joined by the proper label. - */ - @Test - public void testMultipleCells() { - KVariable T1 = KVariable("T1",Att().add(Sort.class,Sort("ThreadCell"))); - KVariable T2 = KVariable("T2",Att().add(Sort.class,Sort("ThreadCell"))); - K term = cell("", - KVariable("F"), - cell("", KVariable("T")), - app("_ThreadCellBag_",T1,T2)); - K expected = cell("", - app("_ThreadCellBag_", - app("_ThreadCellBag_", KVariable("_Gen0"), cell("", KVariable("T"))), - app("_ThreadCellBag_", T1, T2)), - KVariable("_Gen1")); - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(expected, new SortCells(bagCfgInfo, bagLabelInfo).sortCells(term)); - Assert.assertEquals(0, kem.getExceptions().size()); + /** + * Ensure that the splitting in {@linkplain #testPredicateExpansion()} does not happen in a term + * which applies the sort predicate for a different cell fragment sort to a cell fragment + * variable. + */ + @Test + public void testUnrelatedPredicate() { + Rule term = + new Rule( + KRewrite( + cell( + "", + cell(""), + KVariable("X"), + KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), + KVariable("X")), + app("isTopCellFragment", KVariable("X")), + BooleanUtils.TRUE, + Att()); + K replacement = app("-fragment", KVariable("X"), app("noEnvCell"), app(".OptCell")); + K expectedBody = + KRewrite( + cell( + "", + KVariable("X"), + cell(""), + KVariable("Y", Att().add(Sort.class, Sort("OptCell")))), + replacement); + Rule expected = + new Rule(expectedBody, app("isTopCellFragment", replacement), BooleanUtils.TRUE, Att()); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(cfgInfo, labelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - } + /** + * Test that splitting works properly if an item under a parent cell is already a collection of + * multiplicity * cells joined by the proper label. + */ + @Test + public void testMultipleCells() { + KVariable T1 = KVariable("T1", Att().add(Sort.class, Sort("ThreadCell"))); + KVariable T2 = KVariable("T2", Att().add(Sort.class, Sort("ThreadCell"))); + K term = + cell("", KVariable("F"), cell("", KVariable("T")), app("_ThreadCellBag_", T1, T2)); + K expected = + cell( + "", + app( + "_ThreadCellBag_", + app("_ThreadCellBag_", KVariable("_Gen0"), cell("", KVariable("T"))), + app("_ThreadCellBag_", T1, T2)), + KVariable("_Gen1")); + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals(expected, new SortCells(bagCfgInfo, bagLabelInfo).sortCells(term)); + Assert.assertEquals(0, kem.getExceptions().size()); + } - KApply app(String name, K... ks) { - return KApply(KLabel(name), ks); - } + KApply app(String name, K... ks) { + return KApply(KLabel(name), ks); + } - KApply cell(String name, K... ks) { - return KApply(KLabel(name), ks); - } + KApply cell(String name, K... ks) { + return KApply(KLabel(name), ks); + } - KApply cells(K... ks) { - return KApply(KLabels.CELLS, ks); - } + KApply cells(K... ks) { + return KApply(KLabels.CELLS, ks); + } } diff --git a/kernel/src/test/java/org/kframework/kore/compile/TestConfiguration.java b/kernel/src/test/java/org/kframework/kore/compile/TestConfiguration.java index f94742d68a4..0a6f6f335d6 100644 --- a/kernel/src/test/java/org/kframework/kore/compile/TestConfiguration.java +++ b/kernel/src/test/java/org/kframework/kore/compile/TestConfiguration.java @@ -1,203 +1,218 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; -import org.kframework.compile.ConfigurationInfo; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.kframework.kore.KApply; import org.kframework.kore.KLabel; import org.kframework.kore.Sort; import scala.Option; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.kframework.Collections.*; -import static org.kframework.kore.KORE.*; - -/** - * Created by brandon on 3/24/15. - */ +/** Created by brandon on 3/24/15. */ class TestConfiguration implements ConfigurationInfo { - Map levels = Maps.newHashMap(); - Map parents = Maps.newHashMap(); - Map leafCellTypes = Maps.newHashMap(); - ListMultimap children = ArrayListMultimap.create(); - Sort topCell = null; - Sort computationCell = null; - - Map multiplicities = Maps.newHashMap(); - Map defaultCells = Maps.newHashMap(); - BiMap units = HashBiMap.create(); - BiMap concats = HashBiMap.create(); - Map cellLabels = Maps.newHashMap(); - Map cellFragmentLabels = Maps.newHashMap(); - Map cellAbsentLabels = Maps.newHashMap(); - Map cellCollectionSorts = Maps.newHashMap(); - - public void addCell(String parent, String child, String label) { - addCell(parent, child, label, Multiplicity.ONE); - } - public void addCell(String parent, String child, String label, Sort contents) { - addCell(parent, child, label, Multiplicity.ONE, contents); - } - public void addCell(String parent, String child, String label, Multiplicity m) { - addCell(parent, child, label, m, null); - } - public void addCell(String parent, String child, String label, Multiplicity m, Sort contents) { - if (parent != null) { - if (!children.containsKey(Sort(parent))) { - // create a fragment label for the parent cell. - cellFragmentLabels.put(Sort(parent),KLabel(cellLabels.get(Sort(parent)).name()+"-fragment")); - } - if (m != Multiplicity.STAR) { - cellAbsentLabels.put(Sort(child),KLabel("no"+child)); - } - if (m == Multiplicity.STAR) { - cellCollectionSorts.put(Sort(child+"Bag"),Sort(child)); - } - parents.put(Sort(child), Sort(parent)); - children.put(Sort(parent), Sort(child)); - levels.put(Sort(child), 1 + levels.get(Sort(parent))); - } else { - levels.put(Sort(child), 0); - } - if (contents != null) { - leafCellTypes.put(Sort(child), contents); - } - multiplicities.put(Sort(child), m); - cellLabels.put(Sort(child), KLabel(label)); - } - - public void addDefault(String cell, KApply term) { - defaultCells.put(Sort(cell), term); - } - - public void addUnit(String cell, KLabel label) { units.put(Sort(cell), label); } - - public void addConcat(String cell, KLabel label) { concats.put(Sort(cell), label); } - - public TestConfiguration() { - } - - @Override - public int getLevel(Sort k) { - return levels.getOrDefault(k, -1); - } - - @Override - public Sort getParent(Sort k) { - return parents.get(k); - } - - @Override - public List getChildren(Sort k) { - return children.get(k); - } - - @Override - public Multiplicity getMultiplicity(Sort k) { - return multiplicities.get(k); - } - - @Override - public boolean isCell(Sort k) { - return levels.containsKey(k); - } - - @Override - public boolean isCellCollection(Sort s) { - return cellCollectionSorts.containsKey(s); - } - - @Override - public boolean isCellLabel(KLabel kLabel) { - return getCellSort(kLabel) != null; - } - - @Override - public boolean isLeafCell(Sort k) { - return !children.containsKey(k) && isCell(k); - } - - @Override - public boolean isParentCell(Sort k) { - return children.containsKey(k); - } - - @Override - public Sort leafCellType(Sort k) { - return leafCellTypes.get(k); - } - - @Override - public KLabel getCellLabel(Sort k) { - return cellLabels.get(k); - } - - @Override - public Sort getCellSort(KLabel kLabel) { - if (kLabel != null) { - return cellLabels.entrySet().stream().filter(e -> kLabel.equals(e.getValue())).map(Map.Entry::getKey).findAny().orElseGet(null); - } else { - return null; - } - } - - @Override - public KLabel getCellFragmentLabel(Sort k) { return cellFragmentLabels.get(k); } - - @Override - public KLabel getCellAbsentLabel(Sort k) { return cellAbsentLabels.get(k); } - - @Override - public KApply getDefaultCell(Sort k) { - return defaultCells.get(k); - } - - @Override - public boolean isConstantInitializer(Sort k) { - return true; - } - - @Override - public Sort getRootCell() { - return topCell; - } - - @Override - public Sort getComputationCell() { - return computationCell; - } - - @Override - public Set getCellSorts() { - return cellLabels.keySet(); - } - - @Override - public KApply getUnit(Sort k) { return KApply(units.get(k)); } - - @Override - public KLabel getConcat(Sort k) { return concats.get(k); } - - @Override - public Option getCellForConcat(KLabel concat) { - return Option.apply(concats.inverse().get(concat)); - } - - @Override - public Option getCellForUnit(KLabel unit) { - return Option.apply(units.inverse().get(unit)); - } - - @Override - public scala.collection.Set getCellBagSortsOfCell(Sort k) { - return Set(Sort(k.name() + "Bag", k.params())); - } + Map levels = Maps.newHashMap(); + Map parents = Maps.newHashMap(); + Map leafCellTypes = Maps.newHashMap(); + ListMultimap children = ArrayListMultimap.create(); + Sort topCell = null; + Sort computationCell = null; + + Map multiplicities = Maps.newHashMap(); + Map defaultCells = Maps.newHashMap(); + BiMap units = HashBiMap.create(); + BiMap concats = HashBiMap.create(); + Map cellLabels = Maps.newHashMap(); + Map cellFragmentLabels = Maps.newHashMap(); + Map cellAbsentLabels = Maps.newHashMap(); + Map cellCollectionSorts = Maps.newHashMap(); + + public void addCell(String parent, String child, String label) { + addCell(parent, child, label, Multiplicity.ONE); + } + + public void addCell(String parent, String child, String label, Sort contents) { + addCell(parent, child, label, Multiplicity.ONE, contents); + } + + public void addCell(String parent, String child, String label, Multiplicity m) { + addCell(parent, child, label, m, null); + } + + public void addCell(String parent, String child, String label, Multiplicity m, Sort contents) { + if (parent != null) { + if (!children.containsKey(Sort(parent))) { + // create a fragment label for the parent cell. + cellFragmentLabels.put( + Sort(parent), KLabel(cellLabels.get(Sort(parent)).name() + "-fragment")); + } + if (m != Multiplicity.STAR) { + cellAbsentLabels.put(Sort(child), KLabel("no" + child)); + } + if (m == Multiplicity.STAR) { + cellCollectionSorts.put(Sort(child + "Bag"), Sort(child)); + } + parents.put(Sort(child), Sort(parent)); + children.put(Sort(parent), Sort(child)); + levels.put(Sort(child), 1 + levels.get(Sort(parent))); + } else { + levels.put(Sort(child), 0); + } + if (contents != null) { + leafCellTypes.put(Sort(child), contents); + } + multiplicities.put(Sort(child), m); + cellLabels.put(Sort(child), KLabel(label)); + } + + public void addDefault(String cell, KApply term) { + defaultCells.put(Sort(cell), term); + } + + public void addUnit(String cell, KLabel label) { + units.put(Sort(cell), label); + } + + public void addConcat(String cell, KLabel label) { + concats.put(Sort(cell), label); + } + + public TestConfiguration() {} + + @Override + public int getLevel(Sort k) { + return levels.getOrDefault(k, -1); + } + + @Override + public Sort getParent(Sort k) { + return parents.get(k); + } + + @Override + public List getChildren(Sort k) { + return children.get(k); + } + + @Override + public Multiplicity getMultiplicity(Sort k) { + return multiplicities.get(k); + } + + @Override + public boolean isCell(Sort k) { + return levels.containsKey(k); + } + + @Override + public boolean isCellCollection(Sort s) { + return cellCollectionSorts.containsKey(s); + } + + @Override + public boolean isCellLabel(KLabel kLabel) { + return getCellSort(kLabel) != null; + } + + @Override + public boolean isLeafCell(Sort k) { + return !children.containsKey(k) && isCell(k); + } + + @Override + public boolean isParentCell(Sort k) { + return children.containsKey(k); + } + + @Override + public Sort leafCellType(Sort k) { + return leafCellTypes.get(k); + } + + @Override + public KLabel getCellLabel(Sort k) { + return cellLabels.get(k); + } + + @Override + public Sort getCellSort(KLabel kLabel) { + if (kLabel != null) { + return cellLabels.entrySet().stream() + .filter(e -> kLabel.equals(e.getValue())) + .map(Map.Entry::getKey) + .findAny() + .orElseGet(null); + } else { + return null; + } + } + + @Override + public KLabel getCellFragmentLabel(Sort k) { + return cellFragmentLabels.get(k); + } + + @Override + public KLabel getCellAbsentLabel(Sort k) { + return cellAbsentLabels.get(k); + } + + @Override + public KApply getDefaultCell(Sort k) { + return defaultCells.get(k); + } + + @Override + public boolean isConstantInitializer(Sort k) { + return true; + } + + @Override + public Sort getRootCell() { + return topCell; + } + + @Override + public Sort getComputationCell() { + return computationCell; + } + + @Override + public Set getCellSorts() { + return cellLabels.keySet(); + } + + @Override + public KApply getUnit(Sort k) { + return KApply(units.get(k)); + } + + @Override + public KLabel getConcat(Sort k) { + return concats.get(k); + } + + @Override + public Option getCellForConcat(KLabel concat) { + return Option.apply(concats.inverse().get(concat)); + } + + @Override + public Option getCellForUnit(KLabel unit) { + return Option.apply(units.inverse().get(unit)); + } + + @Override + public scala.collection.Set getCellBagSortsOfCell(Sort k) { + return Set(Sort(k.name() + "Bag", k.params())); + } } diff --git a/kernel/src/test/java/org/kframework/lsp/LSPTests.java b/kernel/src/test/java/org/kframework/lsp/LSPTests.java index fd880e98e81..9e334c1620b 100644 --- a/kernel/src/test/java/org/kframework/lsp/LSPTests.java +++ b/kernel/src/test/java/org/kframework/lsp/LSPTests.java @@ -1,6 +1,16 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.lsp; +import java.io.IOException; +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.lsp4j.*; import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.Assert; @@ -16,124 +26,153 @@ import org.kframework.utils.BinaryLoader; import org.kframework.utils.errorsystem.KExceptionManager; -import java.io.IOException; -import java.net.URI; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicReference; - public class LSPTests { - String def = "//require \"Copy (10) test.k\"\n" + - "require \"spec.k\"\n" + - "\n" + - "module A\n" + - " syntax A ::= \"a\"\n" + - "endmodule\n" + - "\n" + - "module B\n" + - " imports private A\n" + - "\n" + - " syntax C ::= B \n" + - " | A\n" + - " syntax B ::= \"b\"\n" + - "\n" + - " // this is the ffunction function\n" + - " syntax B ::= affunction(C) [function, total]\n" + - "\n" + - "endmodule\n" + - "\n" + - "module TEST \n" + - " imports private B \n" + - " imports INT \n" + - "\n" + - " rule .asdfasdf adsf asdf 123454 \n" + - "// rule f(_) => \"a\" [owise] \n" + - "endmodule\n"; - String uri = LSPTests.class.toString(); + String def = + "//require \"Copy (10) test.k\"\n" + + "require \"spec.k\"\n" + + "\n" + + "module A\n" + + " syntax A ::= \"a\"\n" + + "endmodule\n" + + "\n" + + "module B\n" + + " imports private A\n" + + "\n" + + " syntax C ::= B \n" + + " | A\n" + + " syntax B ::= \"b\"\n" + + "\n" + + " // this is the ffunction function\n" + + " syntax B ::= affunction(C) [function, total]\n" + + "\n" + + "endmodule\n" + + "\n" + + "module TEST \n" + + " imports private B \n" + + " imports INT \n" + + "\n" + + " rule .asdfasdf adsf asdf 123454 \n" + + "// rule f(_) => \"a\" [owise] \n" + + "endmodule\n"; + String uri = LSPTests.class.toString(); - @Test - public void testGetContext() { - KTextDocument doc = new KTextDocument(); - doc.updateText(def); - Assert.assertEquals("require", doc.getContextAt(new KPos(2, 2))); - Assert.assertEquals("module", doc.getContextAt(new KPos(4, 8))); - Assert.assertEquals("imports", doc.getContextAt(new KPos(9, 21))); - Assert.assertEquals("syntax", doc.getContextAt(new KPos(11, 18))); - Assert.assertEquals("endmodule", doc.getContextAt(new KPos(19, 1))); - Assert.assertEquals("rule", doc.getContextAt(new KPos(24, 30))); - } + @Test + public void testGetContext() { + KTextDocument doc = new KTextDocument(); + doc.updateText(def); + Assert.assertEquals("require", doc.getContextAt(new KPos(2, 2))); + Assert.assertEquals("module", doc.getContextAt(new KPos(4, 8))); + Assert.assertEquals("imports", doc.getContextAt(new KPos(9, 21))); + Assert.assertEquals("syntax", doc.getContextAt(new KPos(11, 18))); + Assert.assertEquals("endmodule", doc.getContextAt(new KPos(19, 1))); + Assert.assertEquals("rule", doc.getContextAt(new KPos(24, 30))); + } - @Test - public void isPositionOverLocation() { - Assert.assertTrue(TextDocumentSyncHandler.isPositionOverLocation( - new KPos(9, 3), - new Location(9, 3, 12, 17))); - Assert.assertTrue(TextDocumentSyncHandler.isPositionOverLocation( - new KPos(10, 16), - new Location(9, 3, 12, 17))); - Assert.assertFalse(TextDocumentSyncHandler.isPositionOverLocation( - new KPos(9, 2), - new Location(9, 3, 12, 17))); - Assert.assertFalse(TextDocumentSyncHandler.isPositionOverLocation( - new KPos(12, 18), - new Location(9, 3, 12, 17))); - } + @Test + public void isPositionOverLocation() { + Assert.assertTrue( + TextDocumentSyncHandler.isPositionOverLocation(new KPos(9, 3), new Location(9, 3, 12, 17))); + Assert.assertTrue( + TextDocumentSyncHandler.isPositionOverLocation( + new KPos(10, 16), new Location(9, 3, 12, 17))); + Assert.assertFalse( + TextDocumentSyncHandler.isPositionOverLocation(new KPos(9, 2), new Location(9, 3, 12, 17))); + Assert.assertFalse( + TextDocumentSyncHandler.isPositionOverLocation( + new KPos(12, 18), new Location(9, 3, 12, 17))); + } - @Test - public void testKLS() throws ExecutionException, InterruptedException { - KLanguageServer kls = new KLanguageServer(); - KTextDocumentService.DELAY_EXECUTION_MS = 0; - kls.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "kframework", 1, def))); + @Test + public void testKLS() throws ExecutionException, InterruptedException { + KLanguageServer kls = new KLanguageServer(); + KTextDocumentService.DELAY_EXECUTION_MS = 0; + kls.getTextDocumentService() + .didOpen(new DidOpenTextDocumentParams(new TextDocumentItem(uri, "kframework", 1, def))); - CompletableFuture diags = kls.getTextDocumentService().diagnostic(new DocumentDiagnosticParams(new TextDocumentIdentifier(uri))); - RelatedFullDocumentDiagnosticReport z = diags.get().getLeft(); - Assert.assertEquals(0, z.getItems().size()); - //System.out.println("Diags: " + z); + CompletableFuture diags = + kls.getTextDocumentService() + .diagnostic(new DocumentDiagnosticParams(new TextDocumentIdentifier(uri))); + RelatedFullDocumentDiagnosticReport z = diags.get().getLeft(); + Assert.assertEquals(0, z.getItems().size()); + // System.out.println("Diags: " + z); - CompletableFuture, CompletionList>> x = kls.getTextDocumentService().completion(new CompletionParams(new TextDocumentIdentifier(uri), new Position(10, 17))); - List y = x.get().getLeft(); - Assert.assertNotEquals(y.size(), 0); - //System.out.println("Completion: " + y.size()); + CompletableFuture, CompletionList>> x = + kls.getTextDocumentService() + .completion( + new CompletionParams(new TextDocumentIdentifier(uri), new Position(10, 17))); + List y = x.get().getLeft(); + Assert.assertNotEquals(y.size(), 0); + // System.out.println("Completion: " + y.size()); - CompletableFuture, List>> defin = kls.getTextDocumentService().definition(new DefinitionParams(new TextDocumentIdentifier(uri), new Position(21, 6))); - List defRez = defin.get().getRight(); - Assert.assertNotEquals(defRez.size(), 0); - //System.out.println("GoToDef: " + defRez); - } + CompletableFuture< + Either, List>> + defin = + kls.getTextDocumentService() + .definition( + new DefinitionParams(new TextDocumentIdentifier(uri), new Position(21, 6))); + List defRez = defin.get().getRight(); + Assert.assertNotEquals(defRez.size(), 0); + // System.out.println("GoToDef: " + defRez); + } - // useful for local testing - @Test @Ignore - public void testKLSPathK() throws IOException { - WorkspaceFolder workspaceFolder = new WorkspaceFolder("file:///home/radu/work/test", "test"); - BinaryLoader loader = new BinaryLoader(new KExceptionManager(new GlobalOptions())); - Map caches = null; + // useful for local testing + @Test + @Ignore + public void testKLSPathK() throws IOException { + WorkspaceFolder workspaceFolder = new WorkspaceFolder("file:///home/radu/work/test", "test"); + BinaryLoader loader = new BinaryLoader(new KExceptionManager(new GlobalOptions())); + Map caches = null; - Optional cacheFile = Files.walk(Path.of(URI.create(workspaceFolder.getUri()))).filter(p -> p.endsWith(Kompile.CACHE_FILE_NAME)).findFirst(); - if (cacheFile.isPresent()) - caches = loader.loadCache(java.util.Map.class, cacheFile.get().toFile()); + Optional cacheFile = + Files.walk(Path.of(URI.create(workspaceFolder.getUri()))) + .filter(p -> p.endsWith(Kompile.CACHE_FILE_NAME)) + .findFirst(); + if (cacheFile.isPresent()) + caches = loader.loadCache(java.util.Map.class, cacheFile.get().toFile()); - System.out.println(caches.size()); + System.out.println(caches.size()); - KPos pos = new KPos(10, 11); - Map ch = caches.entrySet().stream().filter(elm -> elm.getKey().startsWith("TEST-RULE-CELLS")).findFirst().get().getValue().cache(); + KPos pos = new KPos(10, 11); + Map ch = + caches.entrySet().stream() + .filter(elm -> elm.getKey().startsWith("TEST-RULE-CELLS")) + .findFirst() + .get() + .getValue() + .cache(); - ParseCache.ParsedSentence rl = ch.entrySet().stream().filter(r -> r.getKey().equals("1 => 2")).findFirst().get().getValue(); - K ast = rl.parse(); - AtomicReference x = new AtomicReference<>(); - KViz.from(t -> { - if (TextDocumentSyncHandler.isPositionOverLocation(pos, t.location().get())) { + ParseCache.ParsedSentence rl = + ch.entrySet().stream() + .filter(r -> r.getKey().equals("1 => 2")) + .findFirst() + .get() + .getValue(); + K ast = rl.parse(); + AtomicReference x = new AtomicReference<>(); + KViz.from( + t -> { + if (TextDocumentSyncHandler.isPositionOverLocation(pos, t.location().get())) { x.set(t); - System.out.println("Pos over loc: " + pos + " loc: " + t.location() + " trm: " + t.att().get(Production.class)); - } else - System.out.println("Pos out loc: " + pos + " loc: " + t.location() + " trm: " + t.att().get(Production.class)); - return t; - }, "test find").apply(ast); - System.out.println(x.get()); - } + System.out.println( + "Pos over loc: " + + pos + + " loc: " + + t.location() + + " trm: " + + t.att().get(Production.class)); + } else + System.out.println( + "Pos out loc: " + + pos + + " loc: " + + t.location() + + " trm: " + + t.att().get(Production.class)); + return t; + }, + "test find") + .apply(ast); + System.out.println(x.get()); + } } diff --git a/kernel/src/test/java/org/kframework/parser/inner/RuleGrammarTest.java b/kernel/src/test/java/org/kframework/parser/inner/RuleGrammarTest.java index 89c3e0f819e..b7879671df8 100644 --- a/kernel/src/test/java/org/kframework/parser/inner/RuleGrammarTest.java +++ b/kernel/src/test/java/org/kframework/parser/inner/RuleGrammarTest.java @@ -1,10 +1,14 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Lists; import dk.brics.automaton.Automaton; import dk.brics.automaton.RegExp; import dk.brics.automaton.RunAutomaton; +import java.io.File; +import java.util.Set; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -26,503 +30,576 @@ import scala.Tuple2; import scala.util.Either; -import java.io.File; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - public class RuleGrammarTest { - private final static Sort startSymbol = DefinitionParsing.START_SYMBOL; - private RuleGrammarGenerator gen; - private FileUtil files; - - @Before - public void setUp() throws Exception { - gen = makeRuleGrammarGenerator(); - } - - public RuleGrammarGenerator makeRuleGrammarGenerator() { - String definitionText; - files = FileUtil.testFileUtil(); - ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); - File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); - definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); - - Definition baseK = - parser.loadDefinition("K", "K", definitionText, - definitionFile, - definitionFile.getParentFile(), - Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), - false, false, false); - - return new RuleGrammarGenerator(baseK); - } - - private void parseRule(String input, String def, int warnings, boolean expectedError) { - Module test = ParserUtils.parseMainModuleOuterSyntax(def, Source.apply("generated by RuleGrammarTest"), "TEST"); - ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(gen.getRuleGrammar(test), true, files); - Tuple2, K>, Set> rule = parser.parseString(input, startSymbol, Source.apply("generated by RuleGrammarTest")); - printout(rule, warnings, expectedError); - } - - private void parseRule(String input, String def, int warnings, K expectedResult) { - Module test = ParserUtils.parseMainModuleOuterSyntax(def, Source.apply("generated by RuleGrammarTest"), "TEST"); - ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(gen.getRuleGrammar(test), true, files); - Tuple2, K>, Set> rule - = parser.parseString(input, startSymbol, Source.apply("generated by RuleGrammarTest")); - printout(rule, warnings, false); - Assert.assertEquals(expectedResult, rule._1().right().get()); - } - - private void parseConfig(String input, String def, int warnings, boolean expectedError) { - Module test = ParserUtils.parseMainModuleOuterSyntax(def, Source.apply("generated by RuleGrammarTest"), "TEST"); - ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(test), true, files); - Tuple2, K>, Set> rule = parser.parseString(input, startSymbol, Source.apply("generated by RuleGrammarTest")); - printout(rule, warnings, expectedError); - } - - private void parseProgram(String input, String def, String startSymbol, int warnings, boolean expectedError) { - Module test = ParserUtils.parseMainModuleOuterSyntax(def, Source.apply("generated by RuleGrammarTest"), "TEST"); - ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(test), true, files); - Tuple2, K>, Set> rule = parser.parseString(input, Sort(startSymbol), Source.apply("generated by RuleGrammarTest")); - printout(rule, warnings, expectedError); - } - - private void parseProgram(String input, String def, String startSymbol, int warnings, K expectedResult) { - Module test = ParserUtils.parseMainModuleOuterSyntax(def, Source.apply("generated by RuleGrammarTest"), "TEST"); - ParseInModule parser = RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(test), true, files); - Tuple2, K>, Set> rule = parser.parseString(input, Sort(startSymbol), Source.apply("generated by RuleGrammarTest")); - printout(rule, warnings, false); - Assert.assertEquals(expectedResult, rule._1().right().get()); - } - - private void printout(Tuple2, K>, Set> rule, int warnings, boolean expectedError) { - if (false) { // true to print detailed results - KExceptionManager kem = new KExceptionManager(new GlobalOptions(true, Warnings.ALL, true)); - if (rule._1().isLeft()) { - for (KEMException x : rule._1().left().get()) { - kem.addKException(x.getKException()); - } - } else { - System.err.println("rule = " + rule._1().right().get()); - } - for (KEMException x : rule._2()) { - kem.addKException(x.getKException()); - } - kem.print(); + private static final Sort startSymbol = DefinitionParsing.START_SYMBOL; + private RuleGrammarGenerator gen; + private FileUtil files; + + @Before + public void setUp() throws Exception { + gen = makeRuleGrammarGenerator(); + } + + public RuleGrammarGenerator makeRuleGrammarGenerator() { + String definitionText; + files = FileUtil.testFileUtil(); + ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); + File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); + definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); + + Definition baseK = + parser.loadDefinition( + "K", + "K", + definitionText, + definitionFile, + definitionFile.getParentFile(), + Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), + false, + false, + false); + + return new RuleGrammarGenerator(baseK); + } + + private void parseRule(String input, String def, int warnings, boolean expectedError) { + Module test = + ParserUtils.parseMainModuleOuterSyntax( + def, Source.apply("generated by RuleGrammarTest"), "TEST"); + ParseInModule parser = + RuleGrammarGenerator.getCombinedGrammar(gen.getRuleGrammar(test), true, files); + Tuple2, K>, Set> rule = + parser.parseString(input, startSymbol, Source.apply("generated by RuleGrammarTest")); + printout(rule, warnings, expectedError); + } + + private void parseRule(String input, String def, int warnings, K expectedResult) { + Module test = + ParserUtils.parseMainModuleOuterSyntax( + def, Source.apply("generated by RuleGrammarTest"), "TEST"); + ParseInModule parser = + RuleGrammarGenerator.getCombinedGrammar(gen.getRuleGrammar(test), true, files); + Tuple2, K>, Set> rule = + parser.parseString(input, startSymbol, Source.apply("generated by RuleGrammarTest")); + printout(rule, warnings, false); + Assert.assertEquals(expectedResult, rule._1().right().get()); + } + + private void parseConfig(String input, String def, int warnings, boolean expectedError) { + Module test = + ParserUtils.parseMainModuleOuterSyntax( + def, Source.apply("generated by RuleGrammarTest"), "TEST"); + ParseInModule parser = + RuleGrammarGenerator.getCombinedGrammar(gen.getConfigGrammar(test), true, files); + Tuple2, K>, Set> rule = + parser.parseString(input, startSymbol, Source.apply("generated by RuleGrammarTest")); + printout(rule, warnings, expectedError); + } + + private void parseProgram( + String input, String def, String startSymbol, int warnings, boolean expectedError) { + Module test = + ParserUtils.parseMainModuleOuterSyntax( + def, Source.apply("generated by RuleGrammarTest"), "TEST"); + ParseInModule parser = + RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(test), true, files); + Tuple2, K>, Set> rule = + parser.parseString(input, Sort(startSymbol), Source.apply("generated by RuleGrammarTest")); + printout(rule, warnings, expectedError); + } + + private void parseProgram( + String input, String def, String startSymbol, int warnings, K expectedResult) { + Module test = + ParserUtils.parseMainModuleOuterSyntax( + def, Source.apply("generated by RuleGrammarTest"), "TEST"); + ParseInModule parser = + RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(test), true, files); + Tuple2, K>, Set> rule = + parser.parseString(input, Sort(startSymbol), Source.apply("generated by RuleGrammarTest")); + printout(rule, warnings, false); + Assert.assertEquals(expectedResult, rule._1().right().get()); + } + + private void printout( + Tuple2, K>, Set> rule, + int warnings, + boolean expectedError) { + if (false) { // true to print detailed results + KExceptionManager kem = new KExceptionManager(new GlobalOptions(true, Warnings.ALL, true)); + if (rule._1().isLeft()) { + for (KEMException x : rule._1().left().get()) { + kem.addKException(x.getKException()); } - if (expectedError) - Assert.assertTrue("Expected error here: ", rule._1().isLeft()); - else - Assert.assertTrue("Expected no errors here: ", rule._1().isRight()); - Assert.assertEquals("Expected " + warnings + " warnings: ", warnings, rule._2().size()); - } - - // test proper associativity for rewrite, ~> and cast - @Test - public void test2() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), left] " + - "| r\"[0-9]+\" [token] " + - "syntax left 'Plus " + - "endmodule"; - parseRule("1+2=>A:Exp~>{B}:>Exp", def, 0, false); - } - - // test variable disambiguation when a variable is declared by the user - @Test - public void test3() { - String def = "" + - "module TEST " + - "syntax Exps ::= Exp \",\" Exps [klabel('Exps)] " + - "| Exp " + - "syntax Exp ::= Id " + - "syntax Stmt ::= \"val\" Exps \";\" Stmt [klabel('Decl)] " + - "syntax {Sort} Sort ::= \"(\" Sort \")\" [bracket] " + - "syntax KItem ::= (Id, Stmt) [klabel('tuple)] " + - "syntax Id " + - "syntax K " + - "endmodule"; - parseRule("val X ; S:Stmt => (X, S)", def, 0, false); - } - - // test variable disambiguation when all variables are being inferred - @Test - public void test4() { - String def = "" + - "module TEST " + - "syntax Exps ::= Exp \",\" Exps [klabel('Exps)] " + - "| Exp " + - "syntax Exp ::= Id " + - "syntax Stmt ::= \"val\" Exps \";\" Stmt [klabel('Decl)] " + - "syntax {Sort} Sort ::= \"(\" Sort \")\" [bracket] " + - "syntax KItem ::= (Id, Stmt) [klabel('tuple)] " + - "syntax Id " + - "syntax K " + - "endmodule"; - parseRule("val X ; S => (X, S)", def, 0, false); - } - - // test error reporting when + is non-associative - @Test - public void test5() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), non-assoc] " + - "| r\"[0-9]+\" [token] " + - "syntax non-assoc 'Plus " + - "endmodule"; - parseRule("1+2+3", def, 0, true); - } - - // test AmbFilter which should report ambiguities as errors - @Test - public void test6() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus)] " + - "| r\"[0-9]+\" [token] " + - "endmodule"; - parseRule("1+2+3", def, 0, true); - } - - // test error reporting when rewrite priority is not met - @Test - public void test7() { - String def = "" + - "module TEST " + - "syntax A ::= \"foo\" A [klabel('foo)] " + - "syntax B ::= \"bar\" [klabel('bar)] " + - "endmodule"; - parseRule("foo bar => X", def, 0, true); - } - - // test prefer and avoid - @Test - public void test8() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + - "| Exp \"*\" Exp [klabel('Mul)] " + - "| r\"[0-9]+\" [token] " + - "endmodule"; - parseRule("1+2*3", def, 0, false); - } - - // test cells - @Test - public void test9() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + - "| Exp \"*\" Exp [klabel('Mul)] " + - "| r\"[0-9]+\" [token] " + - "syntax K " + - "syntax TopCell ::= \"\" KCell StateCell \"\" [klabel(), cell] " + - "syntax KCell ::= \"\" K \"\" [klabel(), cell] " + - "syntax StateCell ::= \"\" K \"\" [klabel(), cell] " + - "endmodule"; - parseRule(" ...1+2*3... ( A => .::K ... => .::Bag) ...", def, 0, false); - } - - // test rule cells - @Test - public void test10() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \",\" Exp [klabel('Plus), prefer] " + - "| Exp \"*\" Exp [klabel('Mul)] " + - "| r\"[0-9]+\" [token] " + - "endmodule"; - parseRule("A::KLabel(B::K, C::K, D::K)", def, 0, false); - } - - // test config cells - @Test - public void test11() { - String def = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + - "| Exp \"*\" Exp [klabel('Mul)] " + - "| r\"[0-9]+\" [token] " + - "syntax K " + - "endmodule"; - parseConfig(" 1+2*3 ( A => .::K => .::Bag) ", def, 0, false); - } - - // test variable disambiguation when all variables are being inferred - @Test - public void test12() { - String def = "" + - "module TEST " + - "syntax Stmt ::= \"val\" Exp \";\" Stmt [klabel('Decl)] " + - "syntax Exp " + - "syntax Stmt " + - "endmodule"; - parseRule("val _:Exp ; _", def, 0, false); - } - - // test priority exceptions (requires and ensures) - @Test - public void test13() { - String def = "" + - "module TEST " + - "syntax Bool ::= \"true\" [token] " + - "endmodule"; - parseRule(".::K => .::K requires true", def, 0, false); - } - - // test automatic follow restriction for terminals - @Test - public void test14() { - String def = "" + - "module TEST " + - "syntax Stmt ::= Stmt Stmt [klabel('Stmt)] " + - "syntax Exp ::= K \"==\" K [klabel('Eq)] " + - "syntax Exp ::= K \":\" K [klabel('Colon)] " + - "syntax K " + - "syntax Exp ::= K \"==K\" K [klabel('EqK)] " + - "syntax Exp ::= K \"?\" K \":\" K " + - "endmodule"; - parseRule("A::K ==K A", def, 0, false); - parseRule("A::K == K A", def, 0, true); - parseRule("A:K", def, 0, false); - parseRule("A: K", def, 0, false); - parseRule("A:Stmt ?F : Stmt", def, 0, false); - parseRule("A:Stmt ? F : Stmt", def, 0, false); - } - - // test whitespace - @Test - public void test15() { - String def = "" + - "module TEST " + - "syntax Exp ::= Divide(K, K) [klabel('Divide)] " + - "syntax Exp ::= K \"/\" K [klabel('Div)] " + - "syntax K " + - "endmodule"; - parseRule("Divide(K1:K, K2:K) => K1:K / K2:K", def, 0, false); - } - - // test lexical to RegexTerminal extractor - @Test - public void test16() { - assertPatterns("", "#", "", "#"); - assertPatterns("abc", "#", "abc", "#"); - assertPatterns("(? .K", def, 0, false); - } - - // test special priority - @Test - public void test19() { - String def = "" + - "module TEST \n" + - " syntax K \n" + - " syntax KItem ::= foo(K) [klabel(foo), symbol]\n" + - " syntax Bar ::= bar() [klabel(bar), symbol]\n" + - "endmodule"; - parseRule("`foo`(`bar`(.KList) ~> .K , .KList)", def, 0, false); - parseRule("`foo`(`bar`(.KList) => .K , .KList)", def, 0, false); - } - - // test user lists - @Test - public void test20() { - String def = "" + - "module TEST " + - "syntax Exp ::= Int \"(\" Ints \")\" " + - "syntax Exp ::= Int \"[\" Ints2 \"]\" " + - "syntax Ints ::= List{Int, \",\"} " + - "syntax Ints2 ::= NeList{Int, \".\"} " + - "syntax Int ::= r\"[0-9]+\" [token] " + - "endmodule"; - parseRule("0, 1, 2", def, 0, false); - parseProgram("0, 1, 2", def, "Ints", 0, false); - parseProgram("0()", def, "Exp", 0, false); - parseProgram("0[]", def, "Exp", 0, true); - } - - // test inference with overloading. - // regression test for issue #1586 - @Test - public void test21() { - String def = "" + - "module TEST " + - "syntax A ::= B | \"a\" " + - "syntax B ::= \"b\" " + - "syntax TA ::= TB | t(A) [klabel(t)] " + - "syntax TB ::= t(B) [klabel(t)] " + - "endmodule"; - parseRule("t(Y) => .K", def, 0, false); - parseRule("t(_) => .K", def, 0, false); - } - - // test inference with complicated ambiguity - // regression test for issue #1603 - @Test - public void test22() { - String def = "" + - "module TEST\n" + - "syntax T ::= \"wrap\" M [klabel(wrapM)] | \"wrap\" X [klabel(wrapX)]\n" + - "syntax A\n" + - "syntax B\n" + - "syntax M ::= A | B\n" + - "syntax N ::= A | B | X // make A and B both maximal in the intersection of N and M\n" + - "syntax X\n" + - "syntax KItem ::= label(N,T)\n" + - "endmodule"; - parseRule("X => label(X,wrap X)", def, 0, true); - } - - // automatic follow restriction should not be added for empty terminals - // regression test for issue #1575 - @Test - public void test23() { - String def = "" + - "module TEST " + - "syntax Stmts ::= Stmt \"\" Stmts\n" + - " | \".Stmts\"\n" + - " syntax Stmt ::= \"a\"" + - "endmodule"; - parseRule("a .Stmts", def, 0, false); - } - - // Should not infer sort KList for variable in arity-1 application of a klabel - @Test - public void test24() { - String def = "" + - "module TEST\n" + - "syntax A\n" + - "syntax A ::= f(A) [klabel(l), symbol]\n" + - "endmodule"; - parseRule("l(_) => .K", def, 0, - KApply(KLabel("#ruleNoConditions"),KApply(KLabel("#KRewrite"), - KApply(KLabel("l"), KApply(KLabel("#SemanticCastToA"), KToken("_",Sort("#KVariable")))), - KApply(KLabel("#EmptyK")) - ))); - } - - @Test - public void testPriorityAssoc() throws Exception { - String def = "module TEST " + - "syntax Exp ::= Exp \"*\" Exp [left, klabel('Mul)] " + - "> Exp \"+\" Exp [left, klabel('Plus)] " + - "| r\"[0-9]+\" [token] " + - "syntax left 'Plus " + - "syntax left 'Mul " + - "endmodule"; - parseProgram("1+2", def, "Exp", 0, false); - //System.out.println("out1 = " + out1); - parseProgram("1+2*3", def, "Exp", 0, false); - //System.out.println("out2 = " + out2); - parseProgram("1+2+3", def, "Exp", 0, false); - //System.out.println("out3 = " + out3); - } - - // test default/custom layout - @Test - public void testLayout() { - String defaultLayout = "" + - "module TEST " + - "syntax Int ::= Int \"+\" Int " + - "syntax Int ::= r\"[0-9]+\" [token] " + - "endmodule"; - parseProgram("0 + 3 // some text" , defaultLayout, "Int", 0, false); - parseProgram("0 + 3 /* some text */", defaultLayout, "Int", 0, false); - parseProgram("0 /* some text */ + 3", defaultLayout, "Int", 0, false); - parseProgram("0 + 3 ;; some text" , defaultLayout, "Int", 0, true); - - String customLayout = "" + - "module TEST " + - "syntax #Layout ::= r\"(\\\\(;([^;]|(;+([^;\\\\)])))*;\\\\))\"" + - "| r\"(;;[^\\\\n\\\\r]*)\"" + - "| r\"([\\\\ \\\\n\\\\r\\\\t])\"" + - "// -------------------------------------\n" + // make sure standard layout still works in K defn - "syntax Int ::= Int \"+\" Int " + - "syntax Int ::= r\"[0-9]+\" [token] " + - "endmodule"; - parseProgram("0 + 3 ;; some text" , customLayout, "Int", 0, false); - parseProgram("0 + 3 (; some text ;)", customLayout, "Int", 0, false); - parseProgram("0 (; some text ;) + 3", customLayout, "Int", 0, false); - parseProgram("0 + 3 // some text" , customLayout, "Int", 0, true); - } - - // test KAppToTermConsVisitor for issue #985 - @Test - public void test25() { - String def = "" + - "module TEST\n" + - " syntax E ::= \"a\" [klabel(elma), symbol]\n" + - " syntax Lst ::= E \",\" Lst [klabel(constr), symbol]\n" + - " syntax Lst2 ::= E \",\" Lst2 [klabel(constr), symbol]\n" + - " | Lst \n" + - " syntax S ::= tuple(E, E, S) [klabel(tuplee), symbol]\n" + - "endmodule"; - parseRule("constr(I, L) => L", def, 0, - KApply(KLabel("#ruleNoConditions"),KApply(KLabel("#KRewrite"), - KApply(KLabel("constr"), - KApply(KLabel("#SemanticCastToE"), KToken("I",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToLst2"), KToken("L",Sort("#KVariable")))), - KApply(KLabel("#SemanticCastToLst2"), KToken("L",Sort("#KVariable"))) - ))); - parseRule("`constr`(I, (a, L)) => L", def, 0, - KApply(KLabel("#ruleNoConditions"),KApply(KLabel("#KRewrite"), - KApply(KLabel("constr"), - KApply(KLabel("#SemanticCastToE"), KToken("I",Sort("#KVariable"))), - KApply(KLabel("constr"), - KApply(KLabel("elma")), - KApply(KLabel("#SemanticCastToLst2"), KToken("L",Sort("#KVariable"))))), - KApply(KLabel("#SemanticCastToLst2"), KToken("L",Sort("#KVariable"))) - ))); - parseRule("tuplee(A, B, C) => C", def, 0, - KApply(KLabel("#ruleNoConditions"),KApply(KLabel("#KRewrite"), - KApply(KLabel("tuplee"), - KApply(KLabel("#SemanticCastToE"), KToken("A",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToE"), KToken("B",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToS"), KToken("C",Sort("#KVariable")))), - KApply(KLabel("#SemanticCastToS"), KToken("C",Sort("#KVariable"))) - ))); - parseRule("constr(A, B, C) => .K", def, 0, false); // 3 amb at top 8 amb final - parseRule("constr(A, B, C, D) => .K", def, 0, false); // 17 amb at top 16 final - parseRule("constr(a, a, a) => .K", def, 0, true); // 'a' is not subsorted to the list - } - - @Test - public void test26() { - String def = "" + - "module TEST " + - "syntax Exp ::= \"\" " + - "endmodule"; - parseProgram("", def, "Exp", 0, false); - } + } else { + System.err.println("rule = " + rule._1().right().get()); + } + for (KEMException x : rule._2()) { + kem.addKException(x.getKException()); + } + kem.print(); + } + if (expectedError) Assert.assertTrue("Expected error here: ", rule._1().isLeft()); + else Assert.assertTrue("Expected no errors here: ", rule._1().isRight()); + Assert.assertEquals("Expected " + warnings + " warnings: ", warnings, rule._2().size()); + } + + // test proper associativity for rewrite, ~> and cast + @Test + public void test2() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), left] " + + "| r\"[0-9]+\" [token] " + + "syntax left 'Plus " + + "endmodule"; + parseRule("1+2=>A:Exp~>{B}:>Exp", def, 0, false); + } + + // test variable disambiguation when a variable is declared by the user + @Test + public void test3() { + String def = + "" + + "module TEST " + + "syntax Exps ::= Exp \",\" Exps [klabel('Exps)] " + + "| Exp " + + "syntax Exp ::= Id " + + "syntax Stmt ::= \"val\" Exps \";\" Stmt [klabel('Decl)] " + + "syntax {Sort} Sort ::= \"(\" Sort \")\" [bracket] " + + "syntax KItem ::= (Id, Stmt) [klabel('tuple)] " + + "syntax Id " + + "syntax K " + + "endmodule"; + parseRule("val X ; S:Stmt => (X, S)", def, 0, false); + } + + // test variable disambiguation when all variables are being inferred + @Test + public void test4() { + String def = + "" + + "module TEST " + + "syntax Exps ::= Exp \",\" Exps [klabel('Exps)] " + + "| Exp " + + "syntax Exp ::= Id " + + "syntax Stmt ::= \"val\" Exps \";\" Stmt [klabel('Decl)] " + + "syntax {Sort} Sort ::= \"(\" Sort \")\" [bracket] " + + "syntax KItem ::= (Id, Stmt) [klabel('tuple)] " + + "syntax Id " + + "syntax K " + + "endmodule"; + parseRule("val X ; S => (X, S)", def, 0, false); + } + + // test error reporting when + is non-associative + @Test + public void test5() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), non-assoc] " + + "| r\"[0-9]+\" [token] " + + "syntax non-assoc 'Plus " + + "endmodule"; + parseRule("1+2+3", def, 0, true); + } + + // test AmbFilter which should report ambiguities as errors + @Test + public void test6() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus)] " + + "| r\"[0-9]+\" [token] " + + "endmodule"; + parseRule("1+2+3", def, 0, true); + } + + // test error reporting when rewrite priority is not met + @Test + public void test7() { + String def = + "" + + "module TEST " + + "syntax A ::= \"foo\" A [klabel('foo)] " + + "syntax B ::= \"bar\" [klabel('bar)] " + + "endmodule"; + parseRule("foo bar => X", def, 0, true); + } + + // test prefer and avoid + @Test + public void test8() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + + "| Exp \"*\" Exp [klabel('Mul)] " + + "| r\"[0-9]+\" [token] " + + "endmodule"; + parseRule("1+2*3", def, 0, false); + } + + // test cells + @Test + public void test9() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + + "| Exp \"*\" Exp [klabel('Mul)] " + + "| r\"[0-9]+\" [token] " + + "syntax K " + + "syntax TopCell ::= \"\" KCell StateCell \"\" [klabel(), cell] " + + "syntax KCell ::= \"\" K \"\" [klabel(), cell] " + + "syntax StateCell ::= \"\" K \"\" [klabel(), cell] " + + "endmodule"; + parseRule( + " ...1+2*3... ( A => .::K ... => .::Bag) ...", def, 0, false); + } + + // test rule cells + @Test + public void test10() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \",\" Exp [klabel('Plus), prefer] " + + "| Exp \"*\" Exp [klabel('Mul)] " + + "| r\"[0-9]+\" [token] " + + "endmodule"; + parseRule("A::KLabel(B::K, C::K, D::K)", def, 0, false); + } + + // test config cells + @Test + public void test11() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + + "| Exp \"*\" Exp [klabel('Mul)] " + + "| r\"[0-9]+\" [token] " + + "syntax K " + + "endmodule"; + parseConfig( + " 1+2*3 ( A => .::K => .::Bag) ", + def, + 0, + false); + } + + // test variable disambiguation when all variables are being inferred + @Test + public void test12() { + String def = + "" + + "module TEST " + + "syntax Stmt ::= \"val\" Exp \";\" Stmt [klabel('Decl)] " + + "syntax Exp " + + "syntax Stmt " + + "endmodule"; + parseRule("val _:Exp ; _", def, 0, false); + } + + // test priority exceptions (requires and ensures) + @Test + public void test13() { + String def = "" + "module TEST " + "syntax Bool ::= \"true\" [token] " + "endmodule"; + parseRule(".::K => .::K requires true", def, 0, false); + } + + // test automatic follow restriction for terminals + @Test + public void test14() { + String def = + "" + + "module TEST " + + "syntax Stmt ::= Stmt Stmt [klabel('Stmt)] " + + "syntax Exp ::= K \"==\" K [klabel('Eq)] " + + "syntax Exp ::= K \":\" K [klabel('Colon)] " + + "syntax K " + + "syntax Exp ::= K \"==K\" K [klabel('EqK)] " + + "syntax Exp ::= K \"?\" K \":\" K " + + "endmodule"; + parseRule("A::K ==K A", def, 0, false); + parseRule("A::K == K A", def, 0, true); + parseRule("A:K", def, 0, false); + parseRule("A: K", def, 0, false); + parseRule("A:Stmt ?F : Stmt", def, 0, false); + parseRule("A:Stmt ? F : Stmt", def, 0, false); + } + + // test whitespace + @Test + public void test15() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Divide(K, K) [klabel('Divide)] " + + "syntax Exp ::= K \"/\" K [klabel('Div)] " + + "syntax K " + + "endmodule"; + parseRule("Divide(K1:K, K2:K) => K1:K / K2:K", def, 0, false); + } + + // test lexical to RegexTerminal extractor + @Test + public void test16() { + assertPatterns("", "#", "", "#"); + assertPatterns("abc", "#", "abc", "#"); + assertPatterns("(? .K", def, 0, false); + } + + // test special priority + @Test + public void test19() { + String def = + "" + + "module TEST \n" + + " syntax K \n" + + " syntax KItem ::= foo(K) [klabel(foo), symbol]\n" + + " syntax Bar ::= bar() [klabel(bar), symbol]\n" + + "endmodule"; + parseRule("`foo`(`bar`(.KList) ~> .K , .KList)", def, 0, false); + parseRule("`foo`(`bar`(.KList) => .K , .KList)", def, 0, false); + } + + // test user lists + @Test + public void test20() { + String def = + "" + + "module TEST " + + "syntax Exp ::= Int \"(\" Ints \")\" " + + "syntax Exp ::= Int \"[\" Ints2 \"]\" " + + "syntax Ints ::= List{Int, \",\"} " + + "syntax Ints2 ::= NeList{Int, \".\"} " + + "syntax Int ::= r\"[0-9]+\" [token] " + + "endmodule"; + parseRule("0, 1, 2", def, 0, false); + parseProgram("0, 1, 2", def, "Ints", 0, false); + parseProgram("0()", def, "Exp", 0, false); + parseProgram("0[]", def, "Exp", 0, true); + } + + // test inference with overloading. + // regression test for issue #1586 + @Test + public void test21() { + String def = + "" + + "module TEST " + + "syntax A ::= B | \"a\" " + + "syntax B ::= \"b\" " + + "syntax TA ::= TB | t(A) [klabel(t)] " + + "syntax TB ::= t(B) [klabel(t)] " + + "endmodule"; + parseRule("t(Y) => .K", def, 0, false); + parseRule("t(_) => .K", def, 0, false); + } + + // test inference with complicated ambiguity + // regression test for issue #1603 + @Test + public void test22() { + String def = + "" + + "module TEST\n" + + "syntax T ::= \"wrap\" M [klabel(wrapM)] | \"wrap\" X [klabel(wrapX)]\n" + + "syntax A\n" + + "syntax B\n" + + "syntax M ::= A | B\n" + + "syntax N ::= A | B | X // make A and B both maximal in the intersection of N and M\n" + + "syntax X\n" + + "syntax KItem ::= label(N,T)\n" + + "endmodule"; + parseRule("X => label(X,wrap X)", def, 0, true); + } + + // automatic follow restriction should not be added for empty terminals + // regression test for issue #1575 + @Test + public void test23() { + String def = + "" + + "module TEST " + + "syntax Stmts ::= Stmt \"\" Stmts\n" + + " | \".Stmts\"\n" + + " syntax Stmt ::= \"a\"" + + "endmodule"; + parseRule("a .Stmts", def, 0, false); + } + + // Should not infer sort KList for variable in arity-1 application of a klabel + @Test + public void test24() { + String def = + "" + + "module TEST\n" + + "syntax A\n" + + "syntax A ::= f(A) [klabel(l), symbol]\n" + + "endmodule"; + parseRule( + "l(_) => .K", + def, + 0, + KApply( + KLabel("#ruleNoConditions"), + KApply( + KLabel("#KRewrite"), + KApply( + KLabel("l"), + KApply(KLabel("#SemanticCastToA"), KToken("_", Sort("#KVariable")))), + KApply(KLabel("#EmptyK"))))); + } + + @Test + public void testPriorityAssoc() throws Exception { + String def = + "module TEST " + + "syntax Exp ::= Exp \"*\" Exp [left, klabel('Mul)] " + + "> Exp \"+\" Exp [left, klabel('Plus)] " + + "| r\"[0-9]+\" [token] " + + "syntax left 'Plus " + + "syntax left 'Mul " + + "endmodule"; + parseProgram("1+2", def, "Exp", 0, false); + // System.out.println("out1 = " + out1); + parseProgram("1+2*3", def, "Exp", 0, false); + // System.out.println("out2 = " + out2); + parseProgram("1+2+3", def, "Exp", 0, false); + // System.out.println("out3 = " + out3); + } + + // test default/custom layout + @Test + public void testLayout() { + String defaultLayout = + "" + + "module TEST " + + "syntax Int ::= Int \"+\" Int " + + "syntax Int ::= r\"[0-9]+\" [token] " + + "endmodule"; + parseProgram("0 + 3 // some text", defaultLayout, "Int", 0, false); + parseProgram("0 + 3 /* some text */", defaultLayout, "Int", 0, false); + parseProgram("0 /* some text */ + 3", defaultLayout, "Int", 0, false); + parseProgram("0 + 3 ;; some text", defaultLayout, "Int", 0, true); + + String customLayout = + "" + + "module TEST " + + "syntax #Layout ::= r\"(\\\\(;([^;]|(;+([^;\\\\)])))*;\\\\))\"" + + "| r\"(;;[^\\\\n\\\\r]*)\"" + + "| r\"([\\\\ \\\\n\\\\r\\\\t])\"" + + "// -------------------------------------\n" + + // make sure standard layout still works in K defn + "syntax Int ::= Int \"+\" Int " + + "syntax Int ::= r\"[0-9]+\" [token] " + + "endmodule"; + parseProgram("0 + 3 ;; some text", customLayout, "Int", 0, false); + parseProgram("0 + 3 (; some text ;)", customLayout, "Int", 0, false); + parseProgram("0 (; some text ;) + 3", customLayout, "Int", 0, false); + parseProgram("0 + 3 // some text", customLayout, "Int", 0, true); + } + + // test KAppToTermConsVisitor for issue #985 + @Test + public void test25() { + String def = + "" + + "module TEST\n" + + " syntax E ::= \"a\" [klabel(elma), symbol]\n" + + " syntax Lst ::= E \",\" Lst [klabel(constr), symbol]\n" + + " syntax Lst2 ::= E \",\" Lst2 [klabel(constr), symbol]\n" + + " | Lst \n" + + " syntax S ::= tuple(E, E, S) [klabel(tuplee), symbol]\n" + + "endmodule"; + parseRule( + "constr(I, L) => L", + def, + 0, + KApply( + KLabel("#ruleNoConditions"), + KApply( + KLabel("#KRewrite"), + KApply( + KLabel("constr"), + KApply(KLabel("#SemanticCastToE"), KToken("I", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToLst2"), KToken("L", Sort("#KVariable")))), + KApply(KLabel("#SemanticCastToLst2"), KToken("L", Sort("#KVariable")))))); + parseRule( + "`constr`(I, (a, L)) => L", + def, + 0, + KApply( + KLabel("#ruleNoConditions"), + KApply( + KLabel("#KRewrite"), + KApply( + KLabel("constr"), + KApply(KLabel("#SemanticCastToE"), KToken("I", Sort("#KVariable"))), + KApply( + KLabel("constr"), + KApply(KLabel("elma")), + KApply(KLabel("#SemanticCastToLst2"), KToken("L", Sort("#KVariable"))))), + KApply(KLabel("#SemanticCastToLst2"), KToken("L", Sort("#KVariable")))))); + parseRule( + "tuplee(A, B, C) => C", + def, + 0, + KApply( + KLabel("#ruleNoConditions"), + KApply( + KLabel("#KRewrite"), + KApply( + KLabel("tuplee"), + KApply(KLabel("#SemanticCastToE"), KToken("A", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToE"), KToken("B", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToS"), KToken("C", Sort("#KVariable")))), + KApply(KLabel("#SemanticCastToS"), KToken("C", Sort("#KVariable")))))); + parseRule("constr(A, B, C) => .K", def, 0, false); // 3 amb at top 8 amb final + parseRule("constr(A, B, C, D) => .K", def, 0, false); // 17 amb at top 16 final + parseRule("constr(a, a, a) => .K", def, 0, true); // 'a' is not subsorted to the list + } + + @Test + public void test26() { + String def = "" + "module TEST " + "syntax Exp ::= \"\" " + "endmodule"; + parseProgram("", def, "Exp", 0, false); + } } diff --git a/kernel/src/test/java/org/kframework/parser/inner/disambiguation/AddEmptyListsTest.java b/kernel/src/test/java/org/kframework/parser/inner/disambiguation/AddEmptyListsTest.java index 3e24d2fce8f..6769747df8b 100644 --- a/kernel/src/test/java/org/kframework/parser/inner/disambiguation/AddEmptyListsTest.java +++ b/kernel/src/test/java/org/kframework/parser/inner/disambiguation/AddEmptyListsTest.java @@ -1,7 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.inner.disambiguation; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Lists; +import java.io.File; +import java.util.Set; import org.junit.Assert; import org.junit.Before; import org.junit.Ignore; @@ -16,9 +20,9 @@ import org.kframework.kore.KApply; import org.kframework.kore.KLabel; import org.kframework.main.GlobalOptions; +import org.kframework.parser.ParserUtils; import org.kframework.parser.TreeNodesToKORE; import org.kframework.parser.inner.ParseInModule; -import org.kframework.parser.ParserUtils; import org.kframework.parser.inner.RuleGrammarGenerator; import org.kframework.parser.outer.Outer; import org.kframework.utils.errorsystem.KEMException; @@ -27,194 +31,196 @@ import scala.Tuple2; import scala.util.Either; -import java.io.File; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - public class AddEmptyListsTest { - private ParseInModule parser; - private FileUtil files; - - @Rule - public TestName testName = new TestName(); - - @Before - public void setUp() throws Exception { - RuleGrammarGenerator gen = makeRuleGrammarGenerator(); - Module test = ParserUtils.parseMainModuleOuterSyntax(DEF, Source.apply("AddEmptyListsTest test definition"), "TEST"); - parser = RuleGrammarGenerator.getCombinedGrammar(gen.getRuleGrammar(test), true, files); - } - - /* - * Return a RuleGrammarGenerator which uses the default K syntax as loaded from kast.k - */ - private RuleGrammarGenerator makeRuleGrammarGenerator() { - String definitionText; - files = FileUtil.testFileUtil(); - ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); - File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); - definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); - - Definition baseK = - parser.loadDefinition("K", "K", definitionText, - definitionFile, - definitionFile.getParentFile(), - Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), - false, false, false); - - return new RuleGrammarGenerator(baseK); - } - - private void parseTerm(String term, String sort, K expected) { - parseTerm(term, sort, expected, 0); - } - - private void parseTerm(String term, String sort, K expected, int expectWarnings) { - String source = "AddEmpytListsTest." + testName.getMethodName(); - final Tuple2, K>, Set> parseResult - = parser.parseString(term, Sort(sort), new Source(source)); - if (parseResult._1().isLeft()) { - Assert.assertTrue("Unexpected parse errors" + parseResult._1().left().get(), false); - } - K actual = new TreeNodesToKORE(Outer::parseSort, false).down(parseResult._1().right().get()); - Assert.assertEquals(expected, actual); - if (parseResult._2().size() != expectWarnings) { - Assert.assertTrue("Unexpected parse warnings" + parseResult._2(), false); - } - } - - private static final String DEF = - "module TEST\n" + - "syntax A ::= \"a\" [klabel(\"alabel\"), symbol]\n" + - "syntax B ::= \"b\" [klabel(\"blabel\"), symbol]\n" + - "syntax A ::= B\n" + - "syntax As ::= List{A,\",\"} [klabel(as)]\n" + - "syntax Bs ::= List{B,\",\"} [klabel(as)]\n" + - "syntax As ::= Bs\n" + - "syntax K ::= f(As) [symbol] | g(A) [symbol] | h(Bs) [symbol]" + - "endmodule\n"; - - public static final KApply NIL = KApply(KLabel(".List{\"_,__TEST_Bs_B_Bs\"}_Bs")); - public static final KLabel BS = KLabel("_,__TEST_Bs_B_Bs"); - public static final KLabel AS = KLabel("_,__TEST_As_A_As"); - public static final KLabel CONS = BS; - public static final KApply A = KApply(KLabel("alabel")); - public static final KApply B = KApply(KLabel("blabel")); - public static final KLabel F = KLabel("f"); - public static final KLabel G = KLabel("g"); - public static final KLabel H = KLabel("h"); - public static final KLabel CAST_A = KLabel("#SemanticCastToA"); - public static final KLabel CAST_B = KLabel("#SemanticCastToB"); - public static final KLabel CAST_AS = KLabel("#SemanticCastToAs"); - public static final KLabel CAST_BS = KLabel("#SemanticCastToBs"); - - @Test - public void testEmptyList1() { - parseTerm(".As", "As", NIL); - } - - @Ignore("The API of AddEmptyLists needs to change for this to be possible") - @Test - public void testItem() { - parseTerm("a", "As", KApply(BS, A, NIL)); - } - - @Test - public void testConcreteTop() { - parseTerm(".As", "As", NIL); - parseTerm("a,a", "As", KApply(AS, A, KApply(AS, A, NIL))); - parseTerm("a,.As", "As", KApply(AS, A, NIL)); - parseTerm("a,b", "As", KApply(AS, A, KApply(CONS, B, NIL))); - parseTerm("b,.Bs", "As", KApply(CONS, B, NIL)); - parseTerm("b,b", "As", KApply(CONS, B, KApply(CONS, B, NIL))); - } - - @Test - public void testConcreteArgument() { - parseTerm("f(.As)", "K", KApply(F, NIL)); - parseTerm("f(a)", "K", KApply(F, KApply(AS, A, NIL))); - parseTerm("f(a,a)", "K", KApply(F, KApply(AS, A, KApply(AS, A, NIL)))); - parseTerm("f(a,.As)", "K", KApply(F, KApply(AS, A, NIL))); - parseTerm("f(a,b)", "K", KApply(F, KApply(AS, A, KApply(CONS, B, NIL)))); - parseTerm("f(b,.Bs)", "K", KApply(F, KApply(CONS, B, NIL))); - parseTerm("f(b,b)", "K", KApply(F, KApply(CONS, B, KApply(CONS, B, NIL)))); - } - - @Ignore("BUG: need to also propagate correct sorts to arguments of labeled application") - @Test - public void testLabeledFunSingleItem() { - parseTerm("`f`(a)", "K", KApply(F, KApply(CONS, A, NIL))); - } - - @Test - public void testLabedFunConcreteArgument() { - parseTerm("`f`(.As)", "K", KApply(F, NIL)); - parseTerm("`f`((a,a))", "K", KApply(F, KApply(AS, A, KApply(AS, A, NIL)))); - parseTerm("`f`((a,.As))", "K", KApply(F, KApply(AS, A, NIL))); - parseTerm("`f`((a,b))", "K", KApply(F, KApply(AS, A, KApply(CONS, B, NIL)))); - parseTerm("`f`((b,.Bs))", "K", KApply(F, KApply(CONS, B, NIL))); - parseTerm("`f`((b,b))", "K", KApply(F, KApply(CONS, B, KApply(CONS, B, NIL)))); - } - - @Test - public void testAnnVar() { - parseTerm("V:As", "K", KApply(CAST_AS, KVariable("V"))); - } - - @Test - public void testArgumentLabeledCons() { - parseTerm("f(a,.As)", "K", KApply(F, KApply(AS, A, NIL))); - } - - @Test - public void testArgumentLabeledNil() { - parseTerm("f(.As)", "K", KApply(F, NIL)); - } - - @Test - public void testArgumentLabeledConsSub1() { - parseTerm("h(b,.Bs)", "K", KApply(H, KApply(CONS, B, NIL))); - } - - @Test - public void testArgumentLabeledNilSub1() { - parseTerm("h(.Bs)", "K", KApply(H, NIL)); - } - - @Test - public void testArgumentInferredListVar() { - // 1 warning from inference - parseTerm("f(V)", "K", KApply(F, KApply(CAST_AS, KVariable("V")))); - } - - @Test - public void testArgumentAnnListVar() { - parseTerm("f(V:As)", "K", KApply(F, KApply(CAST_AS, KVariable("V")))); - } - - @Test - public void testArgumentAnnSubListVar() { - parseTerm("f(V:Bs)", "K", KApply(F, KApply(CAST_BS, KVariable("V")))); - } - - @Test - public void testArgumentInferredItemVar() { - // 1 warning from inference - parseTerm("f(V)~>g(V)", "K", - KSequence(KApply(F, KApply(AS, KApply(CAST_A, KVariable("V")), NIL)), - KApply(G, KApply(CAST_A, KVariable("V"))))); - } - - @Test - public void testArgumentAnnItemVar() { - parseTerm("f(V:A)", "K", - KApply(F, KApply(AS, KApply(CAST_A, KVariable("V")), NIL))); - } - - @Test - public void testArgumentAnnSubItemVar() { - parseTerm("f(V:B)", "K", - KApply(F, KApply(CONS, KApply(CAST_B, KVariable("V")), NIL))); - } + private ParseInModule parser; + private FileUtil files; + + @Rule public TestName testName = new TestName(); + + @Before + public void setUp() throws Exception { + RuleGrammarGenerator gen = makeRuleGrammarGenerator(); + Module test = + ParserUtils.parseMainModuleOuterSyntax( + DEF, Source.apply("AddEmptyListsTest test definition"), "TEST"); + parser = RuleGrammarGenerator.getCombinedGrammar(gen.getRuleGrammar(test), true, files); + } + + /* + * Return a RuleGrammarGenerator which uses the default K syntax as loaded from kast.k + */ + private RuleGrammarGenerator makeRuleGrammarGenerator() { + String definitionText; + files = FileUtil.testFileUtil(); + ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); + File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); + definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); + + Definition baseK = + parser.loadDefinition( + "K", + "K", + definitionText, + definitionFile, + definitionFile.getParentFile(), + Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), + false, + false, + false); + + return new RuleGrammarGenerator(baseK); + } + + private void parseTerm(String term, String sort, K expected) { + parseTerm(term, sort, expected, 0); + } + + private void parseTerm(String term, String sort, K expected, int expectWarnings) { + String source = "AddEmpytListsTest." + testName.getMethodName(); + final Tuple2, K>, Set> parseResult = + parser.parseString(term, Sort(sort), new Source(source)); + if (parseResult._1().isLeft()) { + Assert.assertTrue("Unexpected parse errors" + parseResult._1().left().get(), false); + } + K actual = new TreeNodesToKORE(Outer::parseSort, false).down(parseResult._1().right().get()); + Assert.assertEquals(expected, actual); + if (parseResult._2().size() != expectWarnings) { + Assert.assertTrue("Unexpected parse warnings" + parseResult._2(), false); + } + } + + private static final String DEF = + "module TEST\n" + + "syntax A ::= \"a\" [klabel(\"alabel\"), symbol]\n" + + "syntax B ::= \"b\" [klabel(\"blabel\"), symbol]\n" + + "syntax A ::= B\n" + + "syntax As ::= List{A,\",\"} [klabel(as)]\n" + + "syntax Bs ::= List{B,\",\"} [klabel(as)]\n" + + "syntax As ::= Bs\n" + + "syntax K ::= f(As) [symbol] | g(A) [symbol] | h(Bs) [symbol]" + + "endmodule\n"; + + public static final KApply NIL = KApply(KLabel(".List{\"_,__TEST_Bs_B_Bs\"}_Bs")); + public static final KLabel BS = KLabel("_,__TEST_Bs_B_Bs"); + public static final KLabel AS = KLabel("_,__TEST_As_A_As"); + public static final KLabel CONS = BS; + public static final KApply A = KApply(KLabel("alabel")); + public static final KApply B = KApply(KLabel("blabel")); + public static final KLabel F = KLabel("f"); + public static final KLabel G = KLabel("g"); + public static final KLabel H = KLabel("h"); + public static final KLabel CAST_A = KLabel("#SemanticCastToA"); + public static final KLabel CAST_B = KLabel("#SemanticCastToB"); + public static final KLabel CAST_AS = KLabel("#SemanticCastToAs"); + public static final KLabel CAST_BS = KLabel("#SemanticCastToBs"); + + @Test + public void testEmptyList1() { + parseTerm(".As", "As", NIL); + } + + @Ignore("The API of AddEmptyLists needs to change for this to be possible") + @Test + public void testItem() { + parseTerm("a", "As", KApply(BS, A, NIL)); + } + + @Test + public void testConcreteTop() { + parseTerm(".As", "As", NIL); + parseTerm("a,a", "As", KApply(AS, A, KApply(AS, A, NIL))); + parseTerm("a,.As", "As", KApply(AS, A, NIL)); + parseTerm("a,b", "As", KApply(AS, A, KApply(CONS, B, NIL))); + parseTerm("b,.Bs", "As", KApply(CONS, B, NIL)); + parseTerm("b,b", "As", KApply(CONS, B, KApply(CONS, B, NIL))); + } + + @Test + public void testConcreteArgument() { + parseTerm("f(.As)", "K", KApply(F, NIL)); + parseTerm("f(a)", "K", KApply(F, KApply(AS, A, NIL))); + parseTerm("f(a,a)", "K", KApply(F, KApply(AS, A, KApply(AS, A, NIL)))); + parseTerm("f(a,.As)", "K", KApply(F, KApply(AS, A, NIL))); + parseTerm("f(a,b)", "K", KApply(F, KApply(AS, A, KApply(CONS, B, NIL)))); + parseTerm("f(b,.Bs)", "K", KApply(F, KApply(CONS, B, NIL))); + parseTerm("f(b,b)", "K", KApply(F, KApply(CONS, B, KApply(CONS, B, NIL)))); + } + + @Ignore("BUG: need to also propagate correct sorts to arguments of labeled application") + @Test + public void testLabeledFunSingleItem() { + parseTerm("`f`(a)", "K", KApply(F, KApply(CONS, A, NIL))); + } + + @Test + public void testLabedFunConcreteArgument() { + parseTerm("`f`(.As)", "K", KApply(F, NIL)); + parseTerm("`f`((a,a))", "K", KApply(F, KApply(AS, A, KApply(AS, A, NIL)))); + parseTerm("`f`((a,.As))", "K", KApply(F, KApply(AS, A, NIL))); + parseTerm("`f`((a,b))", "K", KApply(F, KApply(AS, A, KApply(CONS, B, NIL)))); + parseTerm("`f`((b,.Bs))", "K", KApply(F, KApply(CONS, B, NIL))); + parseTerm("`f`((b,b))", "K", KApply(F, KApply(CONS, B, KApply(CONS, B, NIL)))); + } + + @Test + public void testAnnVar() { + parseTerm("V:As", "K", KApply(CAST_AS, KVariable("V"))); + } + + @Test + public void testArgumentLabeledCons() { + parseTerm("f(a,.As)", "K", KApply(F, KApply(AS, A, NIL))); + } + + @Test + public void testArgumentLabeledNil() { + parseTerm("f(.As)", "K", KApply(F, NIL)); + } + + @Test + public void testArgumentLabeledConsSub1() { + parseTerm("h(b,.Bs)", "K", KApply(H, KApply(CONS, B, NIL))); + } + + @Test + public void testArgumentLabeledNilSub1() { + parseTerm("h(.Bs)", "K", KApply(H, NIL)); + } + + @Test + public void testArgumentInferredListVar() { + // 1 warning from inference + parseTerm("f(V)", "K", KApply(F, KApply(CAST_AS, KVariable("V")))); + } + + @Test + public void testArgumentAnnListVar() { + parseTerm("f(V:As)", "K", KApply(F, KApply(CAST_AS, KVariable("V")))); + } + + @Test + public void testArgumentAnnSubListVar() { + parseTerm("f(V:Bs)", "K", KApply(F, KApply(CAST_BS, KVariable("V")))); + } + + @Test + public void testArgumentInferredItemVar() { + // 1 warning from inference + parseTerm( + "f(V)~>g(V)", + "K", + KSequence( + KApply(F, KApply(AS, KApply(CAST_A, KVariable("V")), NIL)), + KApply(G, KApply(CAST_A, KVariable("V"))))); + } + + @Test + public void testArgumentAnnItemVar() { + parseTerm("f(V:A)", "K", KApply(F, KApply(AS, KApply(CAST_A, KVariable("V")), NIL))); + } + + @Test + public void testArgumentAnnSubItemVar() { + parseTerm("f(V:B)", "K", KApply(F, KApply(CONS, KApply(CAST_B, KVariable("V")), NIL))); + } } diff --git a/kernel/src/test/java/org/kframework/parser/json/JsonSerializationTests.java b/kernel/src/test/java/org/kframework/parser/json/JsonSerializationTests.java index ca9e9b7868b..f2253d41575 100644 --- a/kernel/src/test/java/org/kframework/parser/json/JsonSerializationTests.java +++ b/kernel/src/test/java/org/kframework/parser/json/JsonSerializationTests.java @@ -1,7 +1,15 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.json; +import static org.kframework.Collections.immutable; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.Sets; +import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; +import javax.json.Json; +import javax.json.JsonObjectBuilder; +import javax.json.JsonStructure; import junit.framework.Assert; import org.junit.Test; import org.kframework.attributes.Att; @@ -12,74 +20,76 @@ import org.kframework.parser.ParserUtils; import org.kframework.unparser.ToJson; -import javax.json.Json; -import javax.json.JsonObjectBuilder; -import javax.json.JsonStructure; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; - -import static org.kframework.Collections.immutable; -import static org.kframework.kore.KORE.*; - public class JsonSerializationTests { - @Test - public void test1() { - K k = KApply(KLabel("#ruleNoConditions"),KApply(KLabel("#KRewrite"), - KApply(KLabel("tuplee"), - KApply(KLabel("#SemanticCastToE"), KToken("A",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToE"), KToken("B",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToS"), KToken("C",Sort("#KVariable")))), - KApply(KLabel("#SemanticCastToS"), KToken("C",Sort("#KVariable"))) - )); + @Test + public void test1() { + K k = + KApply( + KLabel("#ruleNoConditions"), + KApply( + KLabel("#KRewrite"), + KApply( + KLabel("tuplee"), + KApply(KLabel("#SemanticCastToE"), KToken("A", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToE"), KToken("B", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToS"), KToken("C", Sort("#KVariable")))), + KApply(KLabel("#SemanticCastToS"), KToken("C", Sort("#KVariable"))))); - JsonStructure js = ToJson.toJson(k); - JsonObjectBuilder term = Json.createObjectBuilder(); - term.add("format", "KAST"); - term.add("version", ToJson.version); - term.add("term", js); - K k2 = JsonParser.parseJson(term.build()); - Assert.assertEquals(k, k2); - } + JsonStructure js = ToJson.toJson(k); + JsonObjectBuilder term = Json.createObjectBuilder(); + term.add("format", "KAST"); + term.add("version", ToJson.version); + term.add("term", js); + K k2 = JsonParser.parseJson(term.build()); + Assert.assertEquals(k, k2); + } - @Test - public void test2() { - K k = KApply(KLabel("#ruleNoConditions", Sort("X", Sort("6"), Sort("Z"))),KApply(KLabel("#KRewrite", Sort("P")), - KApply(KLabel("tuplee"), - KApply(KLabel("#SemanticCastToE"), KToken("A",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToE"), KToken("B",Sort("#KVariable"))), - KApply(KLabel("#SemanticCastToS"), KToken("C",Sort("#KVariable")))), - KApply(KLabel("#SemanticCastToS"), KToken("C",Sort("#KVariable"))) - )); + @Test + public void test2() { + K k = + KApply( + KLabel("#ruleNoConditions", Sort("X", Sort("6"), Sort("Z"))), + KApply( + KLabel("#KRewrite", Sort("P")), + KApply( + KLabel("tuplee"), + KApply(KLabel("#SemanticCastToE"), KToken("A", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToE"), KToken("B", Sort("#KVariable"))), + KApply(KLabel("#SemanticCastToS"), KToken("C", Sort("#KVariable")))), + KApply(KLabel("#SemanticCastToS"), KToken("C", Sort("#KVariable"))))); - JsonStructure js = ToJson.toJson(k); - JsonObjectBuilder term = Json.createObjectBuilder(); - term.add("format", "KAST"); - term.add("version", ToJson.version); - term.add("term", js); - K k2 = JsonParser.parseJson(term.build()); - Assert.assertEquals(k, k2); - } + JsonStructure js = ToJson.toJson(k); + JsonObjectBuilder term = Json.createObjectBuilder(); + term.add("format", "KAST"); + term.add("version", ToJson.version); + term.add("term", js); + K k2 = JsonParser.parseJson(term.build()); + Assert.assertEquals(k, k2); + } - @Test - public void test3() throws UnsupportedEncodingException { - String defstr = "" + - "module TEST " + - "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + - "| Exp \"*\" Exp [klabel('Mul)] " + - "| r\"[0-9]+\" [token] " + - "syntax K " + - "syntax TopCell ::= \"\" KCell StateCell \"\" [klabel(), cell] " + - "syntax KCell ::= \"\" K \"\" [klabel(), cell] " + - "syntax StateCell ::= \"\" K \"\" [klabel(), cell] " + - "endmodule"; + @Test + public void test3() throws UnsupportedEncodingException { + String defstr = + "" + + "module TEST " + + "syntax Exp ::= Exp \"+\" Exp [klabel('Plus), prefer] " + + "| Exp \"*\" Exp [klabel('Mul)] " + + "| r\"[0-9]+\" [token] " + + "syntax K " + + "syntax TopCell ::= \"\" KCell StateCell \"\" [klabel(), cell] " + + "syntax KCell ::= \"\" K \"\" [klabel(), cell] " + + "syntax StateCell ::= \"\" K \"\" [klabel(), cell] " + + "endmodule"; - Module mod = ParserUtils.parseMainModuleOuterSyntax(defstr, Source.apply("generated by RuleGrammarTest"), "TEST"); - Definition def1 = Definition.apply(mod, immutable(Sets.newHashSet(mod)), Att.empty()); + Module mod = + ParserUtils.parseMainModuleOuterSyntax( + defstr, Source.apply("generated by RuleGrammarTest"), "TEST"); + Definition def1 = Definition.apply(mod, immutable(Sets.newHashSet(mod)), Att.empty()); - String inputDefinition = new String(ToJson.apply(def1), StandardCharsets.UTF_8); - Definition def2 = JsonParser.parseDefinition(inputDefinition); + String inputDefinition = new String(ToJson.apply(def1), StandardCharsets.UTF_8); + Definition def2 = JsonParser.parseDefinition(inputDefinition); - Assert.assertEquals(def1, def2); - } + Assert.assertEquals(def1, def2); + } } diff --git a/kernel/src/test/java/org/kframework/parser/outer/MDsourceTest.java b/kernel/src/test/java/org/kframework/parser/outer/MDsourceTest.java index 756b27c281c..0a737d9180a 100644 --- a/kernel/src/test/java/org/kframework/parser/outer/MDsourceTest.java +++ b/kernel/src/test/java/org/kframework/parser/outer/MDsourceTest.java @@ -10,95 +10,109 @@ import org.kframework.utils.errorsystem.KExceptionManager; public class MDsourceTest { - @Test - public void test1() { - String selectExp = "k"; - String mdTxt = "1\n" + - " ```k\n" + - " // ignore indentation\n" + - "require \"a.md\"\n" + - " ```\n" + - "6\n" + - "```{a b}\n" + - "8\n" + - "```\n" + - "10\n" + - "```{k x}\n" + - "module TEST\n" + - "```\n" + - "\n" + - "``` { k hidden warning\n" + - "}\n" + - "```\n" + - "\n" + - "```{y k}\n" + - "endmodule"; - GlobalOptions go = new GlobalOptions(); - go.warnings = GlobalOptions.Warnings.ALL; - KExceptionManager kem = new KExceptionManager(go); - ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(kem, selectExp); - String kTxt = mdExtractor.extract(mdTxt, new Source(MDsourceTest.class.toString())); - String expectedK = "\n" + - " \n" + - " // ignore indentation\n" + - "require \"a.md\"\n" + - " \n" + - "\n" + - " \n" + - "\n" + - "\n" + - "\n" + - " \n" + - "module TEST\n" + - "\n" + - "\n" + - " \n" + - "\n" + - "\n" + - "\n" + - " \n" + - "endmodule"; - Assert.assertEquals(expectedK, kTxt); - Assert.assertEquals(1, kem.getExceptions().size()); - } + @Test + public void test1() { + String selectExp = "k"; + String mdTxt = + "1\n" + + " ```k\n" + + " // ignore indentation\n" + + "require \"a.md\"\n" + + " ```\n" + + "6\n" + + "```{a b}\n" + + "8\n" + + "```\n" + + "10\n" + + "```{k x}\n" + + "module TEST\n" + + "```\n" + + "\n" + + "``` { k hidden warning\n" + + "}\n" + + "```\n" + + "\n" + + "```{y k}\n" + + "endmodule"; + GlobalOptions go = new GlobalOptions(); + go.warnings = GlobalOptions.Warnings.ALL; + KExceptionManager kem = new KExceptionManager(go); + ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(kem, selectExp); + String kTxt = mdExtractor.extract(mdTxt, new Source(MDsourceTest.class.toString())); + String expectedK = + "\n" + + " \n" + + " // ignore indentation\n" + + "require \"a.md\"\n" + + " \n" + + "\n" + + " \n" + + "\n" + + "\n" + + "\n" + + " \n" + + "module TEST\n" + + "\n" + + "\n" + + " \n" + + "\n" + + "\n" + + "\n" + + " \n" + + "endmodule"; + Assert.assertEquals(expectedK, kTxt); + Assert.assertEquals(1, kem.getExceptions().size()); + } - @Test(expected = KEMException.class) - public void test2() { - String selectExp = "k|"; - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(kem, selectExp); - } + @Test(expected = KEMException.class) + public void test2() { + String selectExp = "k|"; + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(kem, selectExp); + } - @Test(expected = KEMException.class) - public void test3() { - String selectExp = "k|a b"; - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(kem, selectExp); - } + @Test(expected = KEMException.class) + public void test3() { + String selectExp = "k|a b"; + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + ExtractFencedKCodeFromMarkdown mdExtractor = new ExtractFencedKCodeFromMarkdown(kem, selectExp); + } - @Test - public void test4() { - KExceptionManager kem = new KExceptionManager(new GlobalOptions(false, GlobalOptions.Warnings.ALL, false)); - TagSelector.parseTags("k a", new Source(MDsourceTest.class.toString()), kem); - Assert.assertEquals(1, kem.getExceptions().size()); - } + @Test + public void test4() { + KExceptionManager kem = + new KExceptionManager(new GlobalOptions(false, GlobalOptions.Warnings.ALL, false)); + TagSelector.parseTags("k a", new Source(MDsourceTest.class.toString()), kem); + Assert.assertEquals(1, kem.getExceptions().size()); + } - @Test - public void test5() { - KExceptionManager kem = new KExceptionManager(new GlobalOptions(false, GlobalOptions.Warnings.ALL, false)); - TagSelector.parseTags("{k a", new Source(MDsourceTest.class.toString()), kem); - Assert.assertEquals(1, kem.getExceptions().size()); - } + @Test + public void test5() { + KExceptionManager kem = + new KExceptionManager(new GlobalOptions(false, GlobalOptions.Warnings.ALL, false)); + TagSelector.parseTags("{k a", new Source(MDsourceTest.class.toString()), kem); + Assert.assertEquals(1, kem.getExceptions().size()); + } - @Test - public void test6() { - KExceptionManager kem = new KExceptionManager(new GlobalOptions()); - Assert.assertEquals(2, TagSelector.parseTags("{k a}", new Source(MDsourceTest.class.toString()), kem).size()); - Assert.assertEquals(2, TagSelector.parseTags("{.k .a}", new Source(MDsourceTest.class.toString()), kem).size()); - Assert.assertEquals(2, TagSelector.parseTags("{.k a}", new Source(MDsourceTest.class.toString()), kem).size()); - Assert.assertEquals(1, TagSelector.parseTags("k", new Source(MDsourceTest.class.toString()), kem).size()); - Assert.assertEquals(0, TagSelector.parseTags("", new Source(MDsourceTest.class.toString()), kem).size()); - Assert.assertEquals(0, TagSelector.parseTags(" ", new Source(MDsourceTest.class.toString()), kem).size()); - Assert.assertEquals(3, TagSelector.parseTags("{.k .numberLines startFrom=\"0\"}", new Source(MDsourceTest.class.toString()), kem).size()); - } + @Test + public void test6() { + KExceptionManager kem = new KExceptionManager(new GlobalOptions()); + Assert.assertEquals( + 2, TagSelector.parseTags("{k a}", new Source(MDsourceTest.class.toString()), kem).size()); + Assert.assertEquals( + 2, TagSelector.parseTags("{.k .a}", new Source(MDsourceTest.class.toString()), kem).size()); + Assert.assertEquals( + 2, TagSelector.parseTags("{.k a}", new Source(MDsourceTest.class.toString()), kem).size()); + Assert.assertEquals( + 1, TagSelector.parseTags("k", new Source(MDsourceTest.class.toString()), kem).size()); + Assert.assertEquals( + 0, TagSelector.parseTags("", new Source(MDsourceTest.class.toString()), kem).size()); + Assert.assertEquals( + 0, TagSelector.parseTags(" ", new Source(MDsourceTest.class.toString()), kem).size()); + Assert.assertEquals( + 3, + TagSelector.parseTags( + "{.k .numberLines startFrom=\"0\"}", new Source(MDsourceTest.class.toString()), kem) + .size()); + } } diff --git a/kernel/src/test/java/org/kframework/parser/outer/OuterParsingTests.java b/kernel/src/test/java/org/kframework/parser/outer/OuterParsingTests.java index ab0db546896..8f2031c28f2 100644 --- a/kernel/src/test/java/org/kframework/parser/outer/OuterParsingTests.java +++ b/kernel/src/test/java/org/kframework/parser/outer/OuterParsingTests.java @@ -1,10 +1,10 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser.outer; -import java.util.List; +import static org.kframework.kore.KORE.*; +import java.util.List; import junit.framework.Assert; - import org.junit.Test; import org.kframework.attributes.Source; import org.kframework.builtin.Sorts; @@ -12,38 +12,40 @@ import org.kframework.kil.Module; import org.kframework.kil.StringSentence; -import static org.kframework.kore.KORE.*; - public class OuterParsingTests { - @Test - public void testEmptyRules() { - String def = "module TEST rule endmodule"; - - List defItemList = Outer.parse(Source.apply("generated by OuterParsingTests"), def, null); - - Module mod = (Module) defItemList.get(0); - StringSentence sen = (StringSentence) mod.getItems().get(0); - Assert.assertEquals(sen.getContent(), ""); - } - - @Test - public void testClaimKeyword() throws Exception { - String def = "module TEST claim X => Y endmodule"; - - List defItemList = Outer.parse(Source.apply("generated by OuterParsingTests"), def, null); - - Module mod = (Module) defItemList.get(0); - StringSentence sen = (StringSentence) mod.getItems().get(0); - Assert.assertEquals(sen.getContent(), "X => Y"); - Assert.assertEquals(sen.getType(), "claim"); - } - - @Test - public void testSortParsing() { - Assert.assertEquals(Sorts.K().toString(), Outer.parseSort(Sorts.K().toString()).toString()); - Assert.assertEquals(Sorts.MInt().toString(), Outer.parseSort(Sorts.MInt().toString()).toString()); - Assert.assertEquals(Sort("X", Sort("6"), Sort("Z")).toString(), - Outer.parseSort(Sort("X", Sort("6"), Sort("Z")).toString()).toString()); - } + @Test + public void testEmptyRules() { + String def = "module TEST rule endmodule"; + + List defItemList = + Outer.parse(Source.apply("generated by OuterParsingTests"), def, null); + + Module mod = (Module) defItemList.get(0); + StringSentence sen = (StringSentence) mod.getItems().get(0); + Assert.assertEquals(sen.getContent(), ""); + } + + @Test + public void testClaimKeyword() throws Exception { + String def = "module TEST claim X => Y endmodule"; + + List defItemList = + Outer.parse(Source.apply("generated by OuterParsingTests"), def, null); + + Module mod = (Module) defItemList.get(0); + StringSentence sen = (StringSentence) mod.getItems().get(0); + Assert.assertEquals(sen.getContent(), "X => Y"); + Assert.assertEquals(sen.getType(), "claim"); + } + + @Test + public void testSortParsing() { + Assert.assertEquals(Sorts.K().toString(), Outer.parseSort(Sorts.K().toString()).toString()); + Assert.assertEquals( + Sorts.MInt().toString(), Outer.parseSort(Sorts.MInt().toString()).toString()); + Assert.assertEquals( + Sort("X", Sort("6"), Sort("Z")).toString(), + Outer.parseSort(Sort("X", Sort("6"), Sort("Z")).toString()).toString()); + } } diff --git a/kernel/src/test/java/org/kframework/unparser/AddBracketsTest.java b/kernel/src/test/java/org/kframework/unparser/AddBracketsTest.java index 9242ae61968..0a095e2c09d 100644 --- a/kernel/src/test/java/org/kframework/unparser/AddBracketsTest.java +++ b/kernel/src/test/java/org/kframework/unparser/AddBracketsTest.java @@ -1,7 +1,11 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import static org.junit.Assert.*; + import com.google.common.collect.Lists; +import java.io.File; +import java.util.Set; import org.junit.Before; import org.junit.Test; import org.kframework.attributes.Source; @@ -11,9 +15,9 @@ import org.kframework.kompile.Kompile; import org.kframework.kore.K; import org.kframework.main.GlobalOptions; +import org.kframework.parser.ParserUtils; import org.kframework.parser.TreeNodesToKORE; import org.kframework.parser.inner.ParseInModule; -import org.kframework.parser.ParserUtils; import org.kframework.parser.inner.RuleGrammarGenerator; import org.kframework.parser.outer.Outer; import org.kframework.utils.errorsystem.KEMException; @@ -22,85 +26,90 @@ import scala.Tuple2; import scala.util.Either; -import java.io.File; -import java.util.Set; - -import static org.junit.Assert.*; - public class AddBracketsTest { - private RuleGrammarGenerator gen; - private FileUtil files; - - @Before - public void setUp() throws Exception{ - gen = makeRuleGrammarGenerator(); - } + private RuleGrammarGenerator gen; + private FileUtil files; - public RuleGrammarGenerator makeRuleGrammarGenerator() { - String definitionText; - files = FileUtil.testFileUtil(); - ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); - File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); - definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); + @Before + public void setUp() throws Exception { + gen = makeRuleGrammarGenerator(); + } - Definition baseK = - parser.loadDefinition("K", "K", definitionText, - definitionFile, - definitionFile.getParentFile(), - Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), - false, false, false); + public RuleGrammarGenerator makeRuleGrammarGenerator() { + String definitionText; + files = FileUtil.testFileUtil(); + ParserUtils parser = new ParserUtils(files, new KExceptionManager(new GlobalOptions())); + File definitionFile = new File(Kompile.BUILTIN_DIRECTORY + "/prelude.md"); + definitionText = files.loadFromWorkingDirectory(definitionFile.getPath()); - return new RuleGrammarGenerator(baseK); - } + Definition baseK = + parser.loadDefinition( + "K", + "K", + definitionText, + definitionFile, + definitionFile.getParentFile(), + Lists.newArrayList(Kompile.BUILTIN_DIRECTORY), + false, + false, + false); - private Module parseModule(String def) { - return ParserUtils.parseMainModuleOuterSyntax(def, Source.apply("generated by AddBracketsTest"), "TEST"); - } + return new RuleGrammarGenerator(baseK); + } - @Test - public void testLambda() { - String def = "module TEST\n" + - " syntax Val ::= Id\n" + - " | \"lambda\" Id \".\" Exp\n" + - " syntax Exp ::= Val\n" + - " | Exp Exp [left]\n" + - " | \"(\" Exp \")\" [bracket]\n" + - " syntax Id ::= r\"(? _+__TEST\n" + - "endmodule\n"; - unparserTest(def, "1 + 1 + 1 + 1"); - unparserTest(def, "1 + ( 1 + 1 ) + 1"); - unparserTest(def, "1 + ( 1 + ( 1 + 1 ) )"); - unparserTest(def, "1 + 1 * 1"); - unparserTest(def, "( 1 + 1 ) * 1"); - } + @Test + public void testLambda() { + String def = + "module TEST\n" + + " syntax Val ::= Id\n" + + " | \"lambda\" Id \".\" Exp\n" + + " syntax Exp ::= Val\n" + + " | Exp Exp [left]\n" + + " | \"(\" Exp \")\" [bracket]\n" + + " syntax Id ::= r\"(? _+__TEST\n" + + "endmodule\n"; + unparserTest(def, "1 + 1 + 1 + 1"); + unparserTest(def, "1 + ( 1 + 1 ) + 1"); + unparserTest(def, "1 + ( 1 + ( 1 + 1 ) )"); + unparserTest(def, "1 + 1 * 1"); + unparserTest(def, "( 1 + 1 ) * 1"); + } - private K parseTerm(String pgm, ParseInModule parser) { - Tuple2, K>, Set> result = parser.parseString(pgm, Sorts.KItem(), Source.apply("generated by AddBracketsTest")); - assertEquals(0, result._2().size()); - return new TreeNodesToKORE(Outer::parseSort, false).down(result._1().right().get()); - } + private void unparserTest(String def, String pgm) { + Module test = parseModule(def); + ParseInModule parser = + RuleGrammarGenerator.getCombinedGrammar(gen.getProgramsGrammar(test), true, files); + K parsed = parseTerm(pgm, parser); + KPrint kprint = new KPrint(); + String unparsed = kprint.unparseTerm(parsed, test); + assertEquals(pgm, unparsed); + } + private K parseTerm(String pgm, ParseInModule parser) { + Tuple2, K>, Set> result = + parser.parseString(pgm, Sorts.KItem(), Source.apply("generated by AddBracketsTest")); + assertEquals(0, result._2().size()); + return new TreeNodesToKORE(Outer::parseSort, false).down(result._1().right().get()); + } } diff --git a/kernel/src/test/java/org/kframework/unparser/BinaryKASTTest.java b/kernel/src/test/java/org/kframework/unparser/BinaryKASTTest.java index eb5ccb4af26..192be2d42b3 100644 --- a/kernel/src/test/java/org/kframework/unparser/BinaryKASTTest.java +++ b/kernel/src/test/java/org/kframework/unparser/BinaryKASTTest.java @@ -1,50 +1,58 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import static org.junit.Assert.*; +import static org.kframework.kore.KORE.*; + +import java.io.File; import org.junit.Ignore; import org.junit.Test; import org.kframework.kore.K; import org.kframework.parser.binary.BinaryParser; import org.kframework.utils.file.FileUtil; -import java.io.File; - -import static org.junit.Assert.*; -import static org.kframework.kore.KORE.*; - public class BinaryKASTTest { - K sharedTerm = KApply(KLabel("_|->_"), KToken("x", Sort("Id")), KToken("1", Sort("Int"))); - K sharedTerm2 = KToken("foo", Sort("Bar")); - - K term = KApply(KLabel(""), KApply(KLabel(""), KSequence(sharedTerm2, - KRewrite(KVariable("Baz"), KVariable("Baz2")), InjectedKLabel(KLabel("_+_")), KApply(KLabel("foo")))), - KApply(KVariable("Lbl"), sharedTerm, sharedTerm, sharedTerm2, sharedTerm)); - - @Test - public void testWriteThenRead() throws Exception { - byte[] str = ToBinary.apply(term); - K result2 = BinaryParser.parse(str); - assertEquals(term, result2); - } - - @Test - public void testConcatenate() throws Exception { - byte[] str = ToBinary.apply(term); - byte[] krewrite = new byte[str.length * 2 - 8]; - System.arraycopy(str, 0, krewrite, 0, str.length - 1); - System.arraycopy(str, 8, krewrite, str.length - 1, str.length - 9); - krewrite[krewrite.length - 2] = BinaryParser.KREWRITE; - krewrite[krewrite.length - 1] = BinaryParser.END; - K result2 = BinaryParser.parse(krewrite); - assertEquals(KRewrite(term, term), result2); - } - - @Test @Ignore - public void testLarger() throws Exception { - FileUtil.testFileUtil(); - byte[] kast = FileUtil.loadBytes(new File("/home/dwightguth/c-semantics/tmp-kcc-FzjROvt")); - K result = BinaryParser.parse(kast); - System.out.println(ToKast.apply(result)); - } + K sharedTerm = KApply(KLabel("_|->_"), KToken("x", Sort("Id")), KToken("1", Sort("Int"))); + K sharedTerm2 = KToken("foo", Sort("Bar")); + + K term = + KApply( + KLabel(""), + KApply( + KLabel(""), + KSequence( + sharedTerm2, + KRewrite(KVariable("Baz"), KVariable("Baz2")), + InjectedKLabel(KLabel("_+_")), + KApply(KLabel("foo")))), + KApply(KVariable("Lbl"), sharedTerm, sharedTerm, sharedTerm2, sharedTerm)); + + @Test + public void testWriteThenRead() throws Exception { + byte[] str = ToBinary.apply(term); + K result2 = BinaryParser.parse(str); + assertEquals(term, result2); + } + + @Test + public void testConcatenate() throws Exception { + byte[] str = ToBinary.apply(term); + byte[] krewrite = new byte[str.length * 2 - 8]; + System.arraycopy(str, 0, krewrite, 0, str.length - 1); + System.arraycopy(str, 8, krewrite, str.length - 1, str.length - 9); + krewrite[krewrite.length - 2] = BinaryParser.KREWRITE; + krewrite[krewrite.length - 1] = BinaryParser.END; + K result2 = BinaryParser.parse(krewrite); + assertEquals(KRewrite(term, term), result2); + } + + @Test + @Ignore + public void testLarger() throws Exception { + FileUtil.testFileUtil(); + byte[] kast = FileUtil.loadBytes(new File("/home/dwightguth/c-semantics/tmp-kcc-FzjROvt")); + K result = BinaryParser.parse(kast); + System.out.println(ToKast.apply(result)); + } } diff --git a/kernel/src/test/java/org/kframework/unparser/KPrintTest.java b/kernel/src/test/java/org/kframework/unparser/KPrintTest.java index 05e7cd185d5..cc550fd6818 100644 --- a/kernel/src/test/java/org/kframework/unparser/KPrintTest.java +++ b/kernel/src/test/java/org/kframework/unparser/KPrintTest.java @@ -1,6 +1,12 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.unparser; +import static org.junit.Assert.*; +import static org.kframework.kore.KORE.*; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; import org.junit.Test; import org.kframework.attributes.Source; import org.kframework.kore.K; @@ -8,63 +14,55 @@ import org.kframework.parser.json.JsonParser; import org.kframework.parser.kast.KastParser; -import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import static org.junit.Assert.*; -import static org.kframework.kore.KORE.*; - public class KPrintTest { - private K cell(String cellName, K cellContent) { - return KApply(KLabel(cellName), cellContent); - } + private K cell(String cellName, K cellContent) { + return KApply(KLabel(cellName), cellContent); + } - OutputModes[] outputModes = new OutputModes[] { OutputModes.JSON - , OutputModes.BINARY - , OutputModes.KAST - }; + OutputModes[] outputModes = + new OutputModes[] {OutputModes.JSON, OutputModes.BINARY, OutputModes.KAST}; - private String bytes2String(byte[] input) { - return new String(input, StandardCharsets.UTF_8); - } + private String bytes2String(byte[] input) { + return new String(input, StandardCharsets.UTF_8); + } - private String asKast(K term) { - return bytes2String(KPrint.serialize(term, OutputModes.KAST)); - } + private String asKast(K term) { + return bytes2String(KPrint.serialize(term, OutputModes.KAST)); + } - private K unparseThenParse(K origTerm, OutputModes outputMode) { - byte[] unparsed = KPrint.serialize(origTerm, outputMode); - return switch (outputMode) { - case JSON -> JsonParser.parse(unparsed); - case BINARY -> BinaryParser.parse(unparsed); - case KAST -> KastParser.parse(bytes2String(unparsed), new Source("KPrintTest")); - default -> KToken("###", Sort("UnsupportedOutputMode")); - }; - } + private K unparseThenParse(K origTerm, OutputModes outputMode) { + byte[] unparsed = KPrint.serialize(origTerm, outputMode); + return switch (outputMode) { + case JSON -> JsonParser.parse(unparsed); + case BINARY -> BinaryParser.parse(unparsed); + case KAST -> KastParser.parse(bytes2String(unparsed), new Source("KPrintTest")); + default -> KToken("###", Sort("UnsupportedOutputMode")); + }; + } - @Test - public void testUnparseThenParse() throws Exception { + @Test + public void testUnparseThenParse() throws Exception { - List terms = new ArrayList<>(); - terms.add(KApply(KLabel("_|->_"), KToken("x", Sort("Id")), KToken("1", Sort("Int")))); - terms.add( KToken("foo", Sort("Bar")) ); - terms.add( KApply(KLabel("_+_"), KVariable("Baz"), KVariable("Baz2")) ); - terms.add( cell("", KSequence( terms.get(1) - , terms.get(2) - , InjectedKLabel(KLabel("_+_")) - , KApply(KLabel("foo")) - ) - ) - ); - terms.add( KApply(KLabel(""), terms.get(3), KApply(KVariable("Lbl"), terms.get(0), terms.get(0), terms.get(1), terms.get(0))) ); + List terms = new ArrayList<>(); + terms.add(KApply(KLabel("_|->_"), KToken("x", Sort("Id")), KToken("1", Sort("Int")))); + terms.add(KToken("foo", Sort("Bar"))); + terms.add(KApply(KLabel("_+_"), KVariable("Baz"), KVariable("Baz2"))); + terms.add( + cell( + "", + KSequence( + terms.get(1), terms.get(2), InjectedKLabel(KLabel("_+_")), KApply(KLabel("foo"))))); + terms.add( + KApply( + KLabel(""), + terms.get(3), + KApply(KVariable("Lbl"), terms.get(0), terms.get(0), terms.get(1), terms.get(0)))); - for (K term: terms) { - for (OutputModes outputMode: outputModes) { - assertEquals(asKast(term), asKast(unparseThenParse(term, outputMode))); - } - } + for (K term : terms) { + for (OutputModes outputMode : outputModes) { + assertEquals(asKast(term), asKast(unparseThenParse(term, outputMode))); + } } + } } diff --git a/kernel/src/test/java/org/kframework/utils/BaseTestCase.java b/kernel/src/test/java/org/kframework/utils/BaseTestCase.java index 4ccafc4829a..aec5cb88aad 100644 --- a/kernel/src/test/java/org/kframework/utils/BaseTestCase.java +++ b/kernel/src/test/java/org/kframework/utils/BaseTestCase.java @@ -6,6 +6,7 @@ import com.google.inject.Key; import com.google.inject.Provides; import com.google.inject.name.Names; +import java.io.File; import org.junit.Before; import org.junit.runner.RunWith; import org.kframework.kast.KastOptions; @@ -14,8 +15,8 @@ import org.kframework.kompile.KompileOptions; import org.kframework.main.Main; import org.kframework.utils.errorsystem.KExceptionManager; -import org.kframework.utils.file.FileUtil; import org.kframework.utils.file.DefinitionDir; +import org.kframework.utils.file.FileUtil; import org.kframework.utils.file.KompiledDir; import org.kframework.utils.inject.Concrete; import org.kframework.utils.inject.DefinitionScope; @@ -23,84 +24,70 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.io.File; - @RunWith(MockitoJUnitRunner.class) public abstract class BaseTestCase { - @Mock - protected Context context; + @Mock protected Context context; - @Mock - protected Definition definition; + @Mock protected Definition definition; - @Mock - protected KExceptionManager kem; + @Mock protected KExceptionManager kem; - @Mock - protected Stopwatch sw; + @Mock protected Stopwatch sw; - @Mock - protected BinaryLoader loader; + @Mock protected BinaryLoader loader; - @Mock - protected RunProcess rp; + @Mock protected RunProcess rp; - @Mock - protected - File kompiledDir; + @Mock protected File kompiledDir; - @Mock - File definitionDir; + @Mock File definitionDir; - @Mock - File tempDir; + @Mock File tempDir; - @Mock - protected FileUtil files; + @Mock protected FileUtil files; - @Mock - protected DefinitionScope scope; + @Mock protected DefinitionScope scope; - @Before - public void setUpWiring() { - context.kompileOptions = new KompileOptions(); - } - - public class DefinitionSpecificTestModule extends AbstractModule { - - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(KompileOptions.class).toInstance(context.kompileOptions); - bind(Definition.class).toInstance(definition); - bind(File.class).annotatedWith(KompiledDir.class).toInstance(kompiledDir); - bind(File.class).annotatedWith(DefinitionDir.class).toInstance(definitionDir); - bind(Definition.class).annotatedWith(Concrete.class).toInstance(definition); - } - - @Provides - Context context() { - return context; - } - } + @Before + public void setUpWiring() { + context.kompileOptions = new KompileOptions(); + } - public class TestModule extends AbstractModule { + public class DefinitionSpecificTestModule extends AbstractModule { - @Override - protected void configure() { - binder().requireAtInjectOnConstructors(); - bind(RunProcess.class).toInstance(rp); - bind(KastOptions.class).toInstance(new KastOptions()); - } + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(KompileOptions.class).toInstance(context.kompileOptions); + bind(Definition.class).toInstance(definition); + bind(File.class).annotatedWith(KompiledDir.class).toInstance(kompiledDir); + bind(File.class).annotatedWith(DefinitionDir.class).toInstance(definitionDir); + bind(Definition.class).annotatedWith(Concrete.class).toInstance(definition); + } + @Provides + Context context() { + return context; } + } + + public class TestModule extends AbstractModule { - public void prepInjector(Injector injector, String tool, String[] args) { - SimpleScope scope = injector.getInstance(Key.get(SimpleScope.class, Names.named("requestScope"))); - scope.enter(); - DefinitionScope definitionScope = injector.getInstance(DefinitionScope.class); - definitionScope.enter(new File(".")); - Main.seedInjector(scope, tool, args, new File("."), System.getenv(), System.nanoTime()); + @Override + protected void configure() { + binder().requireAtInjectOnConstructors(); + bind(RunProcess.class).toInstance(rp); + bind(KastOptions.class).toInstance(new KastOptions()); } + } + + public void prepInjector(Injector injector, String tool, String[] args) { + SimpleScope scope = + injector.getInstance(Key.get(SimpleScope.class, Names.named("requestScope"))); + scope.enter(); + DefinitionScope definitionScope = injector.getInstance(DefinitionScope.class); + definitionScope.enter(new File(".")); + Main.seedInjector(scope, tool, args, new File("."), System.getenv(), System.nanoTime()); + } } diff --git a/kernel/src/test/java/org/kframework/utils/ColorUtilTest.java b/kernel/src/test/java/org/kframework/utils/ColorUtilTest.java index 8e75c06d4ad..371df2b4715 100644 --- a/kernel/src/test/java/org/kframework/utils/ColorUtilTest.java +++ b/kernel/src/test/java/org/kframework/utils/ColorUtilTest.java @@ -1,18 +1,18 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; +import static org.junit.Assert.*; + import org.junit.Test; import org.kframework.unparser.ColorSetting; -import static org.junit.Assert.*; - public class ColorUtilTest { - @Test - public void testGetColor() { - // set java.awt.headless so that we don't activate the awt bug (see issue #982) - System.setProperty("java.awt.headless", "true"); - assertEquals("", ColorUtil.RgbToAnsi("red", ColorSetting.OFF)); - assertEquals("\u001b[31m", ColorUtil.RgbToAnsi("red", ColorSetting.ON)); - } + @Test + public void testGetColor() { + // set java.awt.headless so that we don't activate the awt bug (see issue #982) + System.setProperty("java.awt.headless", "true"); + assertEquals("", ColorUtil.RgbToAnsi("red", ColorSetting.OFF)); + assertEquals("\u001b[31m", ColorUtil.RgbToAnsi("red", ColorSetting.ON)); + } } diff --git a/kernel/src/test/java/org/kframework/utils/IOTestCase.java b/kernel/src/test/java/org/kframework/utils/IOTestCase.java index ce5559e5c95..ad827bd52d2 100644 --- a/kernel/src/test/java/org/kframework/utils/IOTestCase.java +++ b/kernel/src/test/java/org/kframework/utils/IOTestCase.java @@ -3,27 +3,26 @@ import java.io.ByteArrayOutputStream; import java.io.PrintStream; - import org.junit.After; import org.junit.Before; public abstract class IOTestCase extends BaseTestCase { - PrintStream oldOut, oldErr; - protected ByteArrayOutputStream stdout = new ByteArrayOutputStream(); - protected ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + PrintStream oldOut, oldErr; + protected ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + protected ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - @Before - public void setUpIO() { - oldOut = System.out; - oldErr = System.err; - System.setOut(new PrintStream(stdout)); - System.setErr(new PrintStream(stderr)); - } + @Before + public void setUpIO() { + oldOut = System.out; + oldErr = System.err; + System.setOut(new PrintStream(stdout)); + System.setErr(new PrintStream(stderr)); + } - @After - public void tearDownIO() { - System.setOut(oldOut); - System.setErr(oldErr); - } + @After + public void tearDownIO() { + System.setOut(oldOut); + System.setErr(oldErr); + } } diff --git a/kernel/src/test/java/org/kframework/utils/StringUtilTest.java b/kernel/src/test/java/org/kframework/utils/StringUtilTest.java index 7ff9e1ca280..7e5a312049c 100644 --- a/kernel/src/test/java/org/kframework/utils/StringUtilTest.java +++ b/kernel/src/test/java/org/kframework/utils/StringUtilTest.java @@ -1,111 +1,102 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; +import java.util.regex.Pattern; import junit.framework.Assert; import org.junit.Test; import org.kframework.backend.kore.ModuleToKORE; -import java.util.regex.Pattern; - public class StringUtilTest { - @Test - public void StringUtilUnquote() throws Exception { - Assert.assertTrue(StringUtil.unquoteKString("\"\\n\"").equals("\n")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\r\"").equals("\r")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\f\"").equals("\f")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\t\"").equals("\t")); + @Test + public void StringUtilUnquote() throws Exception { + Assert.assertTrue(StringUtil.unquoteKString("\"\\n\"").equals("\n")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\r\"").equals("\r")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\f\"").equals("\f")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\t\"").equals("\t")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\x20\"").equals(" ")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\u0020\"").equals(" ")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\U00000020\"").equals(" ")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\x20\"").equals(" ")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\u0020\"").equals(" ")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\U00000020\"").equals(" ")); - Assert.assertTrue(StringUtil.unquoteKString("\"\\U00000020\"").equals(" ")); + Assert.assertTrue(StringUtil.unquoteKString("\"\\U00000020\"").equals(" ")); - try { - StringUtil.unquoteKString("\"\\U00110000\""); - throw new AssertionError(); - } catch (IllegalArgumentException e) { - } - try { - StringUtil.unquoteKString("\"\\U0000d801\""); - throw new AssertionError(); - } catch (IllegalArgumentException e) { - } + try { + StringUtil.unquoteKString("\"\\U00110000\""); + throw new AssertionError(); + } catch (IllegalArgumentException e) { } - - @Test - public void decodeKoreString() { - Assert.assertEquals("_V_9", StringUtil.decodeKoreString("'Unds'V'Unds'9")); - Assert.assertEquals("?_0", StringUtil.decodeKoreString("'QuesUnds'0")); - Pattern identChar = Pattern.compile("[A-Za-z0-9\\-]"); - StringBuilder buffer = new StringBuilder(); - StringUtil.encodeStringToAlphanumeric(buffer, "?_0", ModuleToKORE.asciiReadableEncodingKore, identChar, "'"); - Assert.assertEquals("'QuesUnds'0", buffer.toString()); - buffer.setLength(0); - StringUtil.encodeStringToAlphanumeric(buffer, "_V_9", ModuleToKORE.asciiReadableEncodingKore, identChar, "'"); - Assert.assertEquals("'Unds'V'Unds'9", buffer.toString()); + try { + StringUtil.unquoteKString("\"\\U0000d801\""); + throw new AssertionError(); + } catch (IllegalArgumentException e) { } + } - @Test - public void testBijection() { - char[] all = new char[256]; - for (int i = 0; i < 256; i++) - all[i] = (char) i; - String str = String.valueOf(all); - String enquoted = StringUtil.enquoteCString(str); - String backToAll = StringUtil.unquoteCString(enquoted); - char[] all2 = backToAll.toCharArray(); + @Test + public void decodeKoreString() { + Assert.assertEquals("_V_9", StringUtil.decodeKoreString("'Unds'V'Unds'9")); + Assert.assertEquals("?_0", StringUtil.decodeKoreString("'QuesUnds'0")); + Pattern identChar = Pattern.compile("[A-Za-z0-9\\-]"); + StringBuilder buffer = new StringBuilder(); + StringUtil.encodeStringToAlphanumeric( + buffer, "?_0", ModuleToKORE.asciiReadableEncodingKore, identChar, "'"); + Assert.assertEquals("'QuesUnds'0", buffer.toString()); + buffer.setLength(0); + StringUtil.encodeStringToAlphanumeric( + buffer, "_V_9", ModuleToKORE.asciiReadableEncodingKore, identChar, "'"); + Assert.assertEquals("'Unds'V'Unds'9", buffer.toString()); + } - Assert.assertEquals("Different sizes after running quote unquote.", all.length , all2.length); - for (int i = 0; i < 256; i++) - Assert.assertEquals("Different values at position: " + i, all[i] , all2[i]); - } + @Test + public void testBijection() { + char[] all = new char[256]; + for (int i = 0; i < 256; i++) all[i] = (char) i; + String str = String.valueOf(all); + String enquoted = StringUtil.enquoteCString(str); + String backToAll = StringUtil.unquoteCString(enquoted); + char[] all2 = backToAll.toCharArray(); - @Test - public void testKBijection() { - char[] all = new char[257]; - for (int i = 0; i < 256; i++) - all[i] = (char) i; - all[256] = 0xffff; - String str = String.valueOf(all); - String enquoted = StringUtil.enquoteKString(str); - String backToAll = StringUtil.unquoteKString(enquoted); - char[] all2 = backToAll.toCharArray(); + Assert.assertEquals("Different sizes after running quote unquote.", all.length, all2.length); + for (int i = 0; i < 256; i++) + Assert.assertEquals("Different values at position: " + i, all[i], all2[i]); + } - Assert.assertEquals("Different sizes after running quote unquote.", all.length , all2.length); - for (int i = 0; i < 257; i++) - Assert.assertEquals("Different values at position: " + i, all[i] , all2[i]); - } + @Test + public void testKBijection() { + char[] all = new char[257]; + for (int i = 0; i < 256; i++) all[i] = (char) i; + all[256] = 0xffff; + String str = String.valueOf(all); + String enquoted = StringUtil.enquoteKString(str); + String backToAll = StringUtil.unquoteKString(enquoted); + char[] all2 = backToAll.toCharArray(); - @Test - public void testSplitLine() { - String longLine = "http://www.kframework.org should be splitted"; - Assert.assertEquals( - "http://www.kframework.org\nshould be\nsplitted", - StringUtil.splitLines(longLine, 10)); - Assert.assertEquals( - "http://www.kframework.org\nshould be splitted", - StringUtil.splitLines(longLine, 20)); - Assert.assertEquals( - "http://www.kframework.org\nshould\nbe\nsplitted", - StringUtil.splitLines(longLine, 0)); - Assert.assertEquals( - "http://www.kframework.org should be\nsplitted", - StringUtil.splitLines(longLine, longLine.length())); - Assert.assertEquals(longLine, StringUtil.splitLines(longLine, longLine.length() + 1)); + Assert.assertEquals("Different sizes after running quote unquote.", all.length, all2.length); + for (int i = 0; i < 257; i++) + Assert.assertEquals("Different values at position: " + i, all[i], all2[i]); + } - String multiLine = - "http://www.kframework.org\nshort enough line"; - Assert.assertEquals( - "http://www.kframework.org\nshort enough line", - StringUtil.splitLines(multiLine, 30)); - Assert.assertEquals( - "http://www.kframework.org\nshort enough\nline", - StringUtil.splitLines(multiLine, 13)); - Assert.assertEquals( - "http://www.kframework.org\nshort\nenough\nline", - StringUtil.splitLines(multiLine, 10)); - } -} + @Test + public void testSplitLine() { + String longLine = "http://www.kframework.org should be splitted"; + Assert.assertEquals( + "http://www.kframework.org\nshould be\nsplitted", StringUtil.splitLines(longLine, 10)); + Assert.assertEquals( + "http://www.kframework.org\nshould be splitted", StringUtil.splitLines(longLine, 20)); + Assert.assertEquals( + "http://www.kframework.org\nshould\nbe\nsplitted", StringUtil.splitLines(longLine, 0)); + Assert.assertEquals( + "http://www.kframework.org should be\nsplitted", + StringUtil.splitLines(longLine, longLine.length())); + Assert.assertEquals(longLine, StringUtil.splitLines(longLine, longLine.length() + 1)); + String multiLine = "http://www.kframework.org\nshort enough line"; + Assert.assertEquals( + "http://www.kframework.org\nshort enough line", StringUtil.splitLines(multiLine, 30)); + Assert.assertEquals( + "http://www.kframework.org\nshort enough\nline", StringUtil.splitLines(multiLine, 13)); + Assert.assertEquals( + "http://www.kframework.org\nshort\nenough\nline", StringUtil.splitLines(multiLine, 10)); + } +} diff --git a/kernel/src/test/java/org/kframework/utils/inject/DefinitionLoadingModuleTest.java b/kernel/src/test/java/org/kframework/utils/inject/DefinitionLoadingModuleTest.java index f4b8235e7d1..3aa712405df 100644 --- a/kernel/src/test/java/org/kframework/utils/inject/DefinitionLoadingModuleTest.java +++ b/kernel/src/test/java/org/kframework/utils/inject/DefinitionLoadingModuleTest.java @@ -1,81 +1,83 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.inject; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import com.beust.jcommander.JCommander; +import java.io.File; +import java.io.IOException; import org.junit.Assert; import org.junit.Test; import org.kframework.utils.errorsystem.KEMException; -import org.kframework.utils.file.FileUtil; import org.kframework.utils.options.DefinitionLoadingOptions; import org.kframework.utils.options.OuterParsingOptions; import org.kframework.utils.options.OutputDirectoryOptions; -import java.io.File; -import java.io.IOException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - public class DefinitionLoadingModuleTest { - @Test - public void testReadDefinition() throws IOException { - DefinitionLoadingOptions options = new DefinitionLoadingOptions(); - new JCommander(options, "--directory", "src/test/resources"); - DefinitionLoadingModule module = new DefinitionLoadingModule(); - File kompiledDir = module.directory(options, new File("."), System.getenv()); - assertEquals(new File("src/test/resources/test-kompiled").getCanonicalFile(), kompiledDir.getCanonicalFile()); - assertTrue(kompiledDir.exists()); - assertTrue(kompiledDir.isDirectory()); - } + @Test + public void testReadDefinition() throws IOException { + DefinitionLoadingOptions options = new DefinitionLoadingOptions(); + new JCommander(options, "--directory", "src/test/resources"); + DefinitionLoadingModule module = new DefinitionLoadingModule(); + File kompiledDir = module.directory(options, new File("."), System.getenv()); + assertEquals( + new File("src/test/resources/test-kompiled").getCanonicalFile(), + kompiledDir.getCanonicalFile()); + assertTrue(kompiledDir.exists()); + assertTrue(kompiledDir.isDirectory()); + } - @Test - public void testReadDefinition2() throws IOException { - DefinitionLoadingOptions options = new DefinitionLoadingOptions(); - new JCommander(options, "--definition", "src/test/resources/test-kompiled"); - DefinitionLoadingModule module = new DefinitionLoadingModule(); - File kompiledDir = module.directory(options, new File("."), System.getenv()); - assertEquals(new File("src/test/resources/test-kompiled").getCanonicalFile(), kompiledDir.getCanonicalFile()); - assertTrue(kompiledDir.exists()); - assertTrue(kompiledDir.isDirectory()); - } + @Test + public void testReadDefinition2() throws IOException { + DefinitionLoadingOptions options = new DefinitionLoadingOptions(); + new JCommander(options, "--definition", "src/test/resources/test-kompiled"); + DefinitionLoadingModule module = new DefinitionLoadingModule(); + File kompiledDir = module.directory(options, new File("."), System.getenv()); + assertEquals( + new File("src/test/resources/test-kompiled").getCanonicalFile(), + kompiledDir.getCanonicalFile()); + assertTrue(kompiledDir.exists()); + assertTrue(kompiledDir.isDirectory()); + } - @Test(expected = KEMException.class) - public void testReadDefinition3() throws KEMException { - DefinitionLoadingOptions options = new DefinitionLoadingOptions(); - new JCommander(options, "--definition", "src/test/resources/fail"); - DefinitionLoadingModule module = new DefinitionLoadingModule(); - File defDir = module.directory(options, new File("."), System.getenv()); - } + @Test(expected = KEMException.class) + public void testReadDefinition3() throws KEMException { + DefinitionLoadingOptions options = new DefinitionLoadingOptions(); + new JCommander(options, "--definition", "src/test/resources/fail"); + DefinitionLoadingModule module = new DefinitionLoadingModule(); + File defDir = module.directory(options, new File("."), System.getenv()); + } - @Test - public void testReadDefinition4() throws KEMException { - DefinitionLoadingOptions options = new DefinitionLoadingOptions(); - new JCommander(options, "--definition", "src/test/resources/kmp"); - DefinitionLoadingModule module = new DefinitionLoadingModule(); - File defDir = module.directory(options, new File("."), System.getenv()); - Assert.assertEquals(new File("./src/test/resources/kmp"), defDir); - } + @Test + public void testReadDefinition4() throws KEMException { + DefinitionLoadingOptions options = new DefinitionLoadingOptions(); + new JCommander(options, "--definition", "src/test/resources/kmp"); + DefinitionLoadingModule module = new DefinitionLoadingModule(); + File defDir = module.directory(options, new File("."), System.getenv()); + Assert.assertEquals(new File("./src/test/resources/kmp"), defDir); + } - @Test - public void testSaveDefinition() throws KEMException { - OutputDirectoryOptions options = new OutputDirectoryOptions(); - OuterParsingOptions outer = new OuterParsingOptions(); - new JCommander(options, "-o", "src/test/resources/kmp"); - OuterParsingModule module = new OuterParsingModule(); - File kmp = module.kompiledDir(outer, new File("."), options); + @Test + public void testSaveDefinition() throws KEMException { + OutputDirectoryOptions options = new OutputDirectoryOptions(); + OuterParsingOptions outer = new OuterParsingOptions(); + new JCommander(options, "-o", "src/test/resources/kmp"); + OuterParsingModule module = new OuterParsingModule(); + File kmp = module.kompiledDir(outer, new File("."), options); - Assert.assertEquals(new File("./src/test/resources/kmp"), kmp); - } + Assert.assertEquals(new File("./src/test/resources/kmp"), kmp); + } - @Test - public void testSaveDefinition2() throws KEMException { - OutputDirectoryOptions options = new OutputDirectoryOptions(); - OuterParsingOptions outer = new OuterParsingOptions(); - new JCommander(options, "-o", "src/test/resources/newkmp"); - OuterParsingModule module = new OuterParsingModule(); - File kmp = module.kompiledDir(outer, new File("."), options); + @Test + public void testSaveDefinition2() throws KEMException { + OutputDirectoryOptions options = new OutputDirectoryOptions(); + OuterParsingOptions outer = new OuterParsingOptions(); + new JCommander(options, "-o", "src/test/resources/newkmp"); + OuterParsingModule module = new OuterParsingModule(); + File kmp = module.kompiledDir(outer, new File("."), options); - Assert.assertEquals(new File("./src/test/resources/newkmp"), kmp); - } + Assert.assertEquals(new File("./src/test/resources/newkmp"), kmp); + } } diff --git a/kore/src/main/java/org/kframework/API.java b/kore/src/main/java/org/kframework/API.java index 77d3b544c16..7500aa32162 100644 --- a/kore/src/main/java/org/kframework/API.java +++ b/kore/src/main/java/org/kframework/API.java @@ -5,10 +5,8 @@ import java.lang.annotation.Target; /** - * Marker for classes we consider as part fo the K API. - * It is particularly important for these classes to be well-documented. + * Marker for classes we consider as part fo the K API. It is particularly important for these + * classes to be well-documented. */ @Target(ElementType.TYPE) -public @interface API { - -} +public @interface API {} diff --git a/kore/src/main/java/org/kframework/List.java b/kore/src/main/java/org/kframework/List.java index 025ba8b0176..658b6ea5af0 100644 --- a/kore/src/main/java/org/kframework/List.java +++ b/kore/src/main/java/org/kframework/List.java @@ -5,29 +5,29 @@ import java.util.Iterator; public class List implements Iterable, Serializable { - private final scala.collection.immutable.List list; + private final scala.collection.immutable.List list; - public List(scala.collection.immutable.List l) { - this.list = l; - } + public List(scala.collection.immutable.List l) { + this.list = l; + } - @Override - public Iterator iterator() { - return new Iterator() { + @Override + public Iterator iterator() { + return new Iterator() { - private scala.collection.immutable.List l = list; + private scala.collection.immutable.List l = list; - @Override - public boolean hasNext() { - return !l.isEmpty(); - } + @Override + public boolean hasNext() { + return !l.isEmpty(); + } - @Override - public T next() { - T head = l.head(); - l = (scala.collection.immutable.List) l.tail(); - return head; - } - }; - } + @Override + public T next() { + T head = l.head(); + l = (scala.collection.immutable.List) l.tail(); + return head; + } + }; + } } diff --git a/kore/src/main/java/org/kframework/Warning.java b/kore/src/main/java/org/kframework/Warning.java index 7840e88b20e..6f7182c6f7e 100644 --- a/kore/src/main/java/org/kframework/Warning.java +++ b/kore/src/main/java/org/kframework/Warning.java @@ -2,6 +2,4 @@ package org.kframework; @API -public interface Warning { - -} +public interface Warning {} diff --git a/kore/src/main/java/org/kframework/attributes/HasLocation.java b/kore/src/main/java/org/kframework/attributes/HasLocation.java index 2d4ba63220e..43aaff44b69 100644 --- a/kore/src/main/java/org/kframework/attributes/HasLocation.java +++ b/kore/src/main/java/org/kframework/attributes/HasLocation.java @@ -4,6 +4,7 @@ import java.util.Optional; public interface HasLocation { - Optional location(); - Optional source(); + Optional location(); + + Optional source(); } diff --git a/kore/src/main/java/org/kframework/builtin/BooleanUtils.java b/kore/src/main/java/org/kframework/builtin/BooleanUtils.java index 045c2fba1a9..6ff16e5bf21 100644 --- a/kore/src/main/java/org/kframework/builtin/BooleanUtils.java +++ b/kore/src/main/java/org/kframework/builtin/BooleanUtils.java @@ -1,25 +1,25 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.builtin; -import org.kframework.kore.K; -import org.kframework.kore.KApply; -import org.kframework.kore.KToken; - import static org.kframework.kore.KORE.KApply; import static org.kframework.kore.KORE.KLabel; import static org.kframework.kore.KORE.KToken; -import static org.kframework.kore.KORE.Sort; -/** - * Created by dwightguth on 4/17/15. - */ +import org.kframework.kore.K; +import org.kframework.kore.KApply; +import org.kframework.kore.KToken; + +/** Created by dwightguth on 4/17/15. */ public class BooleanUtils { - public static KApply and(K k1, K k2) { - return KApply (KLabel("_andBool_"), k1, k2); - } - public static KApply not(K k) { return KApply(KLabel("notBool_"), k); } + public static KApply and(K k1, K k2) { + return KApply(KLabel("_andBool_"), k1, k2); + } + + public static KApply not(K k) { + return KApply(KLabel("notBool_"), k); + } - public static final KToken TRUE = KToken("true", Sorts.Bool()); - public static final KToken FALSE = KToken("false", Sorts.Bool()); + public static final KToken TRUE = KToken("true", Sorts.Bool()); + public static final KToken FALSE = KToken("false", Sorts.Bool()); } diff --git a/kore/src/main/java/org/kframework/builtin/Hooks.java b/kore/src/main/java/org/kframework/builtin/Hooks.java index 62fe8062c7d..b93641db1f2 100644 --- a/kore/src/main/java/org/kframework/builtin/Hooks.java +++ b/kore/src/main/java/org/kframework/builtin/Hooks.java @@ -2,31 +2,53 @@ package org.kframework.builtin; +import java.util.Arrays; import java.util.Collections; -import java.util.Set; import java.util.HashSet; -import java.util.Arrays; +import java.util.Set; public class Hooks { - public static final String ARRAY = "ARRAY"; - public static final String BOOL = "BOOL"; - public static final String BUFFER = "BUFFER"; - public static final String BYTES = "BYTES"; - public static final String FFI = "FFI"; - public static final String FLOAT = "FLOAT"; - public static final String INT = "INT"; - public static final String IO = "IO"; - public static final String KEQUAL = "KEQUAL"; - public static final String KREFLECTION = "KREFLECTION"; - public static final String LIST = "LIST"; - public static final String MAP = "MAP"; - public static final String RANGEMAP = "RANGEMAP"; - public static final String MINT = "MINT"; - public static final String SET = "SET"; - public static final String STRING = "STRING"; - public static final String SUBSTITUTION = "SUBSTITUTION"; - public static final String UNIFICATION = "UNIFICATION"; - public static final String JSON = "JSON"; + public static final String ARRAY = "ARRAY"; + public static final String BOOL = "BOOL"; + public static final String BUFFER = "BUFFER"; + public static final String BYTES = "BYTES"; + public static final String FFI = "FFI"; + public static final String FLOAT = "FLOAT"; + public static final String INT = "INT"; + public static final String IO = "IO"; + public static final String KEQUAL = "KEQUAL"; + public static final String KREFLECTION = "KREFLECTION"; + public static final String LIST = "LIST"; + public static final String MAP = "MAP"; + public static final String RANGEMAP = "RANGEMAP"; + public static final String MINT = "MINT"; + public static final String SET = "SET"; + public static final String STRING = "STRING"; + public static final String SUBSTITUTION = "SUBSTITUTION"; + public static final String UNIFICATION = "UNIFICATION"; + public static final String JSON = "JSON"; - public static final Set namespaces = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(ARRAY, BOOL, BUFFER, BYTES, FFI, FLOAT, INT, IO, KEQUAL, KREFLECTION, LIST, MAP, RANGEMAP, MINT, SET, STRING, SUBSTITUTION, UNIFICATION, JSON))); + public static final Set namespaces = + Collections.unmodifiableSet( + new HashSet<>( + Arrays.asList( + ARRAY, + BOOL, + BUFFER, + BYTES, + FFI, + FLOAT, + INT, + IO, + KEQUAL, + KREFLECTION, + LIST, + MAP, + RANGEMAP, + MINT, + SET, + STRING, + SUBSTITUTION, + UNIFICATION, + JSON))); } diff --git a/kore/src/main/java/org/kframework/builtin/KLabels.java b/kore/src/main/java/org/kframework/builtin/KLabels.java index 7c985f2d322..9fd44d1d5ec 100644 --- a/kore/src/main/java/org/kframework/builtin/KLabels.java +++ b/kore/src/main/java/org/kframework/builtin/KLabels.java @@ -2,79 +2,79 @@ package org.kframework.builtin; -import org.kframework.kore.KLabel; - import static org.kframework.kore.KORE.KLabel; +import org.kframework.kore.KLabel; + public class KLabels { - public static final KLabel AND = KLabel("_andBool_"); - public static final KLabel OR = KLabel("_orBool_"); + public static final KLabel AND = KLabel("_andBool_"); + public static final KLabel OR = KLabel("_orBool_"); - public static final KLabel KSEQ = KLabel("#KSequence"); - public static final KLabel DOTK = KLabel("#EmptyK"); + public static final KLabel KSEQ = KLabel("#KSequence"); + public static final KLabel DOTK = KLabel("#EmptyK"); - public static final KLabel CELLS = KLabel("#cells"); + public static final KLabel CELLS = KLabel("#cells"); - public static final KLabel DOTS = KLabel("#dots"); - public static final KLabel NO_DOTS = KLabel("#noDots"); + public static final KLabel DOTS = KLabel("#dots"); + public static final KLabel NO_DOTS = KLabel("#noDots"); - public static final KLabel KREWRITE = KLabel("#KRewrite"); - public static final KLabel KLIST = KLabel("#KList"); - public static final KLabel EMPTYKLIST = KLabel("#EmptyKList"); - public static final KLabel KAPP = KLabel("#KApply"); + public static final KLabel KREWRITE = KLabel("#KRewrite"); + public static final KLabel KLIST = KLabel("#KList"); + public static final KLabel EMPTYKLIST = KLabel("#EmptyKList"); + public static final KLabel KAPP = KLabel("#KApply"); - public static final String GENERATED_TOP_CELL_NAME = "generatedTop"; - public static final KLabel GENERATED_TOP_CELL = KLabel(""); - public static final String GENERATED_COUNTER_CELL_NAME = "generatedCounter"; - public static final KLabel GENERATED_COUNTER_CELL = KLabel(""); - public static final KLabel INIT_GENERATED_TOP_CELL = KLabel("initGeneratedTopCell"); - public static final KLabel INIT_GENERATED_COUNTER_CELL = KLabel("initGeneratedCounterCell"); - public static final String THIS_CONFIGURATION = "THIS_CONFIGURATION"; + public static final String GENERATED_TOP_CELL_NAME = "generatedTop"; + public static final KLabel GENERATED_TOP_CELL = KLabel(""); + public static final String GENERATED_COUNTER_CELL_NAME = "generatedCounter"; + public static final KLabel GENERATED_COUNTER_CELL = KLabel(""); + public static final KLabel INIT_GENERATED_TOP_CELL = KLabel("initGeneratedTopCell"); + public static final KLabel INIT_GENERATED_COUNTER_CELL = KLabel("initGeneratedCounterCell"); + public static final String THIS_CONFIGURATION = "THIS_CONFIGURATION"; - public static final String STRATEGY_CELL_NAME = "s"; - public static final KLabel STRATEGY_CELL = KLabel(""); - public static final KLabel STUCK = KLabel("#STUCK"); + public static final String STRATEGY_CELL_NAME = "s"; + public static final KLabel STRATEGY_CELL = KLabel(""); + public static final KLabel STUCK = KLabel("#STUCK"); - public static final KLabel ML_FALSE = KLabel("#Bottom"); - public static final KLabel ML_TRUE = KLabel("#Top"); - public static final KLabel ML_OR = KLabel("#Or"); - public static final KLabel ML_AND = KLabel("#And"); - public static final KLabel ML_NOT = KLabel("#Not"); - public static final KLabel ML_CEIL = KLabel("#Ceil"); - public static final KLabel ML_FLOOR = KLabel("#Floor"); - public static final KLabel ML_EQUALS = KLabel("#Equals"); - public static final KLabel ML_IMPLIES = KLabel("#Implies"); - public static final KLabel ML_EXISTS = KLabel("#Exists"); - public static final KLabel ML_FORALL = KLabel("#Forall"); - public static final KLabel CTL_AG = KLabel("#AG"); - public static final KLabel RL_wEF = KLabel("weakExistsFinally"); - public static final KLabel RL_wAF = KLabel("weakAlwaysFinally"); + public static final KLabel ML_FALSE = KLabel("#Bottom"); + public static final KLabel ML_TRUE = KLabel("#Top"); + public static final KLabel ML_OR = KLabel("#Or"); + public static final KLabel ML_AND = KLabel("#And"); + public static final KLabel ML_NOT = KLabel("#Not"); + public static final KLabel ML_CEIL = KLabel("#Ceil"); + public static final KLabel ML_FLOOR = KLabel("#Floor"); + public static final KLabel ML_EQUALS = KLabel("#Equals"); + public static final KLabel ML_IMPLIES = KLabel("#Implies"); + public static final KLabel ML_EXISTS = KLabel("#Exists"); + public static final KLabel ML_FORALL = KLabel("#Forall"); + public static final KLabel CTL_AG = KLabel("#AG"); + public static final KLabel RL_wEF = KLabel("weakExistsFinally"); + public static final KLabel RL_wAF = KLabel("weakAlwaysFinally"); - public static final KLabel ListItem = KLabel("ListItem"); - public static final KLabel List = KLabel("_List_"); - public static final KLabel DotList = KLabel(".List"); - public static final KLabel MapItem = KLabel("_|->_"); - public static final KLabel Map = KLabel("_Map_"); - public static final KLabel DotMap = KLabel(".Map"); - public static final KLabel SetItem = KLabel("SetItem"); - public static final KLabel Set = KLabel("_Set_"); - public static final KLabel DotSet = KLabel(".Set"); + public static final KLabel ListItem = KLabel("ListItem"); + public static final KLabel List = KLabel("_List_"); + public static final KLabel DotList = KLabel(".List"); + public static final KLabel MapItem = KLabel("_|->_"); + public static final KLabel Map = KLabel("_Map_"); + public static final KLabel DotMap = KLabel(".Map"); + public static final KLabel SetItem = KLabel("SetItem"); + public static final KLabel Set = KLabel("_Set_"); + public static final KLabel DotSet = KLabel(".Set"); - public static final KLabel EQUALS_K = KLabel("_==K_"); - public static final KLabel NOT_EQUALS_K = KLabel("_=/=K_"); - public static final KLabel IN_K = KLabel("_:=K_"); - public static final KLabel NOT_IN_K = KLabel("_:/=K_"); + public static final KLabel EQUALS_K = KLabel("_==K_"); + public static final KLabel NOT_EQUALS_K = KLabel("_=/=K_"); + public static final KLabel IN_K = KLabel("_:=K_"); + public static final KLabel NOT_IN_K = KLabel("_:/=K_"); - public static final KLabel MAP_CHOICE = KLabel("Map:choice"); - public static final KLabel SET_CHOICE = KLabel("Set:choice"); - public static final KLabel LIST_GET = KLabel("List:get"); - public static final KLabel MAP_LOOKUP = KLabel("Map:lookup"); - public static final KLabel SET_MEMBERSHIP = KLabel("Set:in"); - public static final KLabel LIST_RANGE = KLabel("List:range"); - public static final KLabel MAP_UPDATE = KLabel("updateMap"); - public static final KLabel MAP_REMOVE_ALL = KLabel("removeAll"); - public static final KLabel SET_REMOVE_ALL = KLabel("Set:difference"); - public static final KLabel MAP_KEYS = KLabel("keys"); + public static final KLabel MAP_CHOICE = KLabel("Map:choice"); + public static final KLabel SET_CHOICE = KLabel("Set:choice"); + public static final KLabel LIST_GET = KLabel("List:get"); + public static final KLabel MAP_LOOKUP = KLabel("Map:lookup"); + public static final KLabel SET_MEMBERSHIP = KLabel("Set:in"); + public static final KLabel LIST_RANGE = KLabel("List:range"); + public static final KLabel MAP_UPDATE = KLabel("updateMap"); + public static final KLabel MAP_REMOVE_ALL = KLabel("removeAll"); + public static final KLabel SET_REMOVE_ALL = KLabel("Set:difference"); + public static final KLabel MAP_KEYS = KLabel("keys"); - public static final String INJ = "inj"; + public static final String INJ = "inj"; } diff --git a/kore/src/main/java/org/kframework/builtin/Rules.java b/kore/src/main/java/org/kframework/builtin/Rules.java index 07910ed34f6..3551db4b2e7 100644 --- a/kore/src/main/java/org/kframework/builtin/Rules.java +++ b/kore/src/main/java/org/kframework/builtin/Rules.java @@ -1,12 +1,20 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.builtin; -import org.kframework.kore.KRewrite; import static org.kframework.kore.KORE.*; +import org.kframework.kore.KRewrite; + public class Rules { - public static final KRewrite STUCK_RULE = KRewrite( - KApply(KLabels.STRATEGY_CELL, KList(KApply(KLabels.KSEQ, KList(KApply(KLabels.DOTK, KList()), KVariable("#REST"))))) - , KApply(KLabels.STRATEGY_CELL, KList(KApply(KLabels.KSEQ, KList(KApply(KLabels.STUCK, KList()), KVariable("#REST"))))) - ); + public static final KRewrite STUCK_RULE = + KRewrite( + KApply( + KLabels.STRATEGY_CELL, + KList( + KApply(KLabels.KSEQ, KList(KApply(KLabels.DOTK, KList()), KVariable("#REST"))))), + KApply( + KLabels.STRATEGY_CELL, + KList( + KApply( + KLabels.KSEQ, KList(KApply(KLabels.STUCK, KList()), KVariable("#REST")))))); } diff --git a/kore/src/main/java/org/kframework/compile/ConfigurationInfo.java b/kore/src/main/java/org/kframework/compile/ConfigurationInfo.java index f0d7e16df0c..6bc2ad93ece 100644 --- a/kore/src/main/java/org/kframework/compile/ConfigurationInfo.java +++ b/kore/src/main/java/org/kframework/compile/ConfigurationInfo.java @@ -1,116 +1,114 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import java.util.List; +import java.util.Set; import org.kframework.kore.KApply; import org.kframework.kore.KLabel; import org.kframework.kore.Sort; import scala.Option; -import java.util.List; -import java.util.Set; - /** - * Information about the configuration structure used - * in the configuration concretiziation passes. - * Cells are identified by the sort containing the production - * for the cell (this is more convenient when dealing also - * with variables or functions of cell sort). + * Information about the configuration structure used in the configuration concretiziation passes. + * Cells are identified by the sort containing the production for the cell (this is more convenient + * when dealing also with variables or functions of cell sort). */ public interface ConfigurationInfo { - /** Number of proper ancestors of cell k */ - int getLevel(Sort k); + /** Number of proper ancestors of cell k */ + int getLevel(Sort k); + + /** Parent of cell k, or null */ + Sort getParent(Sort k); + + /** Children of cell k */ + List getChildren(Sort k); - /** Parent of cell k, or null */ - Sort getParent(Sort k); + /** Declared multiplicity of a cell */ + Multiplicity getMultiplicity(Sort k); - /** Children of cell k */ - List getChildren(Sort k); + /** True if sort k is actually a cell sort */ + boolean isCell(Sort k); - /** Declared multiplicity of a cell */ - Multiplicity getMultiplicity(Sort k); + /** True if sort s is the collection sort for a multiplicity star cell. */ + boolean isCellCollection(Sort s); - /** True if sort k is actually a cell sort */ - boolean isCell(Sort k); + /** True if kLabel is the KLabel of a cell */ + boolean isCellLabel(KLabel kLabel); - /** True if sort s is the collection sort for a multiplicity star cell. */ - boolean isCellCollection(Sort s); + /** True for cells which contain a term rather than other cells */ + boolean isLeafCell(Sort k); - /** True if kLabel is the KLabel of a cell */ - boolean isCellLabel(KLabel kLabel); + /** True for cells which contain other cells */ + boolean isParentCell(Sort k); - /** True for cells which contain a term rather than other cells */ - boolean isLeafCell(Sort k); + /** + * Set of cell bag sorts (e.g. ThreadCellBag) associated with a multiplicity * cell (e.g. + * ThreadCell). Should not in most cases return more than one sort, but a user can write + * productions that would cause this method to return multiple sorts, e.g. if a particular * cell + * appears in multiple bags in different parts of a configuration. + */ + scala.collection.Set getCellBagSortsOfCell(Sort k); - /** True for cells which contain other cells */ - boolean isParentCell(Sort k); + /** The declared sort of the contents of a leaf cell */ + Sort leafCellType(Sort k); - /** Set of cell bag sorts (e.g. ThreadCellBag) associated with a multiplicity * cell (e.g. ThreadCell). - * Should not in most cases return more than one sort, but a user can write productions that would cause - * this method to return multiple sorts, e.g. if a particular * cell appears in multiple bags in different - * parts of a configuration. - */ - scala.collection.Set getCellBagSortsOfCell(Sort k); + /** The label for a cell */ + KLabel getCellLabel(Sort k); - /** The declared sort of the contents of a leaf cell */ - Sort leafCellType(Sort k); + /** The cell for a label */ + Sort getCellSort(KLabel kLabel); - /** The label for a cell */ - KLabel getCellLabel(Sort k); + /** The label for a fragment of a cell, only defined for parent cells. */ + KLabel getCellFragmentLabel(Sort k); - /** The cell for a label */ - Sort getCellSort(KLabel kLabel); + /** + * The constant label to use as an argument of a cell fragment, when the cell fragment did not + * capture cells of the argument type. Only defined for child cells of multiplicity other than *. + */ + KLabel getCellAbsentLabel(Sort cellSort); - /** The label for a fragment of a cell, only defined for parent cells. */ - KLabel getCellFragmentLabel(Sort k); + /** Returns a term which is the default cell of sort k, probably an initializer macro */ + KApply getDefaultCell(Sort k); - /** - * The constant label to use as an argument of a cell fragment, - * when the cell fragment did not capture cells of the argument type. - * Only defined for child cells of multiplicity other than *. - */ - KLabel getCellAbsentLabel(Sort cellSort); + boolean isConstantInitializer(Sort k); - /** Returns a term which is the default cell of sort k, - * probably an initializer macro */ - KApply getDefaultCell(Sort k); + /** Return the root cell of the configuration . */ + Sort getRootCell(); - boolean isConstantInitializer(Sort k); + /** Return the declared computation cell, by default the k cell */ + Sort getComputationCell(); - /** Return the root cell of the configuration . */ - Sort getRootCell(); - /** Return the declared computation cell, by default the k cell */ - Sort getComputationCell(); - /** Returns the set of cell sorts in this configuration */ - Set getCellSorts(); + /** Returns the set of cell sorts in this configuration */ + Set getCellSorts(); - /** Returns the unit of a * or ? cell. */ - KApply getUnit(Sort k); + /** Returns the unit of a * or ? cell. */ + KApply getUnit(Sort k); - /** Returns the concatenation operation of a multiplicity * cell. */ - KLabel getConcat(Sort k); + /** Returns the concatenation operation of a multiplicity * cell. */ + KLabel getConcat(Sort k); - /** Returns the cell associated with this concatenation label */ - Option getCellForConcat(KLabel concat); + /** Returns the cell associated with this concatenation label */ + Option getCellForConcat(KLabel concat); - /** Returns the cell associated with this unit */ - Option getCellForUnit(KLabel unit); + /** Returns the cell associated with this unit */ + Option getCellForUnit(KLabel unit); - /** Declared mulitplicitly of a cell */ - enum Multiplicity { - /** Exactly one instance of this cell is required */ - ONE, - /** This cell is optional but may not be repeated */ - OPTIONAL, - /** This cell may occur any number of times, zero or more */ - STAR; + /** Declared mulitplicitly of a cell */ + enum Multiplicity { + /** Exactly one instance of this cell is required */ + ONE, + /** This cell is optional but may not be repeated */ + OPTIONAL, + /** This cell may occur any number of times, zero or more */ + STAR; - public static Multiplicity of(String multiplicity) { - return switch (multiplicity) { - case "1" -> Multiplicity.ONE; - case "*" -> Multiplicity.STAR; - case "?" -> Multiplicity.OPTIONAL; - default -> throw new IllegalArgumentException(multiplicity); - }; - } + public static Multiplicity of(String multiplicity) { + return switch (multiplicity) { + case "1" -> Multiplicity.ONE; + case "*" -> Multiplicity.STAR; + case "?" -> Multiplicity.OPTIONAL; + default -> throw new IllegalArgumentException(multiplicity); + }; } + } } diff --git a/kore/src/main/java/org/kframework/compile/LabelInfo.java b/kore/src/main/java/org/kframework/compile/LabelInfo.java index bb747d4a021..4f0b64c6602 100644 --- a/kore/src/main/java/org/kframework/compile/LabelInfo.java +++ b/kore/src/main/java/org/kframework/compile/LabelInfo.java @@ -1,9 +1,16 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.compile; +import static org.kframework.kore.KORE.*; + import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import org.kframework.definition.Production; import org.kframework.kore.K; import org.kframework.kore.KApply; @@ -11,103 +18,95 @@ import org.kframework.kore.KRewrite; import org.kframework.kore.Sort; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import static org.kframework.kore.KORE.*; - -/** - * Basic label information for cell completion - */ +/** Basic label information for cell completion */ public class LabelInfo { - private final Multimap codomain = HashMultimap.create(); - - private final Map assocInfo = new HashMap<>(); - - private final Set functionLabels = new HashSet<>(); - - private final Map productions = new HashMap<>(); - - protected void addLabel(Sort result, String label) { - addLabel(result, label, false); + private final Multimap codomain = HashMultimap.create(); + + private final Map assocInfo = new HashMap<>(); + + private final Set functionLabels = new HashSet<>(); + + private final Map productions = new HashMap<>(); + + protected void addLabel(Sort result, String label) { + addLabel(result, label, false); + } + + protected void addLabel(Sort result, String label, boolean isAssoc) { + addLabel(result, label, isAssoc, false, false); + } + + protected void addLabel( + Sort result, String label, boolean isAssoc, boolean isComm, boolean isFunction) { + addLabel(result, label, isAssoc, isComm, isFunction, null); + } + + protected void addLabel( + Sort result, + String label, + boolean isAssoc, + boolean isComm, + boolean isFunction, + Production prod) { + KLabel kLabel = KLabel(label); + codomain.put(kLabel, result); + AssocInfo info = new AssocInfo(isAssoc, isComm); + if (assocInfo.containsKey(kLabel)) { + assert assocInfo.get(kLabel).equals(info); + } else { + assocInfo.put(kLabel, new AssocInfo(isAssoc, isComm)); } - - protected void addLabel(Sort result, String label, boolean isAssoc) { - addLabel(result, label, isAssoc, false, false); + if (isFunction) { + functionLabels.add(kLabel); } + productions.put(label, prod); + } - protected void addLabel(Sort result, String label, boolean isAssoc, boolean isComm, boolean isFunction) { - addLabel(result, label, isAssoc, isComm, isFunction, null); - } + public LabelInfo() {} - protected void addLabel(Sort result, String label, boolean isAssoc, boolean isComm, boolean isFunction, Production prod) { - KLabel kLabel = KLabel(label); - codomain.put(kLabel, result); - AssocInfo info = new AssocInfo(isAssoc, isComm); - if (assocInfo.containsKey(kLabel)) { - assert assocInfo.get(kLabel).equals(info); - } else { - assocInfo.put(kLabel, new AssocInfo(isAssoc, isComm)); - } - if (isFunction) { - functionLabels.add(kLabel); - } - productions.put(label, prod); - } + /** Get the sort for the KLabel. Could be moved to module eventually. */ + public Sort getCodomain(KLabel l) { + Collection sorts = codomain.get(l); + return Iterables.getOnlyElement(sorts, null); + } - public LabelInfo() { - } + public boolean isFunction(KLabel l) { + return functionLabels.contains(l); + } - /** - * Get the sort for the KLabel. Could be moved to module eventually. - */ - public Sort getCodomain(KLabel l) { - Collection sorts = codomain.get(l); - return Iterables.getOnlyElement(sorts, null); + public boolean isFunction(K term) { + if (term instanceof KApply && isFunction(((KApply) term).klabel())) { + return true; } - - public boolean isFunction(KLabel l) { - return functionLabels.contains(l); + return term instanceof KRewrite + && ((KRewrite) term).left() instanceof KApply + && isFunction(((KApply) ((KRewrite) term).left()).klabel()); + } + + /** Get the AC status of the KLabel. Could be moved to module eventually. */ + public AssocInfo getAssocInfo(KLabel l) { + return assocInfo.get(l); + } + + public static class AssocInfo { + public AssocInfo(boolean isAssoc, boolean isComm) { + this.isAssoc = isAssoc; + this.isComm = isComm; } - public boolean isFunction(K term) { - if (term instanceof KApply && isFunction(((KApply) term).klabel())) { - return true; - } - return term instanceof KRewrite && ((KRewrite) term).left() instanceof KApply - && isFunction(((KApply) ((KRewrite) term).left()).klabel()); - } + private final boolean isAssoc; + private final boolean isComm; - /** - * Get the AC status of the KLabel. Could be moved to module eventually. - */ - public AssocInfo getAssocInfo(KLabel l) { - return assocInfo.get(l); + public boolean isAssoc() { + return isAssoc; } - public static class AssocInfo { - public AssocInfo(boolean isAssoc, boolean isComm) { - this.isAssoc = isAssoc; - this.isComm = isComm; - } - - private final boolean isAssoc; - private final boolean isComm; - - public boolean isAssoc() { - return isAssoc; - } - - public boolean isComm() { - return isComm; - } + public boolean isComm() { + return isComm; } + } - public Production getProduction(String label) { - return productions.get(label); - } + public Production getProduction(String label) { + return productions.get(label); + } } diff --git a/kore/src/main/java/org/kframework/definition/Associativity.java b/kore/src/main/java/org/kframework/definition/Associativity.java index 759dec74580..e0bf5840376 100644 --- a/kore/src/main/java/org/kframework/definition/Associativity.java +++ b/kore/src/main/java/org/kframework/definition/Associativity.java @@ -2,5 +2,8 @@ package org.kframework.definition; public enum Associativity { - Left, Right, NonAssoc, Unspecified + Left, + Right, + NonAssoc, + Unspecified } diff --git a/kore/src/main/java/org/kframework/definition/UserList.java b/kore/src/main/java/org/kframework/definition/UserList.java index e10e37bb19b..24d104353fc 100644 --- a/kore/src/main/java/org/kframework/definition/UserList.java +++ b/kore/src/main/java/org/kframework/definition/UserList.java @@ -1,81 +1,83 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.definition; -import org.kframework.Collections; -import org.kframework.attributes.Att; -import org.kframework.kore.KLabel; -import org.kframework.kore.Sort; - import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import org.kframework.Collections; +import org.kframework.attributes.Att; +import org.kframework.kore.KLabel; +import org.kframework.kore.Sort; -/** - * Class to hold easy to access information about user defined lists. - */ +/** Class to hold easy to access information about user defined lists. */ public class UserList { - public Sort sort = null; - public Sort childSort = null; - public String separator = null; - public KLabel terminatorKLabel = null; - public KLabel klabel = null; - public boolean nonEmpty = false; - public boolean leftAssoc = false; - public Production pList = null, pTerminator = null; - public org.kframework.attributes.Att attrs = null; + public Sort sort = null; + public Sort childSort = null; + public String separator = null; + public KLabel terminatorKLabel = null; + public KLabel klabel = null; + public boolean nonEmpty = false; + public boolean leftAssoc = false; + public Production pList = null, pTerminator = null; + public org.kframework.attributes.Att attrs = null; - public static scala.collection.Set apply(scala.collection.Set sentences) { - return Collections.immutable(getLists(Collections.mutable(sentences))).toSet(); - } + public static scala.collection.Set apply(scala.collection.Set sentences) { + return Collections.immutable(getLists(Collections.mutable(sentences))).toSet(); + } - // find all productions annotated with 'userList' - // expecting to always find 2 of them of the form: - // Es ::= E "," Es [right, userList, klabel(...)] - // Es ::= ".Es" [userList, klabel(...)] - public static java.util.List getLists(Set sentences) { - Map> separatedProds - = sentences.stream().collect(Collectors.groupingBy(p -> p instanceof Production && p.att().contains(Att.USER_LIST()))); - Map> listsMap = separatedProds.getOrDefault(true, new LinkedList<>()) - .stream().collect(Collectors.groupingBy(s -> ((Production) s).sort())); + // find all productions annotated with 'userList' + // expecting to always find 2 of them of the form: + // Es ::= E "," Es [right, userList, klabel(...)] + // Es ::= ".Es" [userList, klabel(...)] + public static java.util.List getLists(Set sentences) { + Map> separatedProds = + sentences.stream() + .collect( + Collectors.groupingBy( + p -> p instanceof Production && p.att().contains(Att.USER_LIST()))); + Map> listsMap = + separatedProds.getOrDefault(true, new LinkedList<>()).stream() + .collect(Collectors.groupingBy(s -> ((Production) s).sort())); - java.util.List res = new ArrayList<>(); - for (Map.Entry> x : listsMap.entrySet()) { - UserList ul = new UserList(); - ul.sort = x.getKey(); - assert x.getValue().size() == 2; - for (Sentence s : x.getValue()) { - Production p = (Production) s; - if (p.items().size() == 3) { - Terminal t = (Terminal) p.items().tail().head(); - ul.separator = t.value(); - ul.klabel = p.klabel().get(); - ul.attrs = p.att().remove(Att.KLABEL()); - // should work without the Att.userList() att, i.e. for any list -- see #1892 - ul.nonEmpty = ul.attrs.get(Att.USER_LIST()).equals("+"); - if (!((NonTerminal)p.items().tail().tail().head()).sort().equals(p.sort())) { - ul.leftAssoc = true; - } - if (ul.leftAssoc) { - ul.childSort = ((NonTerminal) p.items().tail().tail().head()).sort(); - } else { - ul.childSort = ((NonTerminal) p.items().head()).sort(); - } - ul.pList = p; - } else if (p.items().size() == 1 && p.items().head() instanceof Terminal) { - ul.terminatorKLabel = p.klabel().get(); - ul.pTerminator = p; - } else - throw new AssertionError("Didn't expect this type of production when recognizing userList patterns!"); - } - assert ul.attrs != null; - assert ul.klabel != null; - assert ul.terminatorKLabel != null; - assert ul.childSort != null; - res.add(ul); - } - return res; + java.util.List res = new ArrayList<>(); + for (Map.Entry> x : listsMap.entrySet()) { + UserList ul = new UserList(); + ul.sort = x.getKey(); + assert x.getValue().size() == 2; + for (Sentence s : x.getValue()) { + Production p = (Production) s; + if (p.items().size() == 3) { + Terminal t = (Terminal) p.items().tail().head(); + ul.separator = t.value(); + ul.klabel = p.klabel().get(); + ul.attrs = p.att().remove(Att.KLABEL()); + // should work without the Att.userList() att, i.e. for any list -- see #1892 + ul.nonEmpty = ul.attrs.get(Att.USER_LIST()).equals("+"); + if (!((NonTerminal) p.items().tail().tail().head()).sort().equals(p.sort())) { + ul.leftAssoc = true; + } + if (ul.leftAssoc) { + ul.childSort = ((NonTerminal) p.items().tail().tail().head()).sort(); + } else { + ul.childSort = ((NonTerminal) p.items().head()).sort(); + } + ul.pList = p; + } else if (p.items().size() == 1 && p.items().head() instanceof Terminal) { + ul.terminatorKLabel = p.klabel().get(); + ul.pTerminator = p; + } else + throw new AssertionError( + "Didn't expect this type of production when recognizing userList patterns!"); + } + assert ul.attrs != null; + assert ul.klabel != null; + assert ul.terminatorKLabel != null; + assert ul.childSort != null; + res.add(ul); } + return res; + } } diff --git a/kore/src/main/java/org/kframework/kore/AddAtt.java b/kore/src/main/java/org/kframework/kore/AddAtt.java index 68e2a4e3880..0a65fd0beab 100644 --- a/kore/src/main/java/org/kframework/kore/AddAtt.java +++ b/kore/src/main/java/org/kframework/kore/AddAtt.java @@ -1,55 +1,50 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kore; -import org.kframework.attributes.Att; -import org.kframework.kore.K; -import org.kframework.kore.KApply; -import org.kframework.kore.KAs; -import org.kframework.kore.KRewrite; -import org.kframework.kore.KSequence; -import org.kframework.kore.KToken; -import org.kframework.kore.KVariable; -import org.kframework.kore.TransformK; +import static org.kframework.kore.KORE.*; import java.util.function.UnaryOperator; - -import static org.kframework.kore.KORE.*; +import org.kframework.attributes.Att; public class AddAtt extends TransformK { - private final UnaryOperator f; - - public AddAtt(UnaryOperator f) { - this.f = f; - } - - @Override - public K apply(KApply kapp) { - return KApply(kapp.klabel(), kapp.klist(), f.apply(kapp.att())); - } - @Override - public K apply(KRewrite rew) { - return KRewrite(rew.left(), rew.right(), f.apply(rew.att())); - } - @Override - public K apply(KToken tok) { - return KToken(tok.s(), tok.sort(), f.apply(tok.att())); - } - @Override - public K apply(KVariable var) { - return KVariable(var.name(), f.apply(var.att())); - } - @Override - public K apply(KSequence kseq) { - return KSequence(kseq.items(), f.apply(kseq.att())); - } - @Override - public K apply(InjectedKLabel lbl) { - return InjectedKLabel(lbl.klabel(), f.apply(lbl.att())); - } - @Override - public K apply(KAs kas) { - return KAs(kas.pattern(), kas.alias(), f.apply(kas.att())); - } + private final UnaryOperator f; + + public AddAtt(UnaryOperator f) { + this.f = f; + } + + @Override + public K apply(KApply kapp) { + return KApply(kapp.klabel(), kapp.klist(), f.apply(kapp.att())); + } + + @Override + public K apply(KRewrite rew) { + return KRewrite(rew.left(), rew.right(), f.apply(rew.att())); + } + + @Override + public K apply(KToken tok) { + return KToken(tok.s(), tok.sort(), f.apply(tok.att())); + } + + @Override + public K apply(KVariable var) { + return KVariable(var.name(), f.apply(var.att())); + } + + @Override + public K apply(KSequence kseq) { + return KSequence(kseq.items(), f.apply(kseq.att())); + } + + @Override + public K apply(InjectedKLabel lbl) { + return InjectedKLabel(lbl.klabel(), f.apply(lbl.att())); + } + + @Override + public K apply(KAs kas) { + return KAs(kas.pattern(), kas.alias(), f.apply(kas.att())); + } } - - diff --git a/kore/src/main/java/org/kframework/kore/AddAttRec.java b/kore/src/main/java/org/kframework/kore/AddAttRec.java index 443805d3046..5a6a8c4be5d 100644 --- a/kore/src/main/java/org/kframework/kore/AddAttRec.java +++ b/kore/src/main/java/org/kframework/kore/AddAttRec.java @@ -1,10 +1,6 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kore; -import org.kframework.attributes.Att; - -import java.util.function.UnaryOperator; - import static org.kframework.kore.KORE.InjectedKLabel; import static org.kframework.kore.KORE.KApply; import static org.kframework.kore.KORE.KAs; @@ -13,41 +9,48 @@ import static org.kframework.kore.KORE.KToken; import static org.kframework.kore.KORE.KVariable; +import java.util.function.UnaryOperator; +import org.kframework.attributes.Att; + public class AddAttRec extends TransformK { - private final UnaryOperator f; - - public AddAttRec(UnaryOperator f) { - this.f = f; - } - - @Override - public K apply(KApply kapp) { - return super.apply(KApply(kapp.klabel(), kapp.klist(), f.apply(kapp.att()))); - } - @Override - public K apply(KRewrite rew) { - return super.apply(KRewrite(rew.left(), rew.right(), f.apply(rew.att()))); - } - @Override - public K apply(KToken tok) { - return super.apply(KToken(tok.s(), tok.sort(), f.apply(tok.att()))); - } - @Override - public K apply(KVariable var) { - return super.apply(KVariable(var.name(), f.apply(var.att()))); - } - @Override - public K apply(KSequence kseq) { - return super.apply(KSequence(kseq.items(), f.apply(kseq.att()))); - } - @Override - public K apply(InjectedKLabel lbl) { - return super.apply(InjectedKLabel(lbl.klabel(), f.apply(lbl.att()))); - } - @Override - public K apply(KAs kas) { - return super.apply(KAs(kas.pattern(), kas.alias(), f.apply(kas.att()))); - } + private final UnaryOperator f; + + public AddAttRec(UnaryOperator f) { + this.f = f; + } + + @Override + public K apply(KApply kapp) { + return super.apply(KApply(kapp.klabel(), kapp.klist(), f.apply(kapp.att()))); + } + + @Override + public K apply(KRewrite rew) { + return super.apply(KRewrite(rew.left(), rew.right(), f.apply(rew.att()))); + } + + @Override + public K apply(KToken tok) { + return super.apply(KToken(tok.s(), tok.sort(), f.apply(tok.att()))); + } + + @Override + public K apply(KVariable var) { + return super.apply(KVariable(var.name(), f.apply(var.att()))); + } + + @Override + public K apply(KSequence kseq) { + return super.apply(KSequence(kseq.items(), f.apply(kseq.att()))); + } + + @Override + public K apply(InjectedKLabel lbl) { + return super.apply(InjectedKLabel(lbl.klabel(), f.apply(lbl.att()))); + } + + @Override + public K apply(KAs kas) { + return super.apply(KAs(kas.pattern(), kas.alias(), f.apply(kas.att()))); + } } - - diff --git a/kore/src/main/java/org/kframework/kore/AttCompare.java b/kore/src/main/java/org/kframework/kore/AttCompare.java index 7d2ad93715d..35b4ed82d04 100644 --- a/kore/src/main/java/org/kframework/kore/AttCompare.java +++ b/kore/src/main/java/org/kframework/kore/AttCompare.java @@ -1,82 +1,79 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kore; +import java.util.Arrays; +import java.util.List; import org.kframework.attributes.Att; import scala.Tuple2; import scala.collection.Map; -import java.util.Arrays; -import java.util.List; - -/** - * Created by dwightguth on 6/17/15. - */ +/** Created by dwightguth on 6/17/15. */ public class AttCompare { - private final K k; - private final List attNames; + private final K k; + private final List attNames; - public AttCompare(K k, Att.Key... attNames) { - this.k = k; - this.attNames = Arrays.asList(attNames); - } + public AttCompare(K k, Att.Key... attNames) { + this.k = k; + this.attNames = Arrays.asList(attNames); + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; - AttCompare that = (AttCompare) o; + AttCompare that = (AttCompare) o; - return attEquals(this.k, that.k); + return attEquals(this.k, that.k); + } + private boolean attEquals(K thisK, K thatK) { + if (!filterAtt(thisK.att()).equals(filterAtt(thatK.att()))) { + return false; } - - private boolean attEquals(K thisK, K thatK) { - if (!filterAtt(thisK.att()).equals(filterAtt(thatK.att()))) { - return false; - } - if ((thisK instanceof KToken && thatK instanceof KToken) - || (thisK instanceof KVariable && thatK instanceof KVariable) - || (thisK instanceof InjectedKLabel && thatK instanceof InjectedKLabel)) { - return thisK.equals(thatK); - } else if (thisK instanceof KApply thisKItem && thatK instanceof KApply thatKItem) { - return thisKItem.klabel().equals(thatKItem.klabel()) && attEquals(thisKItem.klist().items(), thatKItem.klist().items()); - } else if (thisK instanceof KSequence && thatK instanceof KSequence) { - return attEquals(((KSequence) thisK).items(), ((KSequence) thatK).items()); - } else if (thisK instanceof KRewrite thisKR && thatK instanceof KRewrite thatKR) { - return attEquals(thisKR.left(), thatKR.left()) && attEquals(thisKR.right(), thatKR.right()); - } else { - return false; - } + if ((thisK instanceof KToken && thatK instanceof KToken) + || (thisK instanceof KVariable && thatK instanceof KVariable) + || (thisK instanceof InjectedKLabel && thatK instanceof InjectedKLabel)) { + return thisK.equals(thatK); + } else if (thisK instanceof KApply thisKItem && thatK instanceof KApply thatKItem) { + return thisKItem.klabel().equals(thatKItem.klabel()) + && attEquals(thisKItem.klist().items(), thatKItem.klist().items()); + } else if (thisK instanceof KSequence && thatK instanceof KSequence) { + return attEquals(((KSequence) thisK).items(), ((KSequence) thatK).items()); + } else if (thisK instanceof KRewrite thisKR && thatK instanceof KRewrite thatKR) { + return attEquals(thisKR.left(), thatKR.left()) && attEquals(thisKR.right(), thatKR.right()); + } else { + return false; } + } - private boolean attEquals(List thisK, List thatK) { - if (thisK.size() != thatK.size()) { - return false; - } - for (int i = 0; i < thisK.size(); i++) { - if (!attEquals(thisK.get(i), thatK.get(i))) { - return false; - } - } - return true; + private boolean attEquals(List thisK, List thatK) { + if (thisK.size() != thatK.size()) { + return false; } - - private Map, Object> filterAtt(Att att) { - return att.att().filterKeys(tuple -> attNames.contains(tuple._1())); + for (int i = 0; i < thisK.size(); i++) { + if (!attEquals(thisK.get(i), thatK.get(i))) { + return false; + } } + return true; + } - @Override - public String toString() { - return k.toString(); - } + private Map, Object> filterAtt(Att att) { + return att.att().filterKeys(tuple -> attNames.contains(tuple._1())); + } - @Override - public int hashCode() { - return k.hashCode(); - } + @Override + public String toString() { + return k.toString(); + } - public K get() { - return k; - } + @Override + public int hashCode() { + return k.hashCode(); + } + + public K get() { + return k; + } } diff --git a/kore/src/main/java/org/kframework/kore/ExistsK.java b/kore/src/main/java/org/kframework/kore/ExistsK.java index 95c121a007a..b8966e1bbb3 100644 --- a/kore/src/main/java/org/kframework/kore/ExistsK.java +++ b/kore/src/main/java/org/kframework/kore/ExistsK.java @@ -1,17 +1,15 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kore; -/** - * Checks whether particular K pattern given as a visitor exists. - */ +/** Checks whether particular K pattern given as a visitor exists. */ public class ExistsK extends AbstractFoldK { - @Override - public Boolean unit() { - return false; - } + @Override + public Boolean unit() { + return false; + } - @Override - public Boolean merge(Boolean a, Boolean b) { - return a || b; - } + @Override + public Boolean merge(Boolean a, Boolean b) { + return a || b; + } } diff --git a/kore/src/main/java/org/kframework/kore/FindK.java b/kore/src/main/java/org/kframework/kore/FindK.java index 1df92bdfe57..243527da102 100644 --- a/kore/src/main/java/org/kframework/kore/FindK.java +++ b/kore/src/main/java/org/kframework/kore/FindK.java @@ -4,17 +4,15 @@ import org.kframework.Collections; import scala.collection.Set; -/** - * Finds all patterns described by the visitor - */ +/** Finds all patterns described by the visitor */ public class FindK extends AbstractFoldK> { - @Override - public Set unit() { - return Collections.Set(); - } + @Override + public Set unit() { + return Collections.Set(); + } - @Override - public Set merge(Set a, Set b) { - return Collections.or(a, b); - } + @Override + public Set merge(Set a, Set b) { + return Collections.or(a, b); + } } diff --git a/kore/src/main/java/org/kframework/kore/TransformK.java b/kore/src/main/java/org/kframework/kore/TransformK.java index 0dcb79d8be7..fe106f08c27 100644 --- a/kore/src/main/java/org/kframework/kore/TransformK.java +++ b/kore/src/main/java/org/kframework/kore/TransformK.java @@ -1,91 +1,89 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kore; -import java.util.ArrayList; - import static org.kframework.kore.KORE.KApply; import static org.kframework.kore.KORE.KAs; import static org.kframework.kore.KORE.KList; import static org.kframework.kore.KORE.KRewrite; import static org.kframework.kore.KORE.KSequence; -/** - * Abstract K to K transformer. - */ +import java.util.ArrayList; + +/** Abstract K to K transformer. */ public class TransformK extends AbstractKTransformer { - @Override - public K apply(KApply k) { - ArrayList newItems = new ArrayList<>(k.klist().items()); - boolean change = false; - for (int i = 0; i < newItems.size(); ++i) { - K in = newItems.get(i); - K out = apply(in); - newItems.set(i, out); - change = change || (in != out); - } - if (change) { - return KApply(apply(k.klabel()), KList(newItems), k.att()); - } else { - return k; - } + @Override + public K apply(KApply k) { + ArrayList newItems = new ArrayList<>(k.klist().items()); + boolean change = false; + for (int i = 0; i < newItems.size(); ++i) { + K in = newItems.get(i); + K out = apply(in); + newItems.set(i, out); + change = change || (in != out); } - - private KLabel apply(KLabel klabel) { - return klabel; + if (change) { + return KApply(apply(k.klabel()), KList(newItems), k.att()); + } else { + return k; } + } - @Override - public K apply(KRewrite k) { - K l = apply(k.left()); - K r = apply(k.right()); - if (l != k.left() || r != k.right()) { - return KRewrite(l, r, k.att()); - } else { - return k; - } - } + private KLabel apply(KLabel klabel) { + return klabel; + } - @Override - public K apply(KAs k) { - K l = apply(k.pattern()); - K r = apply(k.alias()); - if (l != k.pattern() || r != k.alias()) { - return KAs(l, r, k.att()); - } else { - return k; - } + @Override + public K apply(KRewrite k) { + K l = apply(k.left()); + K r = apply(k.right()); + if (l != k.left() || r != k.right()) { + return KRewrite(l, r, k.att()); + } else { + return k; } + } - @Override - public K apply(KToken k) { - return k; + @Override + public K apply(KAs k) { + K l = apply(k.pattern()); + K r = apply(k.alias()); + if (l != k.pattern() || r != k.alias()) { + return KAs(l, r, k.att()); + } else { + return k; } + } - @Override - public K apply(KVariable k) { - return k; - } + @Override + public K apply(KToken k) { + return k; + } - @Override - public K apply(KSequence k) { - ArrayList newItems = new ArrayList<>(k.items()); - boolean change = false; - for (int i = 0; i < newItems.size(); ++i) { - K in = newItems.get(i); - K out = apply(newItems.get(i)); - newItems.set(i, out); - change = change || (in != out); - } - if (change) { - return KSequence(newItems, k.att()); - } else { - return k; - } - } + @Override + public K apply(KVariable k) { + return k; + } - @Override - public K apply(InjectedKLabel k) { - return k; + @Override + public K apply(KSequence k) { + ArrayList newItems = new ArrayList<>(k.items()); + boolean change = false; + for (int i = 0; i < newItems.size(); ++i) { + K in = newItems.get(i); + K out = apply(newItems.get(i)); + newItems.set(i, out); + change = change || (in != out); } + if (change) { + return KSequence(newItems, k.att()); + } else { + return k; + } + } + + @Override + public K apply(InjectedKLabel k) { + return k; + } } diff --git a/kore/src/main/java/org/kframework/kore/VisitK.java b/kore/src/main/java/org/kframework/kore/VisitK.java index bea4065a83f..e122e05cf5a 100644 --- a/kore/src/main/java/org/kframework/kore/VisitK.java +++ b/kore/src/main/java/org/kframework/kore/VisitK.java @@ -1,9 +1,5 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.kore; -/** - * Abstract visitor for K. - */ -public class VisitK extends AbstractKVisitor { - -} +/** Abstract visitor for K. */ +public class VisitK extends AbstractKVisitor {} diff --git a/kore/src/main/java/org/kframework/parser/KoreParser.java b/kore/src/main/java/org/kframework/parser/KoreParser.java index da57aa8ca3c..32455e1e69a 100644 --- a/kore/src/main/java/org/kframework/parser/KoreParser.java +++ b/kore/src/main/java/org/kframework/parser/KoreParser.java @@ -1,6 +1,9 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.parser; +import static org.kframework.Collections.*; + +import java.io.File; import org.kframework.Collections; import org.kframework.attributes.Att; import org.kframework.kore.K; @@ -8,43 +11,39 @@ import org.kframework.parser.kore.Pattern; import org.kframework.parser.kore.parser.ParseError; import org.kframework.parser.kore.parser.TextToKore; -import org.kframework.utils.StringUtil; import org.kframework.utils.errorsystem.KEMException; -import scala.collection.Map; import scala.Tuple2; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.Properties; - -import static org.kframework.Collections.*; +import scala.collection.Map; public class KoreParser { - private final TextToKore textToKore; - private final org.kframework.parser.kore.parser.KoreToK koreToK; - - public KoreParser(Map sortAttMap) { - textToKore = new TextToKore(); - koreToK = new org.kframework.parser.kore.parser.KoreToK(stream(sortAttMap).map(t -> Tuple2.apply(t._1().name(), t._2().getOptional(Att.HOOK()).orElse(""))).collect(Collections.toMap())); + private final TextToKore textToKore; + private final org.kframework.parser.kore.parser.KoreToK koreToK; + + public KoreParser(Map sortAttMap) { + textToKore = new TextToKore(); + koreToK = + new org.kframework.parser.kore.parser.KoreToK( + stream(sortAttMap) + .map(t -> Tuple2.apply(t._1().name(), t._2().getOptional(Att.HOOK()).orElse(""))) + .collect(Collections.toMap())); + } + + public K parseString(String koreString) { + try { + Pattern kore = textToKore.parsePattern(koreString); + return koreToK.apply(kore); + } catch (ParseError parseError) { + throw KEMException.criticalError("Parse error\n", parseError); } + } - public K parseString(String koreString) { - try { - Pattern kore = textToKore.parsePattern(koreString); - return koreToK.apply(kore); - } catch (ParseError parseError) { - throw KEMException.criticalError("Parse error\n", parseError ); - } - } + public K parseFile(File koreFile) throws ParseError { + Pattern kore = textToKore.parsePattern(koreFile, 0); + return koreToK.apply(kore); + } - public K parseFile(File koreFile) throws ParseError { - Pattern kore = textToKore.parsePattern(koreFile, 0); - return koreToK.apply(kore); - } - - public K parseFile(File koreFile, int line) throws ParseError { - Pattern kore = textToKore.parsePattern(koreFile, line); - return koreToK.apply(kore); - } + public K parseFile(File koreFile, int line) throws ParseError { + Pattern kore = textToKore.parsePattern(koreFile, line); + return koreToK.apply(kore); + } } diff --git a/kore/src/main/java/org/kframework/rewriter/SearchType.java b/kore/src/main/java/org/kframework/rewriter/SearchType.java index 74a2b98f33f..21497fac24a 100644 --- a/kore/src/main/java/org/kframework/rewriter/SearchType.java +++ b/kore/src/main/java/org/kframework/rewriter/SearchType.java @@ -1,12 +1,10 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.rewriter; -/** - * Created by manasvi on 9/11/15. - */ +/** Created by manasvi on 9/11/15. */ public enum SearchType { - ONE, - PLUS, - STAR, - FINAL + ONE, + PLUS, + STAR, + FINAL } diff --git a/kore/src/main/java/org/kframework/utils/OS.java b/kore/src/main/java/org/kframework/utils/OS.java index 71dd5315006..09e82cc3c24 100644 --- a/kore/src/main/java/org/kframework/utils/OS.java +++ b/kore/src/main/java/org/kframework/utils/OS.java @@ -1,55 +1,57 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; -import org.kframework.utils.errorsystem.KEMException; - import java.util.Arrays; import java.util.List; +import org.kframework.utils.errorsystem.KEMException; public enum OS { - OSX(true), LINUX(true), UNKNOWN(false), WINDOWS(false); - - OS(boolean isPosix) { - this.isPosix = isPosix; - } - - public final boolean isPosix; - - public static OS current() { - String osString = System.getProperty("os.name").toLowerCase(); - if (osString.contains("nix") || osString.contains("nux")) - return OS.LINUX; - else if (osString.contains("win")) - return OS.WINDOWS; - else if (osString.contains("mac")) - return OS.OSX; - else - return OS.UNKNOWN; + OSX(true), + LINUX(true), + UNKNOWN(false), + WINDOWS(false); + + OS(boolean isPosix) { + this.isPosix = isPosix; + } + + public final boolean isPosix; + + public static OS current() { + String osString = System.getProperty("os.name").toLowerCase(); + if (osString.contains("nix") || osString.contains("nux")) return OS.LINUX; + else if (osString.contains("win")) return OS.WINDOWS; + else if (osString.contains("mac")) return OS.OSX; + else return OS.UNKNOWN; + } + + public String getSharedLibraryExtension() { + if (this == OSX) { + return ".dylib"; + } else if (this == LINUX) { + return ".so"; + } else { + throw KEMException.internalError( + "Shared libraries are not supported on: " + System.getProperty("os.name")); } - - public String getSharedLibraryExtension() { - if (this == OSX) { - return ".dylib"; - } else if (this == LINUX) { - return ".so"; - } else { - throw KEMException.internalError("Shared libraries are not supported on: " + System.getProperty("os.name")); - } + } + + public List getSharedLibraryCompilerFlags() { + return Arrays.asList("-fPIC", "-shared"); + } + + public String getNativeExecutable(String executable) { + if (this == UNKNOWN) { + throw KEMException.internalError( + "Unknown OS type. " + + System.getProperty("os.name") + + " not recognized. " + + "Please contact K developers with details of your OS."); } - - public List getSharedLibraryCompilerFlags() { - return Arrays.asList("-fPIC", "-shared"); - } - - public String getNativeExecutable(String executable) { - if (this == UNKNOWN) { - throw KEMException.internalError( - "Unknown OS type. " + System.getProperty("os.name") + " not recognized. " + - "Please contact K developers with details of your OS."); - } - if (this == WINDOWS) { - throw KEMException.internalError("K is not supported on native windows. Please use the Windows Subsystem for Linux."); - } - return executable; + if (this == WINDOWS) { + throw KEMException.internalError( + "K is not supported on native windows. Please use the Windows Subsystem for Linux."); } + return executable; + } } diff --git a/kore/src/main/java/org/kframework/utils/StringUtil.java b/kore/src/main/java/org/kframework/utils/StringUtil.java index b2361b6cfc5..4ffa82c7235 100644 --- a/kore/src/main/java/org/kframework/utils/StringUtil.java +++ b/kore/src/main/java/org/kframework/utils/StringUtil.java @@ -1,744 +1,745 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils; -import org.apache.commons.lang3.StringUtils; - -import com.beust.jcommander.JCommander; - -import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Set; import java.util.regex.Pattern; -import java.util.stream.Collectors; public class StringUtil { - /** - * Unescape the textual representation of a string specific to SDF and Maude. - * It removes the double quote at the beginning and end, and transforms special sequence - * of characters like "\n" into the newline character. - */ - public static String unquoteCString(String str) { - return unquoteCString(str, '"'); - } - public static String unquoteCString(String str, char delimiter) { - StringBuilder sb = new StringBuilder(); - if (str.charAt(0) != delimiter) { - throw new IllegalArgumentException("Expected to find " + delimiter + " at the beginning of string: " + str); - } - if (str.charAt(str.length() - 1) != delimiter) { - throw new IllegalArgumentException("Expected to find " + delimiter + " at the end of string: " + str); - } - for (int i = 1; i < str.length() - 1; i++) { - if (str.charAt(i) == '\\') { - if (str.charAt(i + 1) == '\\') - sb.append('\\'); - else if (str.charAt(i + 1) == 'n') - sb.append('\n'); - else if (str.charAt(i + 1) == 'r') - sb.append('\r'); - else if (str.charAt(i + 1) == 't') - sb.append('\t'); - else if (str.charAt(i + 1) == 'f') - sb.append('\f'); - else if (str.charAt(i + 1) == delimiter) - sb.append(delimiter); - else if (str.charAt(i + 1) >= '0' && str.charAt(i + 1) <= '9') { - // found an octal value - int a2 = str.charAt(i + 1) - '0'; - int a1 = str.charAt(i + 2) - '0'; - if (a1 < 0 || a1 > 9) - throw new IllegalArgumentException("Malformed octal value in string:" + str); - int a0 = str.charAt(i + 3) - '0'; - if (a0 < 0 || a0 > 9) - throw new IllegalArgumentException("Malformed octal value in string:" + str); - int decimal = a2 * 8 * 8 + a1 * 8 + a0; - sb.append((char) decimal); - i++; i++; - } - i++; - } else - sb.append(str.charAt(i)); - } + /** + * Unescape the textual representation of a string specific to SDF and Maude. It removes the + * double quote at the beginning and end, and transforms special sequence of characters like "\n" + * into the newline character. + */ + public static String unquoteCString(String str) { + return unquoteCString(str, '"'); + } - return sb.toString(); + public static String unquoteCString(String str, char delimiter) { + StringBuilder sb = new StringBuilder(); + if (str.charAt(0) != delimiter) { + throw new IllegalArgumentException( + "Expected to find " + delimiter + " at the beginning of string: " + str); + } + if (str.charAt(str.length() - 1) != delimiter) { + throw new IllegalArgumentException( + "Expected to find " + delimiter + " at the end of string: " + str); + } + for (int i = 1; i < str.length() - 1; i++) { + if (str.charAt(i) == '\\') { + if (str.charAt(i + 1) == '\\') sb.append('\\'); + else if (str.charAt(i + 1) == 'n') sb.append('\n'); + else if (str.charAt(i + 1) == 'r') sb.append('\r'); + else if (str.charAt(i + 1) == 't') sb.append('\t'); + else if (str.charAt(i + 1) == 'f') sb.append('\f'); + else if (str.charAt(i + 1) == delimiter) sb.append(delimiter); + else if (str.charAt(i + 1) >= '0' && str.charAt(i + 1) <= '9') { + // found an octal value + int a2 = str.charAt(i + 1) - '0'; + int a1 = str.charAt(i + 2) - '0'; + if (a1 < 0 || a1 > 9) + throw new IllegalArgumentException("Malformed octal value in string:" + str); + int a0 = str.charAt(i + 3) - '0'; + if (a0 < 0 || a0 > 9) + throw new IllegalArgumentException("Malformed octal value in string:" + str); + int decimal = a2 * 8 * 8 + a1 * 8 + a0; + sb.append((char) decimal); + i++; + i++; + } + i++; + } else sb.append(str.charAt(i)); } - /** - * Takes the internal representation of a string, and creates the textual representation - * that is ready to be printed. - * It adds double quote at the beginning and end, and transforms special characters into - * the textual representation (ex: newline becomes "\n"). - */ - public static String enquoteCString(String value) { - return enquoteCString(value, '"'); - } - public static String enquoteCString(String value, char delimiter) { - final int length = value.length(); - StringBuilder result = new StringBuilder(); - result.append(delimiter); - for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { - codepoint = value.codePointAt(offset); - if (codepoint > 0xFF) { - result.appendCodePoint(codepoint); - } else if (codepoint == delimiter) { - result.append("\\" + delimiter); - } else if (codepoint == '\\') { - result.append("\\\\"); - } else if (codepoint == '\n') { - result.append("\\n"); - } else if (codepoint == '\t') { - result.append("\\t"); - } else if (codepoint == '\r') { - result.append("\\r"); - } else if (codepoint == '\f') { - result.append("\\f"); - } else if (codepoint >= 32 && codepoint < 127) { - result.append((char)codepoint); - } else if (codepoint <= 0xff) { - result.append("\\"); - result.append(String.format("%03o", codepoint)); - } - } - result.append(delimiter); - return result.toString(); + return sb.toString(); + } + + /** + * Takes the internal representation of a string, and creates the textual representation that is + * ready to be printed. It adds double quote at the beginning and end, and transforms special + * characters into the textual representation (ex: newline becomes "\n"). + */ + public static String enquoteCString(String value) { + return enquoteCString(value, '"'); + } + + public static String enquoteCString(String value, char delimiter) { + final int length = value.length(); + StringBuilder result = new StringBuilder(); + result.append(delimiter); + for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { + codepoint = value.codePointAt(offset); + if (codepoint > 0xFF) { + result.appendCodePoint(codepoint); + } else if (codepoint == delimiter) { + result.append("\\" + delimiter); + } else if (codepoint == '\\') { + result.append("\\\\"); + } else if (codepoint == '\n') { + result.append("\\n"); + } else if (codepoint == '\t') { + result.append("\\t"); + } else if (codepoint == '\r') { + result.append("\\r"); + } else if (codepoint == '\f') { + result.append("\\f"); + } else if (codepoint >= 32 && codepoint < 127) { + result.append((char) codepoint); + } else if (codepoint <= 0xff) { + result.append("\\"); + result.append(String.format("%03o", codepoint)); + } } + result.append(delimiter); + return result.toString(); + } - public static void throwIfSurrogatePair(int codePoint) { - if (codePoint >= 0xd800 && codePoint <= 0xdfff) { - //we are trying to encode a surrogate pair, which the unicode - //standard forbids - throw new IllegalArgumentException(Integer.toHexString(codePoint) + - " is not in the accepted unicode range."); - } - if (codePoint >= 0x110000) - throw new IllegalArgumentException(Integer.toHexString(codePoint) + - " is not in the accepted unicode range."); + public static void throwIfSurrogatePair(int codePoint) { + if (codePoint >= 0xd800 && codePoint <= 0xdfff) { + // we are trying to encode a surrogate pair, which the unicode + // standard forbids + throw new IllegalArgumentException( + Integer.toHexString(codePoint) + " is not in the accepted unicode range."); } + if (codePoint >= 0x110000) + throw new IllegalArgumentException( + Integer.toHexString(codePoint) + " is not in the accepted unicode range."); + } - public static int lastIndexOfAny(String str, String search, int offset) { - if (str.equals("") || search.equals("")) { - return -1; - } - int start = str.offsetByCodePoints(0, offset); - for (int i = start, strCodepoint; i >= 0; i -= Character.charCount(strCodepoint)) { - strCodepoint = str.codePointAt(i); - for (int j = search.length() - 1, searchCodepoint; j >= 0; j -= Character.charCount(searchCodepoint)) { - searchCodepoint = search.codePointAt(j); - if (strCodepoint == searchCodepoint) { - return i; - } - } - } - return -1; + public static int lastIndexOfAny(String str, String search, int offset) { + if (str.equals("") || search.equals("")) { + return -1; } + int start = str.offsetByCodePoints(0, offset); + for (int i = start, strCodepoint; i >= 0; i -= Character.charCount(strCodepoint)) { + strCodepoint = str.codePointAt(i); + for (int j = search.length() - 1, searchCodepoint; + j >= 0; + j -= Character.charCount(searchCodepoint)) { + searchCodepoint = search.codePointAt(j); + if (strCodepoint == searchCodepoint) { + return i; + } + } + } + return -1; + } - public static int indexOfAny(String str, String search, int offset) { - if (str.equals("") || search.equals("")) { - return -1; - } - int start = str.offsetByCodePoints(0, offset); - for (int i = start, strCodepoint; i < str.length(); i += Character.charCount(strCodepoint)) { - strCodepoint = str.codePointAt(i); - for (int j = 0, searchCodepoint; j < search.length(); j += Character.charCount(searchCodepoint)) { - searchCodepoint = search.codePointAt(j); - if (strCodepoint == searchCodepoint) { - return i; - } - } - } - return -1; + public static int indexOfAny(String str, String search, int offset) { + if (str.equals("") || search.equals("")) { + return -1; + } + int start = str.offsetByCodePoints(0, offset); + for (int i = start, strCodepoint; i < str.length(); i += Character.charCount(strCodepoint)) { + strCodepoint = str.codePointAt(i); + for (int j = 0, searchCodepoint; + j < search.length(); + j += Character.charCount(searchCodepoint)) { + searchCodepoint = search.codePointAt(j); + if (strCodepoint == searchCodepoint) { + return i; + } + } } + return -1; + } - /** - * Removes the first and last double-quote characters and unescapes special characters - * that start with backslash: newline, carriage return, line feed, tab and backslash. - * Characters between 127 and 255 are stored as \xFF - * Characters between 256 and 65535 are stored as \uFFFF - * Characters above 65536 are stored as \u0010FFFF - * @param str Python like double-quoted string - * @return unescaped and unquoted string - */ - public static String unquoteKString(String str) { - StringBuilder sb = new StringBuilder(); - if (str.charAt(0) != '"') { - throw new IllegalArgumentException("Expected to find double quote at the beginning of string: " + str); - } - if (str.charAt(str.length() - 1) != '"') { - throw new IllegalArgumentException("Expected to find double quote at the end of string: " + str); - } - for (int i = 1; i < str.length() - 1; i++) { - if (str.charAt(i) == '\\') { - if (str.charAt(i + 1) == '"') { - sb.append('"'); - i++; - } else if (str.charAt(i + 1) == '\\') { - sb.append('\\'); - i++; - } else if (str.charAt(i + 1) == 'n') { - sb.append('\n'); - i++; - } else if (str.charAt(i + 1) == 'r') { - sb.append('\r'); - i++; - } else if (str.charAt(i + 1) == 't') { - sb.append('\t'); - i++; - } else if (str.charAt(i + 1) == 'f') { - sb.append('\f'); - i++; - } else if (str.charAt(i + 1) == 'x') { - String arg = str.substring(i + 2, i + 4); - sb.append((char)Integer.parseInt(arg, 16)); - i += 3; - } else if (str.charAt(i + 1) == 'u') { - String arg = str.substring(i + 2, i + 6); - int codePoint = Integer.parseInt(arg, 16); - StringUtil.throwIfSurrogatePair(codePoint); - sb.append((char)codePoint); - i += 5; - } else if (str.charAt(i + 1) == 'U') { - String arg = str.substring(i + 2, i + 10); - int codePoint = Integer.parseInt(arg, 16); - StringUtil.throwIfSurrogatePair(codePoint); - sb.append(Character.toChars(codePoint)); - i += 9; - } - } else { - sb.append(str.charAt(i)); - } - } - return sb.toString(); + /** + * Removes the first and last double-quote characters and unescapes special characters that start + * with backslash: newline, carriage return, line feed, tab and backslash. Characters between 127 + * and 255 are stored as \xFF Characters between 256 and 65535 are stored as \uFFFF Characters + * above 65536 are stored as \u0010FFFF + * + * @param str Python like double-quoted string + * @return unescaped and unquoted string + */ + public static String unquoteKString(String str) { + StringBuilder sb = new StringBuilder(); + if (str.charAt(0) != '"') { + throw new IllegalArgumentException( + "Expected to find double quote at the beginning of string: " + str); } + if (str.charAt(str.length() - 1) != '"') { + throw new IllegalArgumentException( + "Expected to find double quote at the end of string: " + str); + } + for (int i = 1; i < str.length() - 1; i++) { + if (str.charAt(i) == '\\') { + if (str.charAt(i + 1) == '"') { + sb.append('"'); + i++; + } else if (str.charAt(i + 1) == '\\') { + sb.append('\\'); + i++; + } else if (str.charAt(i + 1) == 'n') { + sb.append('\n'); + i++; + } else if (str.charAt(i + 1) == 'r') { + sb.append('\r'); + i++; + } else if (str.charAt(i + 1) == 't') { + sb.append('\t'); + i++; + } else if (str.charAt(i + 1) == 'f') { + sb.append('\f'); + i++; + } else if (str.charAt(i + 1) == 'x') { + String arg = str.substring(i + 2, i + 4); + sb.append((char) Integer.parseInt(arg, 16)); + i += 3; + } else if (str.charAt(i + 1) == 'u') { + String arg = str.substring(i + 2, i + 6); + int codePoint = Integer.parseInt(arg, 16); + StringUtil.throwIfSurrogatePair(codePoint); + sb.append((char) codePoint); + i += 5; + } else if (str.charAt(i + 1) == 'U') { + String arg = str.substring(i + 2, i + 10); + int codePoint = Integer.parseInt(arg, 16); + StringUtil.throwIfSurrogatePair(codePoint); + sb.append(Character.toChars(codePoint)); + i += 9; + } + } else { + sb.append(str.charAt(i)); + } + } + return sb.toString(); + } - /** - * Get the escaped string for a Unicode codepoint: - * Codepoints between 32 and 126 are stored directly as the character - * Codepoints between 0 and 31 and between 127 and 255 are stored as \xFF - * Codepoints between 256 and 65535 are stored as \uFFFF - * Codepoints above 65536 are stored as \u0010FFFF - * @param value a Unicode codepoint - * @return representation of the codepoint as an escaped string - */ - public static String getUnicodeEscape(int codepoint) { - if (32 <= codepoint && codepoint < 127) { - return String.valueOf((char) codepoint); - } - if (codepoint <= 0xff) { - return "\\x" + String.format("%02x", codepoint); - } - if (codepoint <= 0xffff) { - return "\\u" + String.format("%04x", codepoint); - } - return "\\U" + String.format("%08x", codepoint); + /** + * Get the escaped string for a Unicode codepoint: Codepoints between 32 and 126 are stored + * directly as the character Codepoints between 0 and 31 and between 127 and 255 are stored as + * \xFF Codepoints between 256 and 65535 are stored as \uFFFF Codepoints above 65536 are stored as + * \u0010FFFF + * + * @param value a Unicode codepoint + * @return representation of the codepoint as an escaped string + */ + public static String getUnicodeEscape(int codepoint) { + if (32 <= codepoint && codepoint < 127) { + return String.valueOf((char) codepoint); + } + if (codepoint <= 0xff) { + return "\\x" + String.format("%02x", codepoint); } + if (codepoint <= 0xffff) { + return "\\u" + String.format("%04x", codepoint); + } + return "\\U" + String.format("%08x", codepoint); + } - /** - * Adds double-quote at the beginning and end of the string and escapes special characters - * with backslash: newline, carriage return, line feed, tab and backslash. - * Characters between 127 and 255 are stored as \xFF - * Characters between 256 and 65535 are stored as \uFFFF - * Characters above 65536 are stored as \u0010FFFF - * @param value any string - * @return Python like textual representation of the string - */ - public static String enquoteKString(String value) { - final int length = value.length(); - StringBuilder result = new StringBuilder(); - result.append("\""); - for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { - codepoint = value.codePointAt(offset); - if (codepoint == '"') { - result.append("\\\""); - } else if (codepoint == '\\') { - result.append("\\\\"); - } else if (codepoint == '\n') { - result.append("\\n"); - } else if (codepoint == '\t') { - result.append("\\t"); - } else if (codepoint == '\r') { - result.append("\\r"); - } else if (codepoint == '\f') { - result.append("\\f"); - } else { - result.append(StringUtil.getUnicodeEscape(codepoint)); - } - } - result.append("\""); - return result.toString(); + /** + * Adds double-quote at the beginning and end of the string and escapes special characters with + * backslash: newline, carriage return, line feed, tab and backslash. Characters between 127 and + * 255 are stored as \xFF Characters between 256 and 65535 are stored as \uFFFF Characters above + * 65536 are stored as \u0010FFFF + * + * @param value any string + * @return Python like textual representation of the string + */ + public static String enquoteKString(String value) { + final int length = value.length(); + StringBuilder result = new StringBuilder(); + result.append("\""); + for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { + codepoint = value.codePointAt(offset); + if (codepoint == '"') { + result.append("\\\""); + } else if (codepoint == '\\') { + result.append("\\\\"); + } else if (codepoint == '\n') { + result.append("\\n"); + } else if (codepoint == '\t') { + result.append("\\t"); + } else if (codepoint == '\r') { + result.append("\\r"); + } else if (codepoint == '\f') { + result.append("\\f"); + } else { + result.append(StringUtil.getUnicodeEscape(codepoint)); + } } + result.append("\""); + return result.toString(); + } - /** - * Escapes all non-ASCII characters as follows: - * Characters between 32 and 126 are stored directly as the character - * Characters between 0 and 31 and between 127 and 255 are stored as \xFF - * Characters between 256 and 65535 are stored as \uFFFF - * Characters above 65536 are stored as \u0010FFFF - * @param value any string - * @return representation of the string with non-ASCII characters escaped - */ - public static String escapeNonASCII(String value) { - final int length = value.length(); - StringBuilder result = new StringBuilder(); - for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { - codepoint = value.codePointAt(offset); - result.append(StringUtil.getUnicodeEscape(codepoint)); - } - return result.toString(); + /** + * Escapes all non-ASCII characters as follows: Characters between 32 and 126 are stored directly + * as the character Characters between 0 and 31 and between 127 and 255 are stored as \xFF + * Characters between 256 and 65535 are stored as \uFFFF Characters above 65536 are stored as + * \u0010FFFF + * + * @param value any string + * @return representation of the string with non-ASCII characters escaped + */ + public static String escapeNonASCII(String value) { + final int length = value.length(); + StringBuilder result = new StringBuilder(); + for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { + codepoint = value.codePointAt(offset); + result.append(StringUtil.getUnicodeEscape(codepoint)); } + return result.toString(); + } - /** - * Returns the two-letter code for a general category of Unicode code point. - */ - public static String getCategoryCode(byte cat) { - switch(cat) { - case Character.COMBINING_SPACING_MARK: - return "Mc"; - case Character.CONNECTOR_PUNCTUATION: - return "Pc"; - case Character.CONTROL: - return "Cc"; - case Character.CURRENCY_SYMBOL: - return "Sc"; - case Character.DASH_PUNCTUATION: - return "Pd"; - case Character.DECIMAL_DIGIT_NUMBER: - return "Nd"; - case Character.ENCLOSING_MARK: - return "Me"; - case Character.END_PUNCTUATION: - return "Pe"; - case Character.FINAL_QUOTE_PUNCTUATION: - return "Pf"; - case Character.FORMAT: - return "Cf"; - case Character.INITIAL_QUOTE_PUNCTUATION: - return "Pi"; - case Character.LETTER_NUMBER: - return "Nl"; - case Character.LINE_SEPARATOR: - return "Zl"; - case Character.LOWERCASE_LETTER: - return "Ll"; - case Character.MATH_SYMBOL: - return "Sm"; - case Character.MODIFIER_LETTER: - return "Lm"; - case Character.MODIFIER_SYMBOL: - return "Sk"; - case Character.NON_SPACING_MARK: - return "Mn"; - case Character.OTHER_LETTER: - return "Lo"; - case Character.OTHER_NUMBER: - return "No"; - case Character.OTHER_PUNCTUATION: - return "Po"; - case Character.OTHER_SYMBOL: - return "So"; - case Character.PARAGRAPH_SEPARATOR: - return "Zp"; - case Character.PRIVATE_USE: - return "Co"; - case Character.SPACE_SEPARATOR: - return "Zs"; - case Character.START_PUNCTUATION: - return "Ps"; - case Character.SURROGATE: - return "Cs"; - case Character.TITLECASE_LETTER: - return "Lt"; - case Character.UNASSIGNED: - return "Cn"; - case Character.UPPERCASE_LETTER: - return "Lu"; - default: - assert false: "should be exhaustive list of categories"; - return null; //unreachable - } + /** Returns the two-letter code for a general category of Unicode code point. */ + public static String getCategoryCode(byte cat) { + switch (cat) { + case Character.COMBINING_SPACING_MARK: + return "Mc"; + case Character.CONNECTOR_PUNCTUATION: + return "Pc"; + case Character.CONTROL: + return "Cc"; + case Character.CURRENCY_SYMBOL: + return "Sc"; + case Character.DASH_PUNCTUATION: + return "Pd"; + case Character.DECIMAL_DIGIT_NUMBER: + return "Nd"; + case Character.ENCLOSING_MARK: + return "Me"; + case Character.END_PUNCTUATION: + return "Pe"; + case Character.FINAL_QUOTE_PUNCTUATION: + return "Pf"; + case Character.FORMAT: + return "Cf"; + case Character.INITIAL_QUOTE_PUNCTUATION: + return "Pi"; + case Character.LETTER_NUMBER: + return "Nl"; + case Character.LINE_SEPARATOR: + return "Zl"; + case Character.LOWERCASE_LETTER: + return "Ll"; + case Character.MATH_SYMBOL: + return "Sm"; + case Character.MODIFIER_LETTER: + return "Lm"; + case Character.MODIFIER_SYMBOL: + return "Sk"; + case Character.NON_SPACING_MARK: + return "Mn"; + case Character.OTHER_LETTER: + return "Lo"; + case Character.OTHER_NUMBER: + return "No"; + case Character.OTHER_PUNCTUATION: + return "Po"; + case Character.OTHER_SYMBOL: + return "So"; + case Character.PARAGRAPH_SEPARATOR: + return "Zp"; + case Character.PRIVATE_USE: + return "Co"; + case Character.SPACE_SEPARATOR: + return "Zs"; + case Character.START_PUNCTUATION: + return "Ps"; + case Character.SURROGATE: + return "Cs"; + case Character.TITLECASE_LETTER: + return "Lt"; + case Character.UNASSIGNED: + return "Cn"; + case Character.UPPERCASE_LETTER: + return "Lu"; + default: + assert false : "should be exhaustive list of categories"; + return null; // unreachable } + } - public static String getDirectionalityCode(byte cat) { - switch(cat) { - case Character.DIRECTIONALITY_ARABIC_NUMBER: - return "AN"; - case Character.DIRECTIONALITY_BOUNDARY_NEUTRAL: - return "BN"; - case Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR: - return "CS"; - case Character.DIRECTIONALITY_EUROPEAN_NUMBER: - return "EN"; - case Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR: - return "ES"; - case Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR: - return "ET"; - case Character.DIRECTIONALITY_LEFT_TO_RIGHT: - return "L"; - case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING: - return "LRE"; - case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE: - return "LRO"; - case Character.DIRECTIONALITY_NONSPACING_MARK: - return "NSM"; - case Character.DIRECTIONALITY_OTHER_NEUTRALS: - return "ON"; - case Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR: - return "B"; - case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT: - return "PDF"; - case Character.DIRECTIONALITY_RIGHT_TO_LEFT: - return "R"; - case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC: - return "AL"; - case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING: - return "RLE"; - case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE: - return "RLO"; - case Character.DIRECTIONALITY_SEGMENT_SEPARATOR: - return "S"; - case Character.DIRECTIONALITY_UNDEFINED: - throw new IllegalArgumentException(); - case Character.DIRECTIONALITY_WHITESPACE: - return "WS"; - default: - assert false: "should be exhaustive list of directionalities"; - return null; //unreachable - } + public static String getDirectionalityCode(byte cat) { + switch (cat) { + case Character.DIRECTIONALITY_ARABIC_NUMBER: + return "AN"; + case Character.DIRECTIONALITY_BOUNDARY_NEUTRAL: + return "BN"; + case Character.DIRECTIONALITY_COMMON_NUMBER_SEPARATOR: + return "CS"; + case Character.DIRECTIONALITY_EUROPEAN_NUMBER: + return "EN"; + case Character.DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR: + return "ES"; + case Character.DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR: + return "ET"; + case Character.DIRECTIONALITY_LEFT_TO_RIGHT: + return "L"; + case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING: + return "LRE"; + case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE: + return "LRO"; + case Character.DIRECTIONALITY_NONSPACING_MARK: + return "NSM"; + case Character.DIRECTIONALITY_OTHER_NEUTRALS: + return "ON"; + case Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR: + return "B"; + case Character.DIRECTIONALITY_POP_DIRECTIONAL_FORMAT: + return "PDF"; + case Character.DIRECTIONALITY_RIGHT_TO_LEFT: + return "R"; + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC: + return "AL"; + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING: + return "RLE"; + case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE: + return "RLO"; + case Character.DIRECTIONALITY_SEGMENT_SEPARATOR: + return "S"; + case Character.DIRECTIONALITY_UNDEFINED: + throw new IllegalArgumentException(); + case Character.DIRECTIONALITY_WHITESPACE: + return "WS"; + default: + assert false : "should be exhaustive list of directionalities"; + return null; // unreachable } + } + + /** + * split string to lines in a way that no lines will exceed 80 columns NOTE: strings split only at + * whitespace character ' ', if string contains no ' ', it's returned as is + * + * @param str string to split + * @return new string with newlines added + */ + public static String splitLines(String str) { + return splitLines(str, 80); + } - /** - * split string to lines in a way that no lines will exceed 80 columns - * NOTE: strings split only at whitespace character ' ', if string contains no ' ', it's returned as is - * @param str string to split - * @return new string with newlines added - */ - public static String splitLines(String str) { - return splitLines(str, 80); + /** + * split string to lines in a way that no lines will exceed `col` columns NOTE: strings split only + * at whitespace character ' ', if string contains no ' ', it's returned as is + * + * @param str string to split + * @param col rightmost column + * @return new string with newlines added + */ + public static String splitLines(String str, final int col) { + String[] lines = str.split("\n"); + StringBuilder builder = new StringBuilder(); + String nl = ""; + for (String line : lines) { + builder.append(nl); + if (line.length() < col) { + builder.append(line); + } else { + builder.append(splitLine(line, col)); + } + nl = "\n"; } + return builder.toString(); + } - /** - * split string to lines in a way that no lines will exceed `col` columns - * NOTE: strings split only at whitespace character ' ', if string contains no ' ', it's returned as is - * @param str string to split - * @param col rightmost column - * @return new string with newlines added - */ - public static String splitLines(String str, final int col) { - String[] lines = str.split("\n"); - StringBuilder builder = new StringBuilder(); - String nl = ""; - for (String line : lines) { - builder.append(nl); - if (line.length() < col) { - builder.append(line); - } else { - builder.append(splitLine(line, col)); - } - nl = "\n"; - } - return builder.toString(); + private static String splitLine(String str, final int col) { + if (str.length() < col) { + return str; } - private static String splitLine(String str, final int col) { - if (str.length() < col) { - return str; - } + // keep indentation of long lines (like term ambiguities) + int firstChar = 0; + while (str.charAt(firstChar) == ' ') firstChar++; + // scan from `col` to left + for (int i = col - 1; i > firstChar; i--) { + if (str.charAt(i) == ' ') { + return str.substring(0, i) + "\n" + splitLine(str.substring(i + 1), col); + } + } - // keep indentation of long lines (like term ambiguities) - int firstChar = 0; - while (str.charAt(firstChar) == ' ') - firstChar++; - // scan from `col` to left - for (int i = col - 1; i > firstChar; i--) { - if (str.charAt(i) == ' ') { - return str.substring(0, i) + "\n" + splitLine(str.substring(i + 1), col); - } - } + // we reached the beginning of the string and it contains no whitespaces before the `col` + // but it's longer than `col` so we should replace first space after rightmost column + // with a newline to make it shorter + for (int i = col; i < str.length(); i++) { + if (str.charAt(i) == ' ') { + return str.substring(0, i) + "\n" + splitLine(str.substring(i + 1), col); + } + } - // we reached the beginning of the string and it contains no whitespaces before the `col` - // but it's longer than `col` so we should replace first space after rightmost column - // with a newline to make it shorter - for (int i = col; i < str.length(); i++) { - if (str.charAt(i) == ' ') { - return str.substring(0, i) + "\n" + splitLine(str.substring(i + 1), col); - } - } + // string has no spaces to split + return str; + } - // string has no spaces to split - return str; + /** + * Takes a textual representation of a KLabel using backticks to delimit and returns the string + * representation of the KLabel that it corresponds to + * + *

Used by the KAST parser. + * + * @param str An image of a parser token corresponding to a KLabel in KORE which begins and ends + * with backtick + * @return The string value of the KLabel + */ + public static String unescapeKoreKLabel(String str) { + char delimiter = '`'; + StringBuilder sb = new StringBuilder(); + if (str.charAt(0) != delimiter) { + throw new IllegalArgumentException( + "Expected to find " + delimiter + " at the beginning of string: " + str); + } + if (str.charAt(str.length() - 1) != delimiter) { + throw new IllegalArgumentException( + "Expected to find " + delimiter + " at the end of string: " + str); + } + for (int i = 1; i < str.length() - 1; i++) { + if (str.charAt(i) == 0x7F || str.charAt(i) < 32) + throw new IllegalArgumentException("Special characters not supported here:" + str); + if (str.charAt(i) == '\\') { + if (str.charAt(i + 1) == '\\') sb.append('\\'); + else if (str.charAt(i + 1) == delimiter) sb.append(delimiter); + i++; + } else sb.append(str.charAt(i)); } - /** - * Takes a textual representation of a KLabel using backticks to delimit - * and returns the string representation of the KLabel that it corresponds to - * - * Used by the KAST parser. - * - * @param str An image of a parser token corresponding to a KLabel in KORE which - * begins and ends with backtick - * @return The string value of the KLabel - */ - public static String unescapeKoreKLabel(String str) { - char delimiter = '`'; - StringBuilder sb = new StringBuilder(); - if (str.charAt(0) != delimiter) { - throw new IllegalArgumentException("Expected to find " + delimiter + " at the beginning of string: " + str); - } - if (str.charAt(str.length() - 1) != delimiter) { - throw new IllegalArgumentException("Expected to find " + delimiter + " at the end of string: " + str); - } - for (int i = 1; i < str.length() - 1; i++) { - if (str.charAt(i) == 0x7F || str.charAt(i) < 32) - throw new IllegalArgumentException("Special characters not supported here:" + str); - if (str.charAt(i) == '\\') { - if (str.charAt(i + 1) == '\\') - sb.append('\\'); - else if (str.charAt(i + 1) == delimiter) - sb.append(delimiter); - i++; - } else - sb.append(str.charAt(i)); - } + return sb.toString(); + } - return sb.toString(); + /** + * Takes the value of a KLabel and returns a string representation, delimited with backticks, of + * the syntax of that KLabel in KORE. + * + *

Used by the KAST pretty printer. + * + * @param str A string value corresponding to a KLabel. + * @return A string which can be parsed back by a KORE parser to reach the original KLabel. + */ + public static String escapeKoreKLabel(String value) { + char delimiter = '`'; + final int length = value.length(); + StringBuilder result = new StringBuilder(); + result.append(delimiter); + for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { + codepoint = value.codePointAt(offset); + if (codepoint == 0x7F || codepoint < 32) { + throw new IllegalArgumentException("Special characters not supported here:" + value); + } else if (codepoint == delimiter) { + result.append("\\" + delimiter); + } else if (codepoint == '\\') { + result.append("\\\\"); + } else { + result.appendCodePoint(codepoint); + } } + result.append(delimiter); + return result.toString(); + } - /** - * Takes the value of a KLabel and returns a string representation, delimited with - * backticks, of the syntax of that KLabel in KORE. - * - * Used by the KAST pretty printer. - * - * @param str A string value corresponding to a KLabel. - * @return A string which can be parsed back by a KORE parser to reach the original KLabel. - */ - public static String escapeKoreKLabel(String value) { - char delimiter = '`'; - final int length = value.length(); - StringBuilder result = new StringBuilder(); - result.append(delimiter); - for (int offset = 0, codepoint; offset < length; offset += Character.charCount(codepoint)) { - codepoint = value.codePointAt(offset); - if (codepoint == 0x7F || codepoint < 32) { - throw new IllegalArgumentException("Special characters not supported here:" + value); - } else if (codepoint == delimiter) { - result.append("\\" + delimiter); - } else if (codepoint == '\\') { - result.append("\\\\"); - } else { - result.appendCodePoint(codepoint); - } - } - result.append(delimiter); - return result.toString(); - } + public static String[] asciiReadableEncodingDefault = + new String[] { + null, // 00 + null, // 01 + null, // 02 + null, // 03 + null, // 04 + null, // 05 + null, // 06 + null, // 07 + null, // 08 + null, // 09 + null, // 0a + null, // 0b + null, // 0c + null, // 0d + null, // 0e + null, // 0f + null, // 10 + null, // 11 + null, // 12 + null, // 13 + null, // 14 + null, // 15 + null, // 16 + null, // 17 + null, // 18 + null, // 19 + null, // 1a + null, // 1b + null, // 1c + null, // 1d + null, // 1e + null, // 1f + "Spce", // 20 + "Bang", // 21 + "Quot", // 22 + "Hash", // 23 + "Dolr", // 24 + "Perc", // 25 + "And", // 26 + "Apos", // 27 + "LPar", // 28 + "RPar", // 29 + "Star", // 2a + "Plus", // 2b + "Comm", // 2c + "-", // 2d + "Stop", // 2e + "Slsh", // 2f + "0", // 30 + "1", // 31 + "2", // 32 + "3", // 33 + "4", // 34 + "5", // 35 + "6", // 36 + "7", // 37 + "8", // 38 + "9", // 39 + "Coln", // 3a + "SCln", // 3b + "LT", // 3c + "Eqls", // 3d + "GT", // 3e + "Ques", // 3f + "AT", // 40 + "A", // 41 + "B", // 42 + "C", // 43 + "D", // 44 + "E", // 45 + "F", // 46 + "G", // 47 + "H", // 48 + "I", // 49 + "J", // 4a + "K", // 4b + "L", // 4c + "M", // 4d + "N", // 4e + "O", // 4f + "P", // 50 + "Q", // 51 + "R", // 52 + "S", // 53 + "T", // 54 + "U", // 55 + "V", // 56 + "W", // 57 + "X", // 58 + "Y", // 59 + "Z", // 5a + "LSqB", // 5b + "Bash", // 5c + "RSqB", // 5d + "Xor", // 5e + "Unds", // 5f + "BQuo", // 60 + "a", // 61 + "b", // 62 + "c", // 63 + "d", // 64 + "e", // 65 + "f", // 66 + "g", // 67 + "h", // 68 + "i", // 69 + "j", // 6a + "k", // 6b + "l", // 6c + "m", // 6d + "n", // 6e + "o", // 6f + "p", // 70 + "q", // 71 + "r", // 72 + "s", // 73 + "t", // 74 + "u", // 75 + "v", // 76 + "w", // 77 + "x", // 78 + "y", // 79 + "z", // 7a + "LBra", // 7b + "Pipe", // 7c + "RBra", // 7d + "Tild", // 7e + null // 7f + }; + private static final Map asciiReadableEncodingDefaultMap = new HashMap<>(); - public static String[] asciiReadableEncodingDefault = new String[] { - null,// 00 - null,// 01 - null,// 02 - null,// 03 - null,// 04 - null,// 05 - null,// 06 - null,// 07 - null,// 08 - null,// 09 - null,// 0a - null,// 0b - null,// 0c - null,// 0d - null,// 0e - null,// 0f - null,// 10 - null,// 11 - null,// 12 - null,// 13 - null,// 14 - null,// 15 - null,// 16 - null,// 17 - null,// 18 - null,// 19 - null,// 1a - null,// 1b - null,// 1c - null,// 1d - null,// 1e - null,// 1f - "Spce",// 20 - "Bang",// 21 - "Quot",// 22 - "Hash",// 23 - "Dolr",// 24 - "Perc",// 25 - "And",// 26 - "Apos",// 27 - "LPar",// 28 - "RPar",// 29 - "Star",// 2a - "Plus",// 2b - "Comm",// 2c - "-",// 2d - "Stop",// 2e - "Slsh",// 2f - "0",// 30 - "1",// 31 - "2",// 32 - "3",// 33 - "4",// 34 - "5",// 35 - "6",// 36 - "7",// 37 - "8",// 38 - "9",// 39 - "Coln",// 3a - "SCln",// 3b - "LT",// 3c - "Eqls",// 3d - "GT",// 3e - "Ques",// 3f - "AT",// 40 - "A",// 41 - "B",// 42 - "C",// 43 - "D",// 44 - "E",// 45 - "F",// 46 - "G",// 47 - "H",// 48 - "I",// 49 - "J",// 4a - "K",// 4b - "L",// 4c - "M",// 4d - "N",// 4e - "O",// 4f - "P",// 50 - "Q",// 51 - "R",// 52 - "S",// 53 - "T",// 54 - "U",// 55 - "V",// 56 - "W",// 57 - "X",// 58 - "Y",// 59 - "Z",// 5a - "LSqB",// 5b - "Bash",// 5c - "RSqB",// 5d - "Xor",// 5e - "Unds",// 5f - "BQuo",// 60 - "a",// 61 - "b",// 62 - "c",// 63 - "d",// 64 - "e",// 65 - "f",// 66 - "g",// 67 - "h",// 68 - "i",// 69 - "j",// 6a - "k",// 6b - "l",// 6c - "m",// 6d - "n",// 6e - "o",// 6f - "p",// 70 - "q",// 71 - "r",// 72 - "s",// 73 - "t",// 74 - "u",// 75 - "v",// 76 - "w",// 77 - "x",// 78 - "y",// 79 - "z",// 7a - "LBra",// 7b - "Pipe",// 7c - "RBra",// 7d - "Tild",// 7e - null// 7f - }; - private static final Map asciiReadableEncodingDefaultMap = new HashMap<>(); - static { - for (int i = 0; i < asciiReadableEncodingDefault.length; i++) - if (asciiReadableEncodingDefault[i] != null && asciiReadableEncodingDefault[i].length() > 1) - asciiReadableEncodingDefaultMap.put(asciiReadableEncodingDefault[i], (char) i); - } + static { + for (int i = 0; i < asciiReadableEncodingDefault.length; i++) + if (asciiReadableEncodingDefault[i] != null && asciiReadableEncodingDefault[i].length() > 1) + asciiReadableEncodingDefaultMap.put(asciiReadableEncodingDefault[i], (char) i); + } - /** - * Encode special characters depending on context. - * @param asciiReadableEncodingTable Override the default `asciiReadableEncodingDefault` depending on language requirements - * @param identChar which characters to replace - */ - public static void encodeStringToAlphanumeric(StringBuilder sb, String name, String[] asciiReadableEncodingTable, Pattern identChar, String escapeChar) { - boolean inIdent = true; - for (int i = 0; i < name.length(); i++) { - if (identChar.matcher(name).region(i, name.length()).lookingAt()) { - if (!inIdent) { - inIdent = true; - sb.append(escapeChar); - } - sb.append(name.charAt(i)); - } else { - if (inIdent) { - inIdent = false; - sb.append(escapeChar); - } - int charAt = name.charAt(i); - if (charAt < 128 && asciiReadableEncodingTable[charAt] != null) { - sb.append(asciiReadableEncodingTable[charAt]); - } else { - sb.append(String.format("%04x", charAt)); - } - } - } + /** + * Encode special characters depending on context. + * + * @param asciiReadableEncodingTable Override the default `asciiReadableEncodingDefault` depending + * on language requirements + * @param identChar which characters to replace + */ + public static void encodeStringToAlphanumeric( + StringBuilder sb, + String name, + String[] asciiReadableEncodingTable, + Pattern identChar, + String escapeChar) { + boolean inIdent = true; + for (int i = 0; i < name.length(); i++) { + if (identChar.matcher(name).region(i, name.length()).lookingAt()) { if (!inIdent) { - sb.append("'"); - } + inIdent = true; + sb.append(escapeChar); + } + sb.append(name.charAt(i)); + } else { + if (inIdent) { + inIdent = false; + sb.append(escapeChar); + } + int charAt = name.charAt(i); + if (charAt < 128 && asciiReadableEncodingTable[charAt] != null) { + sb.append(asciiReadableEncodingTable[charAt]); + } else { + sb.append(String.format("%04x", charAt)); + } + } + } + if (!inIdent) { + sb.append("'"); } + } - public static String decodeKoreString(String encoded) { - boolean quotedState = false; - StringBuilder resultedEncoding = new StringBuilder(); - for (int i = 0; i < encoded.length(); i++) { - if (quotedState) { - if (encoded.charAt(i) == '\'') { - quotedState = false; - } else { - resultedEncoding.append(asciiReadableEncodingDefaultMap.get(encoded.substring(i, i + 4))); - i += 3; - } - } else { - if (encoded.charAt(i) == '\'') { - quotedState = true; - } else - resultedEncoding.append(encoded.charAt(i)); - } - } - return resultedEncoding.toString(); + public static String decodeKoreString(String encoded) { + boolean quotedState = false; + StringBuilder resultedEncoding = new StringBuilder(); + for (int i = 0; i < encoded.length(); i++) { + if (quotedState) { + if (encoded.charAt(i) == '\'') { + quotedState = false; + } else { + resultedEncoding.append(asciiReadableEncodingDefaultMap.get(encoded.substring(i, i + 4))); + i += 3; + } + } else { + if (encoded.charAt(i) == '\'') { + quotedState = true; + } else resultedEncoding.append(encoded.charAt(i)); + } } + return resultedEncoding.toString(); + } - public static String[] splitOneDimensionalAtt(String att) { - String[] splitted = att.trim().split(","); - for (int i = 0; i < splitted.length; i++) { - splitted[i] = splitted[i].trim(); - } - return splitted; + public static String[] splitOneDimensionalAtt(String att) { + String[] splitted = att.trim().split(","); + for (int i = 0; i < splitted.length; i++) { + splitted[i] = splitted[i].trim(); } + return splitted; + } - public static String[][] splitTwoDimensionalAtt(String att) { - String[] parts = att.trim().split(";"); - String[][] splitted = new String[parts.length][]; - for (int i = 0; i < parts.length; i++) { - String[] subparts = splitOneDimensionalAtt(parts[i]); - splitted[i] = subparts; - } - return splitted; + public static String[][] splitTwoDimensionalAtt(String att) { + String[] parts = att.trim().split(";"); + String[][] splitted = new String[parts.length][]; + for (int i = 0; i < parts.length; i++) { + String[] subparts = splitOneDimensionalAtt(parts[i]); + splitted[i] = subparts; } + return splitted; + } } diff --git a/kore/src/main/java/org/kframework/utils/errorsystem/KEMException.java b/kore/src/main/java/org/kframework/utils/errorsystem/KEMException.java index db2ee4a320b..fcb85e7cd25 100644 --- a/kore/src/main/java/org/kframework/utils/errorsystem/KEMException.java +++ b/kore/src/main/java/org/kframework/utils/errorsystem/KEMException.java @@ -1,6 +1,7 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.errorsystem; +import java.util.Objects; import org.kframework.attributes.HasLocation; import org.kframework.attributes.Location; import org.kframework.attributes.Source; @@ -8,161 +9,231 @@ import org.kframework.utils.errorsystem.KException.ExceptionType; import org.kframework.utils.errorsystem.KException.KExceptionGroup; -import java.util.Objects; -import java.util.Optional; - /** * Thrown to indicate that the K Exception manager has terminated the application due to an error. * * @author dwightguth */ public class KEMException extends RuntimeException { - public static final int TERMINATED_WITH_ERRORS_EXIT_CODE = 113; - - public final KException exception; - - KEMException(KException e) { - super(e.toString(), e.getException()); - this.exception = e; - } - - KEMException(KException e, ExceptionType type) { - super(e.toString(), e.getException()); - this.exception = new KException(type, e.exceptionGroup, e.getMessage(), e.getSource(), e.getLocation(), e.getException()); - } - - public static KEMException debuggerError(String message) { - return create(ExceptionType.ERROR, KExceptionGroup.DEBUGGER, message, null, null, null); - } - - public static KEMException criticalError(String message) { - return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, null, null, null); - } - - public static KEMException criticalError(String message, Throwable e) { - return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, e, null, null); - } - - public static KEMException criticalError(String message, HasLocation node) { - return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public static KEMException criticalError(String message, Throwable e, HasLocation node) { - return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, e, node.location().orElse(null), node.source().orElse(null)); - } - - - public static KEMException criticalError(String message, Throwable e, Location loc, Source source) { - return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, e, loc, source); - } - - public static KEMException internalError(String message) { - return create(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, null, null, null); - } - - public static KEMException internalError(String message, Throwable e) { - return create(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, e, null, null); - } - - public static KEMException internalError(String message, HasLocation node) { - return create(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public static KEMException internalError(String message, Throwable e, HasLocation node) { - return create(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, e, node.location().orElse(null), node.source().orElse(null)); - } - - public static KEMException compilerError(String message) { - return create(ExceptionType.ERROR, KExceptionGroup.COMPILER, message, null, null, null); - } - - public static KEMException compilerError(String message, Throwable e) { - return create(ExceptionType.ERROR, KExceptionGroup.COMPILER, message, e, null, null); - } - - public static KEMException compilerError(String message, HasLocation node) { - return create(ExceptionType.ERROR, KExceptionGroup.COMPILER, message, null, node.location().orElse(null), node.source().orElse(null)); - } - - public static KEMException compilerError(String message, Throwable e, HasLocation node) { - return create(ExceptionType.ERROR, KExceptionGroup.COMPILER, message, e, node.location().orElse(null), node.source().orElse(null)); - } - - public static KEMException innerParserError(String message) { - return create(ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, null, null, null); - } - - public static KEMException innerParserError(String message, Source source, Location location) { - return create(ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, null, location, source); - } - - public static KEMException innerParserError(String message, Term t) { - return create(ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, null, t.location().orElse(null), t.source().orElse(null)); - } - - public static KEMException innerParserError(String message, Throwable e, Source source, Location location) { - return create(ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, e, location, source); - } - - public static KEMException outerParserError(String message) { - return create(ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, null, null, null); - } - - public static KEMException outerParserError(String message, Source source, Location location) { - return create(ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, null, location, source); - } - - public static KEMException outerParserError(String message, Throwable e, Source source, Location location) { - return create(ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, e, location, source); - } - - public static KEMException outerParserError(String message, Throwable e, Source source, Location location, boolean printException) { - return create(ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, e, location, source, printException); - } - - public static KEMException asError(KEMException warning) { - return new KEMException(warning.exception, ExceptionType.ERROR); - } - - public KEMException withLocation(Location loc, Source source) { - return create(this.exception.getType(), - exception.getExceptionGroup(), - exception.getMessage(), - exception.getException(), - loc, - source); - } - - @Override - public String getMessage() { - return exception.toString(); - } - - private static KEMException create(ExceptionType type, KExceptionGroup group, String message, - Throwable e, Location location, Source source) { - return new KEMException(new KException(type, group, message, source, location, e)); - } - - private static KEMException create(ExceptionType type, KExceptionGroup group, String message, - Throwable e, Location location, Source source, boolean printException) { - return new KEMException(new KException(type, group, message, source, location, e, printException)); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - KEMException that = (KEMException) o; - return Objects.equals(exception, that.exception); - } - - @Override - public int hashCode() { - return Objects.hash(exception); - } - - public KException getKException() { - return exception; - } - + public static final int TERMINATED_WITH_ERRORS_EXIT_CODE = 113; + + public final KException exception; + + KEMException(KException e) { + super(e.toString(), e.getException()); + this.exception = e; + } + + KEMException(KException e, ExceptionType type) { + super(e.toString(), e.getException()); + this.exception = + new KException( + type, + e.exceptionGroup, + e.getMessage(), + e.getSource(), + e.getLocation(), + e.getException()); + } + + public static KEMException debuggerError(String message) { + return create(ExceptionType.ERROR, KExceptionGroup.DEBUGGER, message, null, null, null); + } + + public static KEMException criticalError(String message) { + return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, null, null, null); + } + + public static KEMException criticalError(String message, Throwable e) { + return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, e, null, null); + } + + public static KEMException criticalError(String message, HasLocation node) { + return create( + ExceptionType.ERROR, + KExceptionGroup.CRITICAL, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public static KEMException criticalError(String message, Throwable e, HasLocation node) { + return create( + ExceptionType.ERROR, + KExceptionGroup.CRITICAL, + message, + e, + node.location().orElse(null), + node.source().orElse(null)); + } + + public static KEMException criticalError( + String message, Throwable e, Location loc, Source source) { + return create(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message, e, loc, source); + } + + public static KEMException internalError(String message) { + return create(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, null, null, null); + } + + public static KEMException internalError(String message, Throwable e) { + return create(ExceptionType.ERROR, KExceptionGroup.INTERNAL, message, e, null, null); + } + + public static KEMException internalError(String message, HasLocation node) { + return create( + ExceptionType.ERROR, + KExceptionGroup.INTERNAL, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public static KEMException internalError(String message, Throwable e, HasLocation node) { + return create( + ExceptionType.ERROR, + KExceptionGroup.INTERNAL, + message, + e, + node.location().orElse(null), + node.source().orElse(null)); + } + + public static KEMException compilerError(String message) { + return create(ExceptionType.ERROR, KExceptionGroup.COMPILER, message, null, null, null); + } + + public static KEMException compilerError(String message, Throwable e) { + return create(ExceptionType.ERROR, KExceptionGroup.COMPILER, message, e, null, null); + } + + public static KEMException compilerError(String message, HasLocation node) { + return create( + ExceptionType.ERROR, + KExceptionGroup.COMPILER, + message, + null, + node.location().orElse(null), + node.source().orElse(null)); + } + + public static KEMException compilerError(String message, Throwable e, HasLocation node) { + return create( + ExceptionType.ERROR, + KExceptionGroup.COMPILER, + message, + e, + node.location().orElse(null), + node.source().orElse(null)); + } + + public static KEMException innerParserError(String message) { + return create(ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, null, null, null); + } + + public static KEMException innerParserError(String message, Source source, Location location) { + return create( + ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, null, location, source); + } + + public static KEMException innerParserError(String message, Term t) { + return create( + ExceptionType.ERROR, + KExceptionGroup.INNER_PARSER, + message, + null, + t.location().orElse(null), + t.source().orElse(null)); + } + + public static KEMException innerParserError( + String message, Throwable e, Source source, Location location) { + return create(ExceptionType.ERROR, KExceptionGroup.INNER_PARSER, message, e, location, source); + } + + public static KEMException outerParserError(String message) { + return create(ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, null, null, null); + } + + public static KEMException outerParserError(String message, Source source, Location location) { + return create( + ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, null, location, source); + } + + public static KEMException outerParserError( + String message, Throwable e, Source source, Location location) { + return create(ExceptionType.ERROR, KExceptionGroup.OUTER_PARSER, message, e, location, source); + } + + public static KEMException outerParserError( + String message, Throwable e, Source source, Location location, boolean printException) { + return create( + ExceptionType.ERROR, + KExceptionGroup.OUTER_PARSER, + message, + e, + location, + source, + printException); + } + + public static KEMException asError(KEMException warning) { + return new KEMException(warning.exception, ExceptionType.ERROR); + } + + public KEMException withLocation(Location loc, Source source) { + return create( + this.exception.getType(), + exception.getExceptionGroup(), + exception.getMessage(), + exception.getException(), + loc, + source); + } + + @Override + public String getMessage() { + return exception.toString(); + } + + private static KEMException create( + ExceptionType type, + KExceptionGroup group, + String message, + Throwable e, + Location location, + Source source) { + return new KEMException(new KException(type, group, message, source, location, e)); + } + + private static KEMException create( + ExceptionType type, + KExceptionGroup group, + String message, + Throwable e, + Location location, + Source source, + boolean printException) { + return new KEMException( + new KException(type, group, message, source, location, e, printException)); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KEMException that = (KEMException) o; + return Objects.equals(exception, that.exception); + } + + @Override + public int hashCode() { + return Objects.hash(exception); + } + + public KException getKException() { + return exception; + } } diff --git a/kore/src/main/java/org/kframework/utils/errorsystem/KException.java b/kore/src/main/java/org/kframework/utils/errorsystem/KException.java index b36dd587828..7bc0a208eed 100755 --- a/kore/src/main/java/org/kframework/utils/errorsystem/KException.java +++ b/kore/src/main/java/org/kframework/utils/errorsystem/KException.java @@ -1,305 +1,333 @@ // Copyright (c) K Team. All Rights Reserved. package org.kframework.utils.errorsystem; -import org.apache.commons.lang3.StringUtils; -import org.kframework.attributes.HasLocation; -import org.kframework.attributes.Location; -import org.kframework.attributes.Source; - import java.io.Serializable; import java.nio.file.Files; import java.nio.file.Paths; import java.util.*; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.kframework.attributes.HasLocation; +import org.kframework.attributes.Location; +import org.kframework.attributes.Source; public class KException implements Serializable, HasLocation { - protected final ExceptionType type; - final KExceptionGroup exceptionGroup; - private final Source source; - private final Location location; - private final String message; - private final Throwable exception; - private final boolean printException; - private final String sourceText; - private final StringBuilder trace = new StringBuilder(); - - private static final Map labels; - static { - labels = new HashMap(); - labels.put(KExceptionGroup.COMPILER, "Compiler"); - labels.put(KExceptionGroup.OUTER_PARSER, "Outer Parser"); - labels.put(KExceptionGroup.INNER_PARSER, "Inner Parser"); - labels.put(KExceptionGroup.LISTS, "Lists"); - labels.put(KExceptionGroup.INTERNAL, "Internal"); - labels.put(KExceptionGroup.CRITICAL, "Critical"); - labels.put(KExceptionGroup.DEBUGGER, "Debugger"); - labels.put(KExceptionGroup.PROVER, "Prover"); + protected final ExceptionType type; + final KExceptionGroup exceptionGroup; + private final Source source; + private final Location location; + private final String message; + private final Throwable exception; + private final boolean printException; + private final String sourceText; + private final StringBuilder trace = new StringBuilder(); + + private static final Map labels; + + static { + labels = new HashMap(); + labels.put(KExceptionGroup.COMPILER, "Compiler"); + labels.put(KExceptionGroup.OUTER_PARSER, "Outer Parser"); + labels.put(KExceptionGroup.INNER_PARSER, "Inner Parser"); + labels.put(KExceptionGroup.LISTS, "Lists"); + labels.put(KExceptionGroup.INTERNAL, "Internal"); + labels.put(KExceptionGroup.CRITICAL, "Critical"); + labels.put(KExceptionGroup.DEBUGGER, "Debugger"); + labels.put(KExceptionGroup.PROVER, "Prover"); + } + + public static KException criticalError(String message) { + return new KException(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message); + } + + public KException(ExceptionType type, KExceptionGroup label, String message) { + this(type, label, message, null, null, null); + } + + public KException(ExceptionType type, KExceptionGroup label, String message, Throwable e) { + this(type, label, message, null, null, e); + } + + public KException( + ExceptionType type, KExceptionGroup label, String message, Source source, Location location) { + this(type, label, message, source, location, null, true); + } + + public KException( + ExceptionType type, + KExceptionGroup label, + String message, + Source source, + Location location, + Throwable exception) { + this(type, label, message, source, location, exception, true); + } + + public KException( + ExceptionType type, + KExceptionGroup label, + String message, + Source source, + Location location, + Throwable exception, + boolean printException) { + super(); + this.type = type; + this.exceptionGroup = label; + this.message = message; + this.source = source; + this.location = location; + this.exception = exception; + this.sourceText = getSourceLineText(); + this.printException = printException; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + KException that = (KException) o; + return type == that.type + && exceptionGroup == that.exceptionGroup + && Objects.equals(source, that.source) + && Objects.equals(location, that.location) + && Objects.equals(message, that.message) + && Objects.equals(exception, that.exception) + && Objects.equals(trace.toString(), that.trace.toString()); + } + + @Override + public int hashCode() { + return Objects.hash( + type, exceptionGroup, source, location, message, exception, trace.toString()); + } + + @Override + public Optional location() { + return Optional.ofNullable(location); + } + + @Override + public Optional source() { + return Optional.ofNullable(source); + } + + public enum KExceptionGroup { + OUTER_PARSER, + INNER_PARSER, + COMPILER, + LISTS, + INTERNAL, + CRITICAL, + DEBUGGER, + PROVER + } + + public enum ExceptionType { + ERROR, + NON_EXHAUSTIVE_MATCH, + UNDELETED_TEMP_DIR, + MISSING_SYNTAX_MODULE, + INVALID_EXIT_CODE, + INVALID_CONFIG_VAR, + INVALID_ASSOCIATIVITY, + FUTURE_ERROR, + UNUSED_VAR, + PROOF_LINT, + NON_LR_GRAMMAR, + IGNORED_ATTRIBUTE, + REMOVED_ANYWHERE, + DEPRECATED_DIRECTORY_FLAG, + MISSING_HOOK, + FIRST_HIDDEN, // warnings below here are hidden by default + USELESS_RULE, + UNRESOLVED_FUNCTION_SYMBOL, + MALFORMED_MARKDOWN, + INVALIDATED_CACHE, + UNUSED_SYMBOL, + } + + @Override + public String toString() { + return toString(false); + } + + public String toString(boolean verbose) { + return "[" + + (type == ExceptionType.ERROR ? "Error" : "Warning") + + "] " + + labels.get(exceptionGroup) + + ": " + + message + + (exception != null && printException + ? " (" + exception.getClass().getSimpleName() + ": " + exception.getMessage() + ")" + : "") + + trace.toString() + + traceTail() + + (source == null ? "" : "\n\t" + source) + + (location == null ? "" : "\n\t" + location) + + (sourceText == null ? "" : sourceText); + } + + public String getMessage() { + return message; + } + + public Throwable getException() { + return exception; + } + + public ExceptionType getType() { + return type; + } + + private String traceTail() { + if (identicalFrames > 1) { + return " * " + identicalFrames; } - - public static KException criticalError(String message) { - return new KException(ExceptionType.ERROR, KExceptionGroup.CRITICAL, message); + return ""; + } + + private int frames = 0; + private int identicalFrames = 1; + private CharSequence lastFrame; + + public void addTraceFrame(CharSequence frame) { + if (frames < 1024) { + if (frame.equals(lastFrame)) { + identicalFrames++; + } else { + if (identicalFrames > 1) { + trace.append(" * ").append(identicalFrames); + identicalFrames = 1; + } + trace.append("\n ").append(frame); + lastFrame = frame; + frames++; + } } + } - public KException(ExceptionType type, KExceptionGroup label, String message) { - this(type, label, message, null, null, null); - } + public void formatTraceFrame(String format, Object... args) { + StringBuilder sb = new StringBuilder(); + new Formatter(sb).format(format, args); + addTraceFrame(sb); + } - public KException(ExceptionType type, KExceptionGroup label, String message, Throwable e) { - this(type, label, message, null, null, e); - } + private boolean locationIsValid() { + return (location != null && location.startLine() > 0 && location.endLine() > 0); + } - public KException(ExceptionType type, KExceptionGroup label, String message, Source source, Location location) { - this(type, label, message, source, location, null, true); + private String getSourceLineText() { + if (!locationIsValid()) { + return null; } - - public KException(ExceptionType type, KExceptionGroup label, String message, Source source, Location location, Throwable exception) { - this(type, label, message, source, location, exception, true); + try { + String sourceLineText; + int errorLineCount = location.endLine() - location.startLine() + 1; + + if (errorLineCount == 1) { + sourceLineText = getSourceLine(); + } else if (errorLineCount > 1) { + // generate line info for multiple lines + sourceLineText = getSourceLine(errorLineCount); + } else { + sourceLineText = null; + } + return sourceLineText; + } catch (java.io.IOException e) { + return null; } + } - public KException( - ExceptionType type, - KExceptionGroup label, - String message, - Source source, - Location location, - Throwable exception, - boolean printException) { - super(); - this.type = type; - this.exceptionGroup = label; - this.message = message; - this.source = source; - this.location = location; - this.exception = exception; - this.sourceText = getSourceLineText(); - this.printException = printException; - } + private String getSourceLine() throws java.io.IOException { + int lineNumberPadding = String.valueOf(location.startLine()).length(); + StringBuilder sourceText = new StringBuilder(); - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - KException that = (KException) o; - return type == that.type && - exceptionGroup == that.exceptionGroup && - Objects.equals(source, that.source) && - Objects.equals(location, that.location) && - Objects.equals(message, that.message) && - Objects.equals(exception, that.exception) && - Objects.equals(trace.toString(), that.trace.toString()); - } + sourceText.append("\n\t"); + sourceText.append(location.startLine() + " |\t"); + Stream lines = Files.lines(Paths.get(getSource().source())); + sourceText.append((String) lines.skip(location.startLine() - 1).findFirst().orElse("")); - @Override - public int hashCode() { - return Objects.hash(type, exceptionGroup, source, location, message, exception, trace.toString()); - } + /* generate a line below the source file that underlines the location of the error */ - @Override - public Optional location() { - return Optional.ofNullable(location); + sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " .\t"); + sourceText.append(StringUtils.repeat(' ', location.startColumn() - 1)); + sourceText.append('^'); + if (location.endColumn() > location.startColumn()) { + sourceText.append(StringUtils.repeat('~', location.endColumn() - location.startColumn() - 1)); } - @Override - public Optional source() { - return Optional.ofNullable(source); - } + return sourceText.toString(); + } - public enum KExceptionGroup { - OUTER_PARSER, INNER_PARSER, COMPILER, LISTS, INTERNAL, CRITICAL, DEBUGGER, PROVER - } + private String getSourceLine(int errorLineCount) throws java.io.IOException { - public enum ExceptionType { - ERROR, - NON_EXHAUSTIVE_MATCH, - UNDELETED_TEMP_DIR, - MISSING_SYNTAX_MODULE, - INVALID_EXIT_CODE, - INVALID_CONFIG_VAR, - INVALID_ASSOCIATIVITY, - FUTURE_ERROR, - UNUSED_VAR, - PROOF_LINT, - NON_LR_GRAMMAR, - IGNORED_ATTRIBUTE, - REMOVED_ANYWHERE, - DEPRECATED_DIRECTORY_FLAG, - MISSING_HOOK, - FIRST_HIDDEN, // warnings below here are hidden by default - USELESS_RULE, - UNRESOLVED_FUNCTION_SYMBOL, - MALFORMED_MARKDOWN, - INVALIDATED_CACHE, - UNUSED_SYMBOL, - } + /* The line number padding is based on the endline because this is the largest number of padding needed */ - @Override - public String toString() { - return toString(false); - } + int lineNumberPadding = String.valueOf(location.endLine()).length(); + StringBuilder sourceText = new StringBuilder(); - public String toString(boolean verbose) { - return "[" + (type == ExceptionType.ERROR ? "Error" : "Warning") + "] " + labels.get(exceptionGroup) + ": " + message - + (exception != null && printException ? " (" + exception.getClass().getSimpleName() + ": " + exception.getMessage() + ")" : "") - + trace.toString() + traceTail() - + (source == null ? "" : "\n\t" + source) - + (location == null ? "" : "\n\t" + location) - + (sourceText == null ? "" : sourceText); - } + /* generate a line above the source file that indicates the location of the error */ - public String getMessage() { - return message; - } + sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " .\t"); + sourceText.append(StringUtils.repeat(' ', location.startColumn() - 1)); + sourceText.append('v'); - public Throwable getException() { - return exception; - } + Stream lines = Files.lines(Paths.get(getSource().source())); + String firstLine = (String) lines.skip(location.startLine() - 1).findFirst().get(); - public ExceptionType getType() { - return type; + if (firstLine.length() - location.startColumn() > 0) { + sourceText.append(StringUtils.repeat('~', firstLine.length() - location.startColumn())); } - - private String traceTail() { - if (identicalFrames > 1) { - return " * " + identicalFrames; - } - return ""; + sourceText.append("\n\t"); + int padding = + String.valueOf(location.endLine()).length() - String.valueOf(location.startLine()).length(); + sourceText.append(StringUtils.repeat(' ', padding) + location.startLine() + " |\t"); + sourceText.append(firstLine); + + if (errorLineCount == 3) { + sourceText.append("\n\t"); + int padding2 = + String.valueOf(location.endLine()).length() + - String.valueOf(location.startLine() + 1).length(); + sourceText.append(StringUtils.repeat(' ', padding2) + (location.startLine() + 1) + " |\t"); + Stream secondline = Files.lines(Paths.get(getSource().source())); + sourceText.append((String) secondline.skip(location.startLine()).findFirst().get()); + } else if (errorLineCount > 3) { + /* + * If the error message spans more than 3 lines, indicate this line with "...". + * For errors that span many lines, this is sufficient to get the point across. + */ + sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " |\t\t..."); } - private int frames = 0; - private int identicalFrames = 1; - private CharSequence lastFrame; - public void addTraceFrame(CharSequence frame) { - if (frames < 1024) { - if (frame.equals(lastFrame)) { - identicalFrames++; - } else { - if (identicalFrames > 1) { - trace.append(" * ").append(identicalFrames); - identicalFrames = 1; - } - trace.append("\n ").append(frame); - lastFrame = frame; - frames++; - } - } - } + sourceText.append("\n\t"); + sourceText.append(location.endLine() + " |\t"); + String lastLine = + Files.lines(Paths.get(getSource().source())).skip(location.endLine() - 1).findFirst().get(); + int firstCharIndex = lastLine.indexOf(lastLine.trim()); + sourceText.append(lastLine); - public void formatTraceFrame(String format, Object... args) { - StringBuilder sb = new StringBuilder(); - new Formatter(sb).format(format, args); - addTraceFrame(sb); - } - - private boolean locationIsValid() { - return (location != null && location.startLine() > 0 && location.endLine() > 0); - } - - private String getSourceLineText() { - if (!locationIsValid()) { - return null; - } - try { - String sourceLineText; - int errorLineCount = location.endLine() - location.startLine() + 1; - - if (errorLineCount == 1) { - sourceLineText = getSourceLine(); - } else if (errorLineCount > 1) { - // generate line info for multiple lines - sourceLineText = getSourceLine(errorLineCount); - } else { - sourceLineText = null; - } - return sourceLineText; - } catch (java.io.IOException e) { - return null; - } - } - - private String getSourceLine() throws java.io.IOException { - int lineNumberPadding = String.valueOf(location.startLine()).length(); - StringBuilder sourceText = new StringBuilder(); - - sourceText.append("\n\t"); - sourceText.append(location.startLine() + " |\t"); - Stream lines = Files.lines(Paths.get(getSource().source())); - sourceText.append((String) lines.skip(location.startLine() - 1).findFirst().orElse("")); - - /* generate a line below the source file that underlines the location of the error */ - - sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " .\t"); - sourceText.append(StringUtils.repeat(' ', location.startColumn() - 1)); - sourceText.append('^'); - if (location.endColumn() > location.startColumn()) { - sourceText.append(StringUtils.repeat('~', location.endColumn() - location.startColumn() - 1)); - } - - return sourceText.toString(); - } - - private String getSourceLine(int errorLineCount) throws java.io.IOException { + /* generate a line below the source file that underlines the location of the error */ - /* The line number padding is based on the endline because this is the largest number of padding needed */ + sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " .\t"); + sourceText.append(StringUtils.repeat(' ', firstCharIndex)); + sourceText.append(StringUtils.repeat('~', location.endColumn() - firstCharIndex - 2)); + sourceText.append('^'); - int lineNumberPadding = String.valueOf(location.endLine()).length(); - StringBuilder sourceText = new StringBuilder(); + return sourceText.toString(); + } - /* generate a line above the source file that indicates the location of the error */ + public Source getSource() { + return source; + } - sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " .\t"); - sourceText.append(StringUtils.repeat(' ', location.startColumn() - 1)); - sourceText.append('v'); + public Location getLocation() { + return location; + } - Stream lines = Files.lines(Paths.get(getSource().source())); - String firstLine = (String) lines.skip(location.startLine() - 1).findFirst().get(); - - if (firstLine.length() - location.startColumn() > 0) { - sourceText.append(StringUtils.repeat('~', firstLine.length() - location.startColumn())); - } - sourceText.append("\n\t"); - int padding = String.valueOf(location.endLine()).length() - String.valueOf(location.startLine()).length(); - sourceText.append(StringUtils.repeat(' ', padding) + location.startLine() + " |\t"); - sourceText.append(firstLine); - - if (errorLineCount == 3) { - sourceText.append("\n\t"); - int padding2 = String.valueOf(location.endLine()).length() - String.valueOf(location.startLine() + 1).length(); - sourceText.append(StringUtils.repeat(' ', padding2) + (location.startLine() + 1) + " |\t"); - Stream secondline = Files.lines(Paths.get(getSource().source())); - sourceText.append((String) secondline.skip(location.startLine()).findFirst().get()); - } else if (errorLineCount > 3) { - /* - * If the error message spans more than 3 lines, indicate this line with "...". - * For errors that span many lines, this is sufficient to get the point across. - */ - sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " |\t\t..."); - } - - sourceText.append("\n\t"); - sourceText.append(location.endLine() + " |\t"); - String lastLine = Files.lines(Paths.get(getSource().source())).skip(location.endLine() -1).findFirst().get(); - int firstCharIndex = lastLine.indexOf(lastLine.trim()); - sourceText.append(lastLine); - - /* generate a line below the source file that underlines the location of the error */ - - sourceText.append("\n\t" + StringUtils.repeat(' ', lineNumberPadding) + " .\t"); - sourceText.append(StringUtils.repeat(' ', firstCharIndex)); - sourceText.append(StringUtils.repeat('~', location.endColumn() - firstCharIndex - 2)); - sourceText.append('^'); - - return sourceText.toString(); - } - - public Source getSource() { - return source; - } - - public Location getLocation() { - return location; - } - - public KExceptionGroup getExceptionGroup() { - return exceptionGroup; - } + public KExceptionGroup getExceptionGroup() { + return exceptionGroup; + } } diff --git a/kore/src/test/java/org/kframework/CollectionsTest.java b/kore/src/test/java/org/kframework/CollectionsTest.java index 0f6beaf0a08..96a1bdcc39e 100644 --- a/kore/src/test/java/org/kframework/CollectionsTest.java +++ b/kore/src/test/java/org/kframework/CollectionsTest.java @@ -2,51 +2,49 @@ package org.kframework; +import static org.junit.Assert.*; +import static org.kframework.Collections.*; +import static org.kframework.Collections.List; + +import java.util.stream.Stream; import org.junit.Test; import scala.collection.Set; import scala.collection.immutable.List; -import java.util.stream.Stream; - -import static org.junit.Assert.*; -import static org.kframework.Collections.List; -import static org.kframework.Collections.*; - public class CollectionsTest { - @Test - public void testList() { - // creating a List - List aList = List(1, 2, 3); - - // getting a Stream from a list - Stream s = stream(aList); + @Test + public void testList() { + // creating a List + List aList = List(1, 2, 3); - // usual Java 8 manipulation - Stream l = s.map(x -> x.toString()); + // getting a Stream from a list + Stream s = stream(aList); - // and back to an immutable List - List collectedList = l.collect(toList()); + // usual Java 8 manipulation + Stream l = s.map(x -> x.toString()); - // which has the expected value - assertEquals(List("1", "2", "3"), collectedList); - } + // and back to an immutable List + List collectedList = l.collect(toList()); - @Test - public void testSet() { - // creating a Set - Set aList = Set(1, 2, 3); + // which has the expected value + assertEquals(List("1", "2", "3"), collectedList); + } - // getting a Stream from a Set - Stream s = stream(aList); + @Test + public void testSet() { + // creating a Set + Set aList = Set(1, 2, 3); - // usual Java 8 manipulation - Stream l = s.map(x -> x / 2); + // getting a Stream from a Set + Stream s = stream(aList); - // and back to an immutable Set - Set collectedList = l.collect(toSet()); + // usual Java 8 manipulation + Stream l = s.map(x -> x / 2); - // which has the expected value - assertEquals(Set(0, 1), collectedList); - } + // and back to an immutable Set + Set collectedList = l.collect(toSet()); + // which has the expected value + assertEquals(Set(0, 1), collectedList); + } } diff --git a/kore/src/test/java/org/kframework/kore/InterfaceTest.java b/kore/src/test/java/org/kframework/kore/InterfaceTest.java index a36ea1faee9..f1bf71b747f 100644 --- a/kore/src/test/java/org/kframework/kore/InterfaceTest.java +++ b/kore/src/test/java/org/kframework/kore/InterfaceTest.java @@ -2,41 +2,44 @@ package org.kframework.kore; -import org.junit.Test; -import org.kframework.builtin.Sorts; - import static org.junit.Assert.*; -import static org.kframework.kore.KORE.*; import static org.kframework.Collections.*; +import static org.kframework.kore.KORE.*; + +import org.junit.Test; +import org.kframework.builtin.Sorts; public class InterfaceTest { - @Test - public void example() { - // Creating "A + 0 => A" programmatically - - KRewrite k = KRewrite( - KApply(KLabel("_+_"), KVariable("A"), KToken("0", Sort("Int"))), - KVariable("A")); - - // Navigating it - KLabel theLabel = ((KApply) k.left()).klabel(); - theLabel.name(); - } - - @Test - public void kListIsAssociative() { - // assertEquals(KList(KToken(Sorts.Int(), "1"), KToken(Sorts.Int(), "2")), KList(KToken(Sorts.Int(), "1"), KList(KToken(Sorts.Int(), "2")))); - } - - @Test - public void kSeqIsAssociative() { - assertEquals(KSequence(Seq(KToken("1", Sorts.Int()), KToken("2", Sorts.Int()))), KSequence(Seq(KToken("1", Sorts.Int()), KSequence(Seq(KToken("2", Sorts.Int())))))); - } - -// @Test -// public void manipulatingKSeq() { -// KSequence l = stream(KSequence(KToken("1", Sorts.Int()), KToken("2", Sorts.Int()))).map(x -> KToken("3", Sorts.Int())).collect(toKSequence()); -// assertEquals(KSequence(KToken("3", Sorts.Int()), KToken("3", Sorts.Int())), l); -// } + @Test + public void example() { + // Creating "A + 0 => A" programmatically + + KRewrite k = + KRewrite(KApply(KLabel("_+_"), KVariable("A"), KToken("0", Sort("Int"))), KVariable("A")); + + // Navigating it + KLabel theLabel = ((KApply) k.left()).klabel(); + theLabel.name(); + } + + @Test + public void kListIsAssociative() { + // assertEquals(KList(KToken(Sorts.Int(), "1"), KToken(Sorts.Int(), "2")), + // KList(KToken(Sorts.Int(), "1"), KList(KToken(Sorts.Int(), "2")))); + } + + @Test + public void kSeqIsAssociative() { + assertEquals( + KSequence(Seq(KToken("1", Sorts.Int()), KToken("2", Sorts.Int()))), + KSequence(Seq(KToken("1", Sorts.Int()), KSequence(Seq(KToken("2", Sorts.Int())))))); + } + + // @Test + // public void manipulatingKSeq() { + // KSequence l = stream(KSequence(KToken("1", Sorts.Int()), KToken("2", + // Sorts.Int()))).map(x -> KToken("3", Sorts.Int())).collect(toKSequence()); + // assertEquals(KSequence(KToken("3", Sorts.Int()), KToken("3", Sorts.Int())), l); + // } } diff --git a/kore/src/test/java/org/kframework/kore/VisitorTest.java b/kore/src/test/java/org/kframework/kore/VisitorTest.java index f81d062539e..2b35ec29816 100644 --- a/kore/src/test/java/org/kframework/kore/VisitorTest.java +++ b/kore/src/test/java/org/kframework/kore/VisitorTest.java @@ -5,78 +5,76 @@ import static org.junit.Assert.*; import static org.kframework.kore.KORE.*; -import org.junit.Test; - import java.util.List; import java.util.stream.Collectors; +import org.junit.Test; public class VisitorTest { - class FooTransformer extends TransformK { - - @Override - public K apply(KToken k) { - return KVariable("T"); - } - - @Override - public K apply(KVariable k) { - return k; - } - - @Override - public K apply(KSequence k) { - List newItems = k.items().stream().map(this).collect(Collectors.toList()); - return KORE.KSequence(newItems, k.att()); - } - - @Override - public K apply(InjectedKLabel k) { - return k; - } - - } - - @Test - public void testTopLevel() { - FooTransformer fooTransformer = new FooTransformer(); - K t = fooTransformer.apply(KToken("bla", Sort("foo"))); - - assertEquals(KVariable("T"), t); - } + class FooTransformer extends TransformK { - @Test - public void testTopLevelNoTransoformation() { - FooTransformer fooTransformer = new FooTransformer(); - KVariable term = KVariable("X"); - K t = fooTransformer.apply(term); - - assertEquals(term, t); + @Override + public K apply(KToken k) { + return KVariable("T"); } - @Test - public void testGenericK() { - FooTransformer fooTransformer = new FooTransformer(); - K term = KVariable("X"); - K t = fooTransformer.apply(term); - - assertEquals(term, t); + @Override + public K apply(KVariable k) { + return k; } - @Test - public void testTopLevelNoTransoformationOnCollection() { - FooTransformer fooTransformer = new FooTransformer(); - KRewrite term = KRewrite(KVariable("X"), KVariable("Y")); - KRewrite t = (KRewrite) fooTransformer.apply(term); - - assertEquals(term, t); + @Override + public K apply(KSequence k) { + List newItems = k.items().stream().map(this).collect(Collectors.toList()); + return KORE.KSequence(newItems, k.att()); } - @Test - public void testNested() { - FooTransformer fooTransformer = new FooTransformer(); - KRewrite t = (KRewrite) fooTransformer.apply(KRewrite(KToken("bla", Sort("foo")), - KVariable("U"))); - - assertEquals(KRewrite(KVariable("T"), KVariable("U")), t); + @Override + public K apply(InjectedKLabel k) { + return k; } + } + + @Test + public void testTopLevel() { + FooTransformer fooTransformer = new FooTransformer(); + K t = fooTransformer.apply(KToken("bla", Sort("foo"))); + + assertEquals(KVariable("T"), t); + } + + @Test + public void testTopLevelNoTransoformation() { + FooTransformer fooTransformer = new FooTransformer(); + KVariable term = KVariable("X"); + K t = fooTransformer.apply(term); + + assertEquals(term, t); + } + + @Test + public void testGenericK() { + FooTransformer fooTransformer = new FooTransformer(); + K term = KVariable("X"); + K t = fooTransformer.apply(term); + + assertEquals(term, t); + } + + @Test + public void testTopLevelNoTransoformationOnCollection() { + FooTransformer fooTransformer = new FooTransformer(); + KRewrite term = KRewrite(KVariable("X"), KVariable("Y")); + KRewrite t = (KRewrite) fooTransformer.apply(term); + + assertEquals(term, t); + } + + @Test + public void testNested() { + FooTransformer fooTransformer = new FooTransformer(); + KRewrite t = + (KRewrite) fooTransformer.apply(KRewrite(KToken("bla", Sort("foo")), KVariable("U"))); + + assertEquals(KRewrite(KVariable("T"), KVariable("U")), t); + } } diff --git a/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackend.java b/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackend.java index 2e0e4b1c692..3d0ad8fa45f 100644 --- a/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackend.java +++ b/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackend.java @@ -2,179 +2,183 @@ package org.kframework.backend.llvm; import com.google.inject.Inject; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.mutable.MutableInt; import org.kframework.attributes.Att; -import org.kframework.backend.llvm.matching.Matching; import org.kframework.backend.kore.KoreBackend; +import org.kframework.backend.llvm.matching.Matching; import org.kframework.compile.Backend; -import org.kframework.kompile.CompiledDefinition; import org.kframework.kompile.KompileOptions; import org.kframework.main.GlobalOptions; import org.kframework.main.Tool; import org.kframework.utils.Stopwatch; -import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.errorsystem.KEMException; import org.kframework.utils.errorsystem.KException.ExceptionType; +import org.kframework.utils.errorsystem.KExceptionManager; import org.kframework.utils.file.FileUtil; -import java.io.File; -import java.io.IOException; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; - public class LLVMBackend extends KoreBackend { - private final GlobalOptions globalOptions; - private final LLVMKompileOptions options; - private final KExceptionManager kem; - private final KompileOptions kompileOptions; - private final Tool tool; - - @Inject - public LLVMBackend( - KompileOptions kompileOptions, - GlobalOptions globalOptions, - FileUtil files, - KExceptionManager kem, - LLVMKompileOptions options, - Tool tool) { - super(kompileOptions, files, kem, tool); - this.globalOptions = globalOptions; - this.options = options; - this.kompileOptions = kompileOptions; - this.kem = kem; - this.tool = tool; - } - - - @Override - public void accept(Backend.Holder h) { - Stopwatch sw = new Stopwatch(globalOptions); - String kore = getKompiledString(h.def, true); - h.def = null; - files.saveToKompiled("definition.kore", kore); - sw.printIntermediate(" Print definition.kore"); - FileUtils.deleteQuietly(files.resolveKompiled("dt")); - MutableInt warnings = new MutableInt(); - boolean optimize = kompileOptions.optimize1 || kompileOptions.optimize2 || kompileOptions.optimize3; - Matching.writeDecisionTreeToFile( - files.resolveKompiled("definition.kore"), - options.heuristic, - files.resolveKompiled("dt"), - Matching.getThreshold(getThreshold()), - !optimize, - globalOptions.includesExceptionType(ExceptionType.USELESS_RULE), - options.enableSearch, - ex -> { + private final GlobalOptions globalOptions; + private final LLVMKompileOptions options; + private final KExceptionManager kem; + private final KompileOptions kompileOptions; + private final Tool tool; + + @Inject + public LLVMBackend( + KompileOptions kompileOptions, + GlobalOptions globalOptions, + FileUtil files, + KExceptionManager kem, + LLVMKompileOptions options, + Tool tool) { + super(kompileOptions, files, kem, tool); + this.globalOptions = globalOptions; + this.options = options; + this.kompileOptions = kompileOptions; + this.kem = kem; + this.tool = tool; + } + + @Override + public void accept(Backend.Holder h) { + Stopwatch sw = new Stopwatch(globalOptions); + String kore = getKompiledString(h.def, true); + h.def = null; + files.saveToKompiled("definition.kore", kore); + sw.printIntermediate(" Print definition.kore"); + FileUtils.deleteQuietly(files.resolveKompiled("dt")); + MutableInt warnings = new MutableInt(); + boolean optimize = + kompileOptions.optimize1 || kompileOptions.optimize2 || kompileOptions.optimize3; + Matching.writeDecisionTreeToFile( + files.resolveKompiled("definition.kore"), + options.heuristic, + files.resolveKompiled("dt"), + Matching.getThreshold(getThreshold()), + !optimize, + globalOptions.includesExceptionType(ExceptionType.USELESS_RULE), + options.enableSearch, + ex -> { kem.addKException(ex); if (globalOptions.includesExceptionType(ex.getType())) { - warnings.increment(); + warnings.increment(); } return null; }); - sw.printIntermediate(" Write decision tree"); - if (warnings.intValue() > 0 && kem.options.warnings2errors) { - throw KEMException.compilerError("Had " + warnings.intValue() + " pattern matching errors."); - } - if (options.noLLVMKompile) { - return; - } - if (options.enableSearch && options.llvmKompileOutput != null) { - throw KEMException.criticalError("Can't use --llvm-kompile-output with --enable-search."); - } - if (options.llvmKompileType.equals("python") && options.llvmKompileOutput != null) { - throw KEMException.criticalError("Can't use --llvm-kompile-output with --llvm-kompile-type python"); - } - String llvmType = switch (options.llvmKompileType) { - case "main", "search", "static", "library", "python", "c" -> options.llvmKompileType; - default -> throw KEMException.criticalError("Non-valid argument for --llvm-kompile-type: " + options.llvmKompileType + ". Expected [main|search|library|static|python|c]"); + sw.printIntermediate(" Write decision tree"); + if (warnings.intValue() > 0 && kem.options.warnings2errors) { + throw KEMException.compilerError("Had " + warnings.intValue() + " pattern matching errors."); + } + if (options.noLLVMKompile) { + return; + } + if (options.enableSearch && options.llvmKompileOutput != null) { + throw KEMException.criticalError("Can't use --llvm-kompile-output with --enable-search."); + } + if (options.llvmKompileType.equals("python") && options.llvmKompileOutput != null) { + throw KEMException.criticalError( + "Can't use --llvm-kompile-output with --llvm-kompile-type python"); + } + String llvmType = + switch (options.llvmKompileType) { + case "main", "search", "static", "library", "python", "c" -> options.llvmKompileType; + default -> throw KEMException.criticalError( + "Non-valid argument for --llvm-kompile-type: " + + options.llvmKompileType + + ". Expected [main|search|library|static|python|c]"); }; - String llvmOutput = "interpreter"; - if (options.llvmKompileOutput != null) { - llvmOutput = options.llvmKompileOutput; - } + String llvmOutput = "interpreter"; + if (options.llvmKompileOutput != null) { + llvmOutput = options.llvmKompileOutput; + } - if (options.llvmKompileType.equals("python")) { - llvmOutput = null; - } + if (options.llvmKompileType.equals("python")) { + llvmOutput = null; + } - llvmKompile(llvmType, llvmOutput); + llvmKompile(llvmType, llvmOutput); - if (options.enableSearch) { - llvmKompile("search", "search"); - } + if (options.enableSearch) { + llvmKompile("search", "search"); } - - private void llvmKompile(String type, String executable) { - Stopwatch sw = new Stopwatch(globalOptions); - ProcessBuilder pb = files.getProcessBuilder(); - List args = new ArrayList<>(); - - try { - args.add("llvm-kompile"); - args.add(files.resolveKompiled("definition.kore").getCanonicalPath()); - args.add(files.resolveKompiled("dt").getCanonicalPath()); - args.add(type); - - // Arguments after this point are passed on to Clang. - args.add("--"); - - if (options.debug) { - args.add("-g"); - args.add("-O1"); - } - - // For Python bindings, we explicitly leave this unset so that python3-config - // can decide the proper filename. - if (executable != null) { - args.add("-o"); - - File outputFile = new File(executable); - if(!new File(executable).isAbsolute()) { - outputFile = files.resolveKompiled(executable); - } - - args.add(outputFile.getCanonicalPath()); - } - - if (!options.debug) { - if (kompileOptions.optimize1) args.add("-O1"); - if (kompileOptions.optimize2) args.add("-O2"); - if (kompileOptions.optimize3) args.add("-O2"); // clang -O3 does not make the llvm backend any faster - } - - args.addAll(options.ccopts); - - if (globalOptions.verbose) { - System.out.println(" \u250cExecuting: " + String.join(" ", args)); - } - - Process p = pb.command(args).inheritIO().start(); - int exit = p.waitFor(); - if (exit != 0) { - throw KEMException.criticalError("llvm-kompile returned nonzero exit code: " + exit + "\nExamine output to see errors."); - } - } catch (IOException | InterruptedException e) { - throw KEMException.criticalError("Error with I/O while executing llvm-kompile", e); + } + + private void llvmKompile(String type, String executable) { + Stopwatch sw = new Stopwatch(globalOptions); + ProcessBuilder pb = files.getProcessBuilder(); + List args = new ArrayList<>(); + + try { + args.add("llvm-kompile"); + args.add(files.resolveKompiled("definition.kore").getCanonicalPath()); + args.add(files.resolveKompiled("dt").getCanonicalPath()); + args.add(type); + + // Arguments after this point are passed on to Clang. + args.add("--"); + + if (options.debug) { + args.add("-g"); + args.add("-O1"); + } + + // For Python bindings, we explicitly leave this unset so that python3-config + // can decide the proper filename. + if (executable != null) { + args.add("-o"); + + File outputFile = new File(executable); + if (!new File(executable).isAbsolute()) { + outputFile = files.resolveKompiled(executable); } - sw.printIntermediate(" \u2514" + executable + ": " + type); - } - private String getThreshold() { - if (!options.iterated && !kompileOptions.optimize3) { - return "0"; - } - return options.iteratedThreshold; + args.add(outputFile.getCanonicalPath()); + } + + if (!options.debug) { + if (kompileOptions.optimize1) args.add("-O1"); + if (kompileOptions.optimize2) args.add("-O2"); + if (kompileOptions.optimize3) + args.add("-O2"); // clang -O3 does not make the llvm backend any faster + } + + args.addAll(options.ccopts); + + if (globalOptions.verbose) { + System.out.println(" \u250cExecuting: " + String.join(" ", args)); + } + + Process p = pb.command(args).inheritIO().start(); + int exit = p.waitFor(); + if (exit != 0) { + throw KEMException.criticalError( + "llvm-kompile returned nonzero exit code: " + exit + "\nExamine output to see errors."); + } + } catch (IOException | InterruptedException e) { + throw KEMException.criticalError("Error with I/O while executing llvm-kompile", e); } + sw.printIntermediate(" \u2514" + executable + ": " + type); + } - @Override - public Set excludedModuleTags() { - return new HashSet<>(Arrays.asList(Att.SYMBOLIC(), Att.KAST())); + private String getThreshold() { + if (!options.iterated && !kompileOptions.optimize3) { + return "0"; } + return options.iteratedThreshold; + } + + @Override + public Set excludedModuleTags() { + return new HashSet<>(Arrays.asList(Att.SYMBOLIC(), Att.KAST())); + } } diff --git a/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackendKModule.java b/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackendKModule.java index 593ac782be4..0db0dd9a277 100644 --- a/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackendKModule.java +++ b/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMBackendKModule.java @@ -3,40 +3,35 @@ import com.google.inject.AbstractModule; import com.google.inject.Module; -import com.google.inject.TypeLiteral; import com.google.inject.multibindings.MapBinder; -import org.apache.commons.lang3.tuple.Pair; -import org.kframework.definition.Definition; -import org.kframework.main.AbstractKModule; -import org.kframework.rewriter.Rewriter; - import java.util.Collections; import java.util.List; -import java.util.function.Function; +import org.apache.commons.lang3.tuple.Pair; +import org.kframework.main.AbstractKModule; -/** - * Created by traiansf on 9/13/18. - */ +/** Created by traiansf on 9/13/18. */ public class LLVMBackendKModule extends AbstractKModule { - @Override - public List getKompileModules() { - List mods = super.getKompileModules(); - mods.add(new AbstractModule() { - @Override - protected void configure() { - bindOptions(LLVMBackendKModule.this::kompileOptions, binder()); + @Override + public List getKompileModules() { + List mods = super.getKompileModules(); + mods.add( + new AbstractModule() { + @Override + protected void configure() { + bindOptions(LLVMBackendKModule.this::kompileOptions, binder()); - MapBinder mapBinder = MapBinder.newMapBinder( - binder(), String.class, org.kframework.compile.Backend.class); - mapBinder.addBinding("llvm").to(LLVMBackend.class); - } + MapBinder mapBinder = + MapBinder.newMapBinder( + binder(), String.class, org.kframework.compile.Backend.class); + mapBinder.addBinding("llvm").to(LLVMBackend.class); + } }); - return mods; - } + return mods; + } - @Override - public List, Boolean>> kompileOptions() { - return Collections.singletonList(Pair.of(LLVMKompileOptions.class, true)); - } + @Override + public List, Boolean>> kompileOptions() { + return Collections.singletonList(Pair.of(LLVMKompileOptions.class, true)); + } } diff --git a/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMKompileOptions.java b/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMKompileOptions.java index bb757de59a8..5a1ea131b5a 100644 --- a/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMKompileOptions.java +++ b/llvm-backend/src/main/java/org/kframework/backend/llvm/LLVMKompileOptions.java @@ -1,52 +1,103 @@ // Copyright (c) Runtime Verification, Inc. All Rights Reserved. package org.kframework.backend.llvm; -import com.beust.jcommander.Parameter; import com.beust.jcommander.IStringConverter; +import com.beust.jcommander.Parameter; import com.google.inject.Inject; -import org.kframework.utils.inject.RequestScoped; - -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import org.kframework.utils.inject.RequestScoped; @RequestScoped public class LLVMKompileOptions { - @Inject - public LLVMKompileOptions() {} + @Inject + public LLVMKompileOptions() {} - @Parameter(names="--enable-llvm-debug", description="Enable debugging support for the LLVM backend.") - public boolean debug = false; + @Parameter( + names = "--enable-llvm-debug", + description = "Enable debugging support for the LLVM backend.") + public boolean debug = false; - @Parameter(names="-ccopt", description="Add a command line option to the compiler invocation for the llvm backend.", descriptionKey = "options", listConverter=SingletonListConverter.class, hidden = true) - public List ccopts = new ArrayList<>(); + @Parameter( + names = "-ccopt", + description = "Add a command line option to the compiler invocation for the llvm backend.", + descriptionKey = "options", + listConverter = SingletonListConverter.class, + hidden = true) + public List ccopts = new ArrayList<>(); - public static class SingletonListConverter implements IStringConverter> { - @Override - public List convert(String str) { - return Arrays.asList(str); - } + public static class SingletonListConverter implements IStringConverter> { + @Override + public List convert(String str) { + return Arrays.asList(str); } + } - @Parameter(names="--heuristic", description="A string of single characters representing a sequence of heuristics to use during pattern matching compilation. Valid choices are f, d, b, a, l, r, n, p, q, _, N, L, R.", descriptionKey = "heuristics", hidden = true) - public String heuristic = "qbaL"; + @Parameter( + names = "--heuristic", + description = + "A string of single characters representing a sequence of heuristics to use during" + + " pattern matching compilation. Valid choices are f, d, b, a, l, r, n, p, q, _, N," + + " L, R.", + descriptionKey = "heuristics", + hidden = true) + public String heuristic = "qbaL"; - @Parameter(names="--iterated", description="Generate iterated pattern matching optimization; time-consuming but significantly reduces matching time.", hidden = true) - public boolean iterated = false; + @Parameter( + names = "--iterated", + description = + "Generate iterated pattern matching optimization; time-consuming but significantly" + + " reduces matching time.", + hidden = true) + public boolean iterated = false; - @Parameter(names="--iterated-threshold", description="Threshold heuristic to use when choosing which axioms to optimize. A value of 0 turns the optimization off; a value of 1 turns the optimization on for every axiom. Values in between (expressed as a fraction of two integers, e.g. 1/2), control the aggressiveness of the optimization. Higher values increase compilation times extremely, but also increase the effectiveness of the optimization. Consider decreasing this threshold if compilation is too slow.", descriptionKey = "value", hidden = true) - public String iteratedThreshold = "1/2"; + @Parameter( + names = "--iterated-threshold", + description = + "Threshold heuristic to use when choosing which axioms to optimize. A value of 0 turns" + + " the optimization off; a value of 1 turns the optimization on for every axiom." + + " Values in between (expressed as a fraction of two integers, e.g. 1/2), control" + + " the aggressiveness of the optimization. Higher values increase compilation times" + + " extremely, but also increase the effectiveness of the optimization. Consider" + + " decreasing this threshold if compilation is too slow.", + descriptionKey = "value", + hidden = true) + public String iteratedThreshold = "1/2"; - @Parameter(names="--no-llvm-kompile", description="Do not invoke llvm-kompile. Useful if you want to do it yourself when building with the LLVM backend.", hidden = true) - public boolean noLLVMKompile; + @Parameter( + names = "--no-llvm-kompile", + description = + "Do not invoke llvm-kompile. Useful if you want to do it yourself when building with the" + + " LLVM backend.", + hidden = true) + public boolean noLLVMKompile; - @Parameter(names="--enable-search", description="By default, to reduce compilation time, `krun --search` is disabled on the LLVM backend. Pass this flag to enable it.") - public boolean enableSearch; + @Parameter( + names = "--enable-search", + description = + "By default, to reduce compilation time, `krun --search` is disabled on the LLVM backend." + + " Pass this flag to enable it.") + public boolean enableSearch; - @Parameter(names="--llvm-kompile-type", description="Specifies the llvm backend's output type. Valid choices are main (build an interpreter), library (build an interpreter, but don't link a main function), search (same as main, but the interpreter does search instead of single-path execution), static (same as library, but no '-l' flags are passed during linking. Used for making a partially linked object file) and python (build a Python bindings module for this definition)", descriptionKey = "type", hidden = true) - public String llvmKompileType = "main"; + @Parameter( + names = "--llvm-kompile-type", + description = + "Specifies the llvm backend's output type. Valid choices are main (build an interpreter)," + + " library (build an interpreter, but don't link a main function), search (same as" + + " main, but the interpreter does search instead of single-path execution), static" + + " (same as library, but no '-l' flags are passed during linking. Used for making a" + + " partially linked object file) and python (build a Python bindings module for this" + + " definition)", + descriptionKey = "type", + hidden = true) + public String llvmKompileType = "main"; - @Parameter(names="--llvm-kompile-output", description="Name of the output binary from the llvm backend.", descriptionKey = "file", hidden = true) - public String llvmKompileOutput = null; + @Parameter( + names = "--llvm-kompile-output", + description = "Name of the output binary from the llvm backend.", + descriptionKey = "file", + hidden = true) + public String llvmKompileOutput = null; } From 12f92c2f82e1571af684d785c2f4c351b17eee9d Mon Sep 17 00:00:00 2001 From: Dwight Guth Date: Wed, 1 Nov 2023 12:24:55 -0500 Subject: [PATCH 3/4] update the version of a couple vulnerable dependencies (#3775) Co-authored-by: Sam Balco Co-authored-by: devops Co-authored-by: rv-jenkins --- flake.lock | 10 +- flake.nix | 3 +- kernel/pom.xml | 8 +- kore/pom.xml | 2 +- nix/mavenix.lock | 588 ++++++++++++++++++++++++----------------------- 5 files changed, 318 insertions(+), 293 deletions(-) diff --git a/flake.lock b/flake.lock index f0be4f4fdfb..7b1ded9a071 100644 --- a/flake.lock +++ b/flake.lock @@ -160,15 +160,15 @@ ] }, "locked": { - "lastModified": 1643802645, - "narHash": "sha256-BynM25iwp/l3FyrcHqiNJdDxvN6IxSM3/zkFR6PD3B0=", - "owner": "nix-community", + "lastModified": 1689018333, + "narHash": "sha256-sthxx50rj0E7gv38oeMj8GZOp7i1776P1qZsM7pVLd0=", + "owner": "goodlyrottenapple", "repo": "mavenix", - "rev": "ce9ddfd7f361190e8e8dcfaf6b8282eebbb3c7cb", + "rev": "153d69e62f87e5dd37d35492cc3e35dd80d2b5fa", "type": "github" }, "original": { - "owner": "nix-community", + "owner": "goodlyrottenapple", "repo": "mavenix", "type": "github" } diff --git a/flake.nix b/flake.nix index 7e2020c1fff..71381cc01b1 100644 --- a/flake.nix +++ b/flake.nix @@ -11,7 +11,7 @@ nixpkgs.follows = "haskell-backend/nixpkgs"; flake-utils.url = "github:numtide/flake-utils"; mavenix = { - url = "github:nix-community/mavenix"; + url = "github:goodlyrottenapple/mavenix"; inputs.nixpkgs.follows = "haskell-backend/nixpkgs"; inputs.utils.follows = "flake-utils"; }; @@ -144,6 +144,7 @@ ${pkgs.nix}/bin/nix-build --no-out-link -E 'import ./nix/flake-compat-k-unwrapped.nix' \ || echo "^~~~ expected error" + export PATH="${pkgs.gnused}/bin:$PATH" ${pkgs.mavenix-cli}/bin/mvnix-update -l ./nix/mavenix.lock -E 'import ./nix/flake-compat-k-unwrapped.nix' ''; diff --git a/kernel/pom.xml b/kernel/pom.xml index aa1541af51d..9508552e3ee 100644 --- a/kernel/pom.xml +++ b/kernel/pom.xml @@ -27,7 +27,7 @@ org.bouncycastle bcprov-jdk15on - 1.67 + 1.69 com.google.inject @@ -91,12 +91,12 @@ org.apache.commons commons-collections4 - 4.1 + 4.3 commons-codec commons-codec - 1.10 + 1.13 net.sf.jung @@ -171,7 +171,7 @@ com.vladsch.flexmark flexmark-all - 0.60.2 + 0.64.6 diff --git a/kore/pom.xml b/kore/pom.xml index b7aca9ca652..8bff8d18913 100644 --- a/kore/pom.xml +++ b/kore/pom.xml @@ -23,7 +23,7 @@ com.google.guava guava - 30.0-jre + 32.1.3-jre org.pcollections diff --git a/nix/mavenix.lock b/nix/mavenix.lock index 541407e5860..cd9f373805e 100644 --- a/nix/mavenix.lock +++ b/nix/mavenix.lock @@ -182,8 +182,12 @@ "sha1": "292197f3cb1ebc0dd03e20897e4250b265177286" }, { - "path": "com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.jar", - "sha1": "dac170e4594de319655ffb62f41cbd6dbb5e601e" + "path": "com/google/errorprone/error_prone_annotations/2.21.1/error_prone_annotations-2.21.1.jar", + "sha1": "6d9b10773b5237df178a7b3c1b4208df7d0e7f94" + }, + { + "path": "com/google/errorprone/error_prone_annotations/2.21.1/error_prone_annotations-2.21.1.pom", + "sha1": "e3d7e7e5c6e7b24256bd55642344a8d99b64e599" }, { "path": "com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.pom", @@ -197,6 +201,10 @@ "path": "com/google/errorprone/error_prone_annotations/2.7.1/error_prone_annotations-2.7.1.pom", "sha1": "0b0fa22131b64b3985fba347927252af21898984" }, + { + "path": "com/google/errorprone/error_prone_parent/2.21.1/error_prone_parent-2.21.1.pom", + "sha1": "e5a62220a9c871cb1283dde6e52b7f1f21c84207" + }, { "path": "com/google/errorprone/error_prone_parent/2.3.4/error_prone_parent-2.3.4.pom", "sha1": "a9b9dd42d174a5f96d6c195525877fc6d0b2028a" @@ -233,10 +241,6 @@ "path": "com/google/guava/guava-parent/26.0-android/guava-parent-26.0-android.pom", "sha1": "a2c0df489614352b7e8e503e274bd1dee5c42a64" }, - { - "path": "com/google/guava/guava-parent/30.0-jre/guava-parent-30.0-jre.pom", - "sha1": "967743c6cda3e5267084455bca3c7ab08df3f453" - }, { "path": "com/google/guava/guava-parent/30.1-jre/guava-parent-30.1-jre.pom", "sha1": "b732bbf7c4ceb14dfd6af514a8b8b71dd952e53b" @@ -245,6 +249,10 @@ "path": "com/google/guava/guava-parent/31.0.1-jre/guava-parent-31.0.1-jre.pom", "sha1": "eb78b5264bd92cca5655396c44420eef3ad3ec0f" }, + { + "path": "com/google/guava/guava-parent/32.1.3-jre/guava-parent-32.1.3-jre.pom", + "sha1": "25e3a63dea904b6b1461cb6cbcf7e31bd211714e" + }, { "path": "com/google/guava/guava/16.0.1/guava-16.0.1.pom", "sha1": "52f16cd93f1ee1f0d1e1e55f46fa21c35f829f85" @@ -253,14 +261,6 @@ "path": "com/google/guava/guava/19.0/guava-19.0.pom", "sha1": "65a43a21dbddcc19aa3ca50a63a4b33166bfbc77" }, - { - "path": "com/google/guava/guava/30.0-jre/guava-30.0-jre.jar", - "sha1": "8ddbc8769f73309fe09b54c5951163f10b0d89fa" - }, - { - "path": "com/google/guava/guava/30.0-jre/guava-30.0-jre.pom", - "sha1": "d7239fe628e6e3fbb6734acbc07195435fdac305" - }, { "path": "com/google/guava/guava/30.1-jre/guava-30.1-jre.pom", "sha1": "4056c9385578a442117d1a68118def38087164da" @@ -273,6 +273,14 @@ "path": "com/google/guava/guava/31.0.1-jre/guava-31.0.1-jre.pom", "sha1": "d0ec1628dcc04e4835721416103672384ea3136f" }, + { + "path": "com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.jar", + "sha1": "0f306708742ce2bf0fb0901216183bc14073feae" + }, + { + "path": "com/google/guava/guava/32.1.3-jre/guava-32.1.3-jre.pom", + "sha1": "698deeca13a1dc49e069b8a7e11d8cc2ff6a8cf9" + }, { "path": "com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar", "sha1": "b421526c5f297295adef1c886e5246c39d4ac629" @@ -337,6 +345,14 @@ "path": "com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.pom", "sha1": "47e0dd93285dcc6b33181713bc7e8aed66742964" }, + { + "path": "com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.jar", + "sha1": "c85270e307e7b822f1086b93689124b89768e273" + }, + { + "path": "com/google/j2objc/j2objc-annotations/2.8/j2objc-annotations-2.8.pom", + "sha1": "c8daacea97066c6826844e2175ec89857e598122" + }, { "path": "com/helger/maven/ph-javacc-maven-plugin/4.1.4/ph-javacc-maven-plugin-4.1.4.jar", "sha1": "c4434297659c27e788ee9d352188862734278fe5" @@ -394,12 +410,12 @@ "sha1": "f5e5690593e7124b34b7463a10473517f3d14098" }, { - "path": "com/ibm/icu/icu4j/59.1/icu4j-59.1.jar", - "sha1": "6f06e820cf4c8968bbbaae66ae0b33f6a256b57f" + "path": "com/ibm/icu/icu4j/72.1/icu4j-72.1.jar", + "sha1": "bc9057df4b5efddf7f6d1880bf7f3399f4ce5633" }, { - "path": "com/ibm/icu/icu4j/59.1/icu4j-59.1.pom", - "sha1": "577f1f4e1d5c8603f45a5fa34ba42128ea6e5b84" + "path": "com/ibm/icu/icu4j/72.1/icu4j-72.1.pom", + "sha1": "035e3d76620a1ae74da17fa52d2c33609d3673ae" }, { "path": "com/jcraft/jsch/0.1.27/jsch-0.1.27.jar", @@ -426,40 +442,32 @@ "sha1": "d96547ef58c82124f804209865254f13aa1db928" }, { - "path": "com/openhtmltopdf/openhtmltopdf-core/1.0.0/openhtmltopdf-core-1.0.0.jar", - "sha1": "a0c330e952ca185ff7b105e36294f02199d2c171" - }, - { - "path": "com/openhtmltopdf/openhtmltopdf-core/1.0.0/openhtmltopdf-core-1.0.0.pom", - "sha1": "78b9520d9e091f294d7d05648ab9df8159eac2b9" + "path": "com/openhtmltopdf/openhtmltopdf-core/1.0.10/openhtmltopdf-core-1.0.10.jar", + "sha1": "cab5dcb31834bd86ffb1b1f82811a37fcea63cd2" }, { - "path": "com/openhtmltopdf/openhtmltopdf-jsoup-dom-converter/1.0.0/openhtmltopdf-jsoup-dom-converter-1.0.0.jar", - "sha1": "dba071d26065e53a83270ae01d4b1d3f2faa1757" + "path": "com/openhtmltopdf/openhtmltopdf-core/1.0.10/openhtmltopdf-core-1.0.10.pom", + "sha1": "863d04f060068ab723a1b183f4ed60518e205618" }, { - "path": "com/openhtmltopdf/openhtmltopdf-jsoup-dom-converter/1.0.0/openhtmltopdf-jsoup-dom-converter-1.0.0.pom", - "sha1": "fd9243f930cc126acfe378be901f755de95bc5fc" + "path": "com/openhtmltopdf/openhtmltopdf-parent/1.0.10/openhtmltopdf-parent-1.0.10.pom", + "sha1": "25ee9e84d10793153ca288db3892cb30ca6e04cf" }, { - "path": "com/openhtmltopdf/openhtmltopdf-parent/1.0.0/openhtmltopdf-parent-1.0.0.pom", - "sha1": "61eae444a6ca3842c7246d48e7b1de32dc24e9f5" + "path": "com/openhtmltopdf/openhtmltopdf-pdfbox/1.0.10/openhtmltopdf-pdfbox-1.0.10.jar", + "sha1": "4041442fda47e760985cea8005d51a830031420f" }, { - "path": "com/openhtmltopdf/openhtmltopdf-pdfbox/1.0.0/openhtmltopdf-pdfbox-1.0.0.jar", - "sha1": "b5a0ceb836b85a02b412333bb5a2e990b0bb0d84" + "path": "com/openhtmltopdf/openhtmltopdf-pdfbox/1.0.10/openhtmltopdf-pdfbox-1.0.10.pom", + "sha1": "d2a6028968660a2af7908d14448f2aebf91907c7" }, { - "path": "com/openhtmltopdf/openhtmltopdf-pdfbox/1.0.0/openhtmltopdf-pdfbox-1.0.0.pom", - "sha1": "fd972fdecfe515938248116eb9e711f1e7e94384" + "path": "com/openhtmltopdf/openhtmltopdf-rtl-support/1.0.10/openhtmltopdf-rtl-support-1.0.10.jar", + "sha1": "074232c12ffb569ae287c6d0d983811880d7172f" }, { - "path": "com/openhtmltopdf/openhtmltopdf-rtl-support/1.0.0/openhtmltopdf-rtl-support-1.0.0.jar", - "sha1": "b47402742530ce94720161c0e44623f460f48683" - }, - { - "path": "com/openhtmltopdf/openhtmltopdf-rtl-support/1.0.0/openhtmltopdf-rtl-support-1.0.0.pom", - "sha1": "74d18a5a5cffbfa318c2d7d648e81483af9629fb" + "path": "com/openhtmltopdf/openhtmltopdf-rtl-support/1.0.10/openhtmltopdf-rtl-support-1.0.10.pom", + "sha1": "8cd6426319ff6d8b76d4e25e41034f326cd442f9" }, { "path": "com/puppycrawl/tools/checkstyle/9.3/checkstyle-9.3.jar", @@ -522,392 +530,400 @@ "sha1": "c8bc33680364e03feab66f8672c906ab015b74d8" }, { - "path": "com/vladsch/flexmark/flexmark-all/0.60.2/flexmark-all-0.60.2.jar", - "sha1": "108b9c4dede3ca7ef56a15ded46ebdb099a530f4" + "path": "com/vladsch/flexmark/flexmark-all/0.64.6/flexmark-all-0.64.6.jar", + "sha1": "a0873fd9edc51c7116a8bb06452f049c54eb64bf" + }, + { + "path": "com/vladsch/flexmark/flexmark-all/0.64.6/flexmark-all-0.64.6.pom", + "sha1": "9a091f55340621fc89092acdf6acf6e89aeef529" + }, + { + "path": "com/vladsch/flexmark/flexmark-ext-abbreviation/0.64.6/flexmark-ext-abbreviation-0.64.6.jar", + "sha1": "6e61c1e878316a7d08cc9847e20ed57ccf3f5ee4" }, { - "path": "com/vladsch/flexmark/flexmark-all/0.60.2/flexmark-all-0.60.2.pom", - "sha1": "1ace631ba021f7d5ef69da7dbd39d6fcf39c0fd8" + "path": "com/vladsch/flexmark/flexmark-ext-abbreviation/0.64.6/flexmark-ext-abbreviation-0.64.6.pom", + "sha1": "4ed9361f4cf68dcc1e7ed52ea474064946c7e881" }, { - "path": "com/vladsch/flexmark/flexmark-ext-abbreviation/0.60.2/flexmark-ext-abbreviation-0.60.2.jar", - "sha1": "6cf9a249320fc0ef80f73c73a1a48e8d1fe4ea4d" + "path": "com/vladsch/flexmark/flexmark-ext-admonition/0.64.6/flexmark-ext-admonition-0.64.6.jar", + "sha1": "1f309ee74523e885b9a6ce9561bfdc9180ae7072" }, { - "path": "com/vladsch/flexmark/flexmark-ext-abbreviation/0.60.2/flexmark-ext-abbreviation-0.60.2.pom", - "sha1": "c7ef090a92be897ce7b00b70f34f98c28b4e04de" + "path": "com/vladsch/flexmark/flexmark-ext-admonition/0.64.6/flexmark-ext-admonition-0.64.6.pom", + "sha1": "5f217339d972d075b87d85cde0994723c2c36337" }, { - "path": "com/vladsch/flexmark/flexmark-ext-admonition/0.60.2/flexmark-ext-admonition-0.60.2.jar", - "sha1": "3be30c580544310791d5cf797d4bb0e3e327fe2d" + "path": "com/vladsch/flexmark/flexmark-ext-anchorlink/0.64.6/flexmark-ext-anchorlink-0.64.6.jar", + "sha1": "13cdca9006615b7f4e919c2701f48b4d5790483d" }, { - "path": "com/vladsch/flexmark/flexmark-ext-admonition/0.60.2/flexmark-ext-admonition-0.60.2.pom", - "sha1": "a9ff1995b063ce7e601a3f79c18b97bd72f96789" + "path": "com/vladsch/flexmark/flexmark-ext-anchorlink/0.64.6/flexmark-ext-anchorlink-0.64.6.pom", + "sha1": "a846660c287bfe5eb1e7e553b4da705fa1aa9558" }, { - "path": "com/vladsch/flexmark/flexmark-ext-anchorlink/0.60.2/flexmark-ext-anchorlink-0.60.2.jar", - "sha1": "49c56e1a0d80fdc31a6b89cd7b36f2e5493df124" + "path": "com/vladsch/flexmark/flexmark-ext-aside/0.64.6/flexmark-ext-aside-0.64.6.jar", + "sha1": "c8fa5d9df64363f81a1904f64f6a169005aa7cb7" }, { - "path": "com/vladsch/flexmark/flexmark-ext-anchorlink/0.60.2/flexmark-ext-anchorlink-0.60.2.pom", - "sha1": "05a4a80b3096348bc721f5c502c40c4efb35e5e0" + "path": "com/vladsch/flexmark/flexmark-ext-aside/0.64.6/flexmark-ext-aside-0.64.6.pom", + "sha1": "ddb0beec713c41f21224c3be00685555fd393f46" }, { - "path": "com/vladsch/flexmark/flexmark-ext-aside/0.60.2/flexmark-ext-aside-0.60.2.jar", - "sha1": "24386047788c8f2fad3c9ec5ff12f39d8fa6aa72" + "path": "com/vladsch/flexmark/flexmark-ext-attributes/0.64.6/flexmark-ext-attributes-0.64.6.jar", + "sha1": "baa0a051dd492099d21db9c6907bd4c1070885c7" }, { - "path": "com/vladsch/flexmark/flexmark-ext-aside/0.60.2/flexmark-ext-aside-0.60.2.pom", - "sha1": "bbee3167051fdf3286763512c8c87fa6ff217288" + "path": "com/vladsch/flexmark/flexmark-ext-attributes/0.64.6/flexmark-ext-attributes-0.64.6.pom", + "sha1": "b3ad1b37209cdb2d4769aeb43d605a3a24d0cf0c" }, { - "path": "com/vladsch/flexmark/flexmark-ext-attributes/0.60.2/flexmark-ext-attributes-0.60.2.jar", - "sha1": "92c01b3a56f186e7d6cbb54c8cc5f8e06540dac5" + "path": "com/vladsch/flexmark/flexmark-ext-autolink/0.64.6/flexmark-ext-autolink-0.64.6.jar", + "sha1": "5896022d0bc27b1fb9704802635cebe823c18e87" }, { - "path": "com/vladsch/flexmark/flexmark-ext-attributes/0.60.2/flexmark-ext-attributes-0.60.2.pom", - "sha1": "89805e24e74c6c1dca4726fbb0c31b41d681ce26" + "path": "com/vladsch/flexmark/flexmark-ext-autolink/0.64.6/flexmark-ext-autolink-0.64.6.pom", + "sha1": "d6e1d788091dcbe17dba10ee6a3a1fba8893df23" }, { - "path": "com/vladsch/flexmark/flexmark-ext-autolink/0.60.2/flexmark-ext-autolink-0.60.2.jar", - "sha1": "697876cbfd3d75e774af0f038523a712ed03bc37" + "path": "com/vladsch/flexmark/flexmark-ext-definition/0.64.6/flexmark-ext-definition-0.64.6.jar", + "sha1": "6db2da9cfa806317b69430ba84f9c330b9fcc962" }, { - "path": "com/vladsch/flexmark/flexmark-ext-autolink/0.60.2/flexmark-ext-autolink-0.60.2.pom", - "sha1": "d9f7f1b1cfcc82f71c7282d64f706f0bc39590dc" + "path": "com/vladsch/flexmark/flexmark-ext-definition/0.64.6/flexmark-ext-definition-0.64.6.pom", + "sha1": "635e5ff38d0975cb053ecf400d2e15aa648d70e2" }, { - "path": "com/vladsch/flexmark/flexmark-ext-definition/0.60.2/flexmark-ext-definition-0.60.2.jar", - "sha1": "1cacb9035224c8462fb5957be239c6888d96803c" + "path": "com/vladsch/flexmark/flexmark-ext-emoji/0.64.6/flexmark-ext-emoji-0.64.6.jar", + "sha1": "d28358dedd8154f5233d2db9f7f31edffd35025e" }, { - "path": "com/vladsch/flexmark/flexmark-ext-definition/0.60.2/flexmark-ext-definition-0.60.2.pom", - "sha1": "1906d5ce0b213d67669990bd80d4554e5a385db5" + "path": "com/vladsch/flexmark/flexmark-ext-emoji/0.64.6/flexmark-ext-emoji-0.64.6.pom", + "sha1": "f597cb9f4b9eec3e5b8b90f728f8878ffb75abdf" }, { - "path": "com/vladsch/flexmark/flexmark-ext-emoji/0.60.2/flexmark-ext-emoji-0.60.2.jar", - "sha1": "5a11d261f822f9570b38a7dfe7003d9941f3177f" + "path": "com/vladsch/flexmark/flexmark-ext-enumerated-reference/0.64.6/flexmark-ext-enumerated-reference-0.64.6.jar", + "sha1": "e589943601ab290c46fabdb18ff32035ea24c6d0" }, { - "path": "com/vladsch/flexmark/flexmark-ext-emoji/0.60.2/flexmark-ext-emoji-0.60.2.pom", - "sha1": "81a6e5a92d9890096d15a4fe04cc66b2e20ed6f3" + "path": "com/vladsch/flexmark/flexmark-ext-enumerated-reference/0.64.6/flexmark-ext-enumerated-reference-0.64.6.pom", + "sha1": "86dfe86456d49ba92983294b54f02241830252da" }, { - "path": "com/vladsch/flexmark/flexmark-ext-enumerated-reference/0.60.2/flexmark-ext-enumerated-reference-0.60.2.jar", - "sha1": "ff5fad22442e95c42551f03f33c878678f995208" + "path": "com/vladsch/flexmark/flexmark-ext-escaped-character/0.64.6/flexmark-ext-escaped-character-0.64.6.jar", + "sha1": "8d9ebf200f5313d389164aa76ed36054930656cc" }, { - "path": "com/vladsch/flexmark/flexmark-ext-enumerated-reference/0.60.2/flexmark-ext-enumerated-reference-0.60.2.pom", - "sha1": "25b698de67c5566a85dc3f7a33ff2741765fa063" + "path": "com/vladsch/flexmark/flexmark-ext-escaped-character/0.64.6/flexmark-ext-escaped-character-0.64.6.pom", + "sha1": "4dddca2caa2c6e16c7c31e0c22f8c849ea880611" }, { - "path": "com/vladsch/flexmark/flexmark-ext-escaped-character/0.60.2/flexmark-ext-escaped-character-0.60.2.jar", - "sha1": "2ba7185f2bb92824ccae4f2954ccc8ef01efa67a" + "path": "com/vladsch/flexmark/flexmark-ext-footnotes/0.64.6/flexmark-ext-footnotes-0.64.6.jar", + "sha1": "6d99e8d56d128c7b640caf1b2fe5bb6f45dc736d" }, { - "path": "com/vladsch/flexmark/flexmark-ext-escaped-character/0.60.2/flexmark-ext-escaped-character-0.60.2.pom", - "sha1": "3dadb0bb22fe99e44bf9da94626fef8e732a6e2f" + "path": "com/vladsch/flexmark/flexmark-ext-footnotes/0.64.6/flexmark-ext-footnotes-0.64.6.pom", + "sha1": "a953a2533e7462a3a86fe301a29a574159f3ed89" }, { - "path": "com/vladsch/flexmark/flexmark-ext-footnotes/0.60.2/flexmark-ext-footnotes-0.60.2.jar", - "sha1": "f0f33a706fa9d78dabdaf1fa81d4b904a19ebd08" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-issues/0.64.6/flexmark-ext-gfm-issues-0.64.6.jar", + "sha1": "96e017f022a8352513fb437d44703668f6d108cd" }, { - "path": "com/vladsch/flexmark/flexmark-ext-footnotes/0.60.2/flexmark-ext-footnotes-0.60.2.pom", - "sha1": "a5de234048c5bbd4824009c782c6ec61d4666ddd" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-issues/0.64.6/flexmark-ext-gfm-issues-0.64.6.pom", + "sha1": "ed42f7f72a7bea3e472c5e76071b3533e23d3bad" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-issues/0.60.2/flexmark-ext-gfm-issues-0.60.2.jar", - "sha1": "38a80722c7ba3a7483788b5dc6096056b18adfa9" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-strikethrough/0.64.6/flexmark-ext-gfm-strikethrough-0.64.6.jar", + "sha1": "4efc43213c62df5ee64a9d49cf347577c58e4430" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-issues/0.60.2/flexmark-ext-gfm-issues-0.60.2.pom", - "sha1": "28c942ed9a31970b5be54037b164425b2eb5b53b" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-strikethrough/0.64.6/flexmark-ext-gfm-strikethrough-0.64.6.pom", + "sha1": "cbd88eb47523b92433a2284425523af0b0219b0f" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-strikethrough/0.60.2/flexmark-ext-gfm-strikethrough-0.60.2.jar", - "sha1": "5596e49c93675d5ce02daa3d0519fe10d4186258" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-tasklist/0.64.6/flexmark-ext-gfm-tasklist-0.64.6.jar", + "sha1": "96153a10ac31402534853cd2cf6b90a363bd8c3b" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-strikethrough/0.60.2/flexmark-ext-gfm-strikethrough-0.60.2.pom", - "sha1": "e573a623970b28f3abff98a46bc1d8b46db34529" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-tasklist/0.64.6/flexmark-ext-gfm-tasklist-0.64.6.pom", + "sha1": "a76bf7987e37b79649cacd4d9eff779892bf27a0" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-tasklist/0.60.2/flexmark-ext-gfm-tasklist-0.60.2.jar", - "sha1": "10a525068a99dc8e66a825ed07152e5ee76b72b6" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-users/0.64.6/flexmark-ext-gfm-users-0.64.6.jar", + "sha1": "47c46de63718f08fff5bfcf4cf44881bb37bb1e2" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-tasklist/0.60.2/flexmark-ext-gfm-tasklist-0.60.2.pom", - "sha1": "82ea49c71ee94424fea2dee37956d39492ffcd41" + "path": "com/vladsch/flexmark/flexmark-ext-gfm-users/0.64.6/flexmark-ext-gfm-users-0.64.6.pom", + "sha1": "d36256594267bcb1fbbd9091dfa7fb010a65f15b" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-users/0.60.2/flexmark-ext-gfm-users-0.60.2.jar", - "sha1": "b6099b9c62da5221847a84162be37d476607eff7" + "path": "com/vladsch/flexmark/flexmark-ext-gitlab/0.64.6/flexmark-ext-gitlab-0.64.6.jar", + "sha1": "fe201c9a859866d1867dcedd0b82be7a9dcfa00f" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gfm-users/0.60.2/flexmark-ext-gfm-users-0.60.2.pom", - "sha1": "d42addee996832c74fa98a623f6c456a2b752cfb" + "path": "com/vladsch/flexmark/flexmark-ext-gitlab/0.64.6/flexmark-ext-gitlab-0.64.6.pom", + "sha1": "584659a3c4e3c5c5b7ff8f5e1d8612ed438a55f5" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gitlab/0.60.2/flexmark-ext-gitlab-0.60.2.jar", - "sha1": "fe18172fc35fe0a4c0b8c22c424f84b5aa688058" + "path": "com/vladsch/flexmark/flexmark-ext-ins/0.64.6/flexmark-ext-ins-0.64.6.jar", + "sha1": "bf61251b412df232853a3e7284fd4eac3a34f594" }, { - "path": "com/vladsch/flexmark/flexmark-ext-gitlab/0.60.2/flexmark-ext-gitlab-0.60.2.pom", - "sha1": "52133fd9f74a264e20c8198c89e6757fae60be80" + "path": "com/vladsch/flexmark/flexmark-ext-ins/0.64.6/flexmark-ext-ins-0.64.6.pom", + "sha1": "f0bfc016b41ecf7d4524b24582cacf50b4e13944" }, { - "path": "com/vladsch/flexmark/flexmark-ext-ins/0.60.2/flexmark-ext-ins-0.60.2.jar", - "sha1": "6a34a48f9d2478ef1e8c793e32ab7650c057be3a" + "path": "com/vladsch/flexmark/flexmark-ext-jekyll-front-matter/0.64.6/flexmark-ext-jekyll-front-matter-0.64.6.jar", + "sha1": "5587cf106274f5aa537a56596b38cfe4b6444171" }, { - "path": "com/vladsch/flexmark/flexmark-ext-ins/0.60.2/flexmark-ext-ins-0.60.2.pom", - "sha1": "22535df1be857a37f4738ac4959453a4d0d75be0" + "path": "com/vladsch/flexmark/flexmark-ext-jekyll-front-matter/0.64.6/flexmark-ext-jekyll-front-matter-0.64.6.pom", + "sha1": "3e291b0fe0512d0a1ef45256413cc4d2c3ff14cf" }, { - "path": "com/vladsch/flexmark/flexmark-ext-jekyll-front-matter/0.60.2/flexmark-ext-jekyll-front-matter-0.60.2.jar", - "sha1": "7a83f6f2d4558ee673b719e8f24f8a2f312890c5" + "path": "com/vladsch/flexmark/flexmark-ext-jekyll-tag/0.64.6/flexmark-ext-jekyll-tag-0.64.6.jar", + "sha1": "0ffda5e6f9d39f3c47902fad2f4d64f8fcf9d9c0" }, { - "path": "com/vladsch/flexmark/flexmark-ext-jekyll-front-matter/0.60.2/flexmark-ext-jekyll-front-matter-0.60.2.pom", - "sha1": "907d0c076f1027ef711d1c66da593f21eb5c42de" + "path": "com/vladsch/flexmark/flexmark-ext-jekyll-tag/0.64.6/flexmark-ext-jekyll-tag-0.64.6.pom", + "sha1": "99c518290a7dcbd5e0b08030577b1f7c2f26375f" }, { - "path": "com/vladsch/flexmark/flexmark-ext-jekyll-tag/0.60.2/flexmark-ext-jekyll-tag-0.60.2.jar", - "sha1": "40f91672c85f869ff6920ab8c9ec874ab6026385" + "path": "com/vladsch/flexmark/flexmark-ext-macros/0.64.6/flexmark-ext-macros-0.64.6.jar", + "sha1": "8d0d9bebf0e134017e5bc2a3b70f20b924aabe33" }, { - "path": "com/vladsch/flexmark/flexmark-ext-jekyll-tag/0.60.2/flexmark-ext-jekyll-tag-0.60.2.pom", - "sha1": "5fbc2dc15086c22a29f0866ce7830033a339470b" + "path": "com/vladsch/flexmark/flexmark-ext-macros/0.64.6/flexmark-ext-macros-0.64.6.pom", + "sha1": "0ba690a3fb802094022daae90897fec250d0d44d" }, { - "path": "com/vladsch/flexmark/flexmark-ext-macros/0.60.2/flexmark-ext-macros-0.60.2.jar", - "sha1": "b423af384a6a5b9f074bd2f957306e1a850fd4e9" + "path": "com/vladsch/flexmark/flexmark-ext-media-tags/0.64.6/flexmark-ext-media-tags-0.64.6.jar", + "sha1": "4ce92735883aa62f933cc18785cf82f65748782b" }, { - "path": "com/vladsch/flexmark/flexmark-ext-macros/0.60.2/flexmark-ext-macros-0.60.2.pom", - "sha1": "dc52277f66fa2b0d4b3d8ab68bccb3123dc81748" + "path": "com/vladsch/flexmark/flexmark-ext-media-tags/0.64.6/flexmark-ext-media-tags-0.64.6.pom", + "sha1": "ae13817577a4feeb7a45f9ca7cc882fed6cb5682" }, { - "path": "com/vladsch/flexmark/flexmark-ext-media-tags/0.60.2/flexmark-ext-media-tags-0.60.2.jar", - "sha1": "d57cf95f86e25c2fafcca1bdc12d0b4730fdb65f" + "path": "com/vladsch/flexmark/flexmark-ext-resizable-image/0.64.6/flexmark-ext-resizable-image-0.64.6.jar", + "sha1": "79b3dcfebd4c024045f976d4749168f6622f1570" }, { - "path": "com/vladsch/flexmark/flexmark-ext-media-tags/0.60.2/flexmark-ext-media-tags-0.60.2.pom", - "sha1": "4ddd45aa6c8a701360c1ad41e3bc70a17d419255" + "path": "com/vladsch/flexmark/flexmark-ext-resizable-image/0.64.6/flexmark-ext-resizable-image-0.64.6.pom", + "sha1": "2f9387a2b6e71422664ab130c817af43843a2ac9" }, { - "path": "com/vladsch/flexmark/flexmark-ext-superscript/0.60.2/flexmark-ext-superscript-0.60.2.jar", - "sha1": "0a363a6bf7c622f669e867bef620cffac67cfd46" + "path": "com/vladsch/flexmark/flexmark-ext-superscript/0.64.6/flexmark-ext-superscript-0.64.6.jar", + "sha1": "5a901a2926d2d4a69e1828a7436982236fb9a545" }, { - "path": "com/vladsch/flexmark/flexmark-ext-superscript/0.60.2/flexmark-ext-superscript-0.60.2.pom", - "sha1": "01002b79470743480025d7157f4d3a403062ce6c" + "path": "com/vladsch/flexmark/flexmark-ext-superscript/0.64.6/flexmark-ext-superscript-0.64.6.pom", + "sha1": "5684f8d2e07abcccea469fdaf1d11dd9ae751df7" }, { - "path": "com/vladsch/flexmark/flexmark-ext-tables/0.60.2/flexmark-ext-tables-0.60.2.jar", - "sha1": "56b026a571bbd9e098fda3a114452414fdfead6d" + "path": "com/vladsch/flexmark/flexmark-ext-tables/0.64.6/flexmark-ext-tables-0.64.6.jar", + "sha1": "79a451aca1271ddc865bd9125a49cea52da938e8" }, { - "path": "com/vladsch/flexmark/flexmark-ext-tables/0.60.2/flexmark-ext-tables-0.60.2.pom", - "sha1": "d02f6bbb88373707dd0d11761235d32ce9fb1140" + "path": "com/vladsch/flexmark/flexmark-ext-tables/0.64.6/flexmark-ext-tables-0.64.6.pom", + "sha1": "8d4f530e09b62e19dfc9d60eb062099e36905863" }, { - "path": "com/vladsch/flexmark/flexmark-ext-toc/0.60.2/flexmark-ext-toc-0.60.2.jar", - "sha1": "eec83613105d4fdef09941a1b5af5d6d6478638b" + "path": "com/vladsch/flexmark/flexmark-ext-toc/0.64.6/flexmark-ext-toc-0.64.6.jar", + "sha1": "5505aea3c013e5f62f2774a04632f06fea8a14d8" }, { - "path": "com/vladsch/flexmark/flexmark-ext-toc/0.60.2/flexmark-ext-toc-0.60.2.pom", - "sha1": "3623550a2f4294095c27daffe5dbffa37313aeda" + "path": "com/vladsch/flexmark/flexmark-ext-toc/0.64.6/flexmark-ext-toc-0.64.6.pom", + "sha1": "c615622289858410c1464aaa7f9a404a5dbacebf" }, { - "path": "com/vladsch/flexmark/flexmark-ext-typographic/0.60.2/flexmark-ext-typographic-0.60.2.jar", - "sha1": "ce55ebfa056d4a15e6e083e56f398de25e053214" + "path": "com/vladsch/flexmark/flexmark-ext-typographic/0.64.6/flexmark-ext-typographic-0.64.6.jar", + "sha1": "6569f2d1a44227b6abd11d1d2d63e23d66b70b95" }, { - "path": "com/vladsch/flexmark/flexmark-ext-typographic/0.60.2/flexmark-ext-typographic-0.60.2.pom", - "sha1": "81d7f4152f89df1ff7a08d3d2b64eae24d9da0f5" + "path": "com/vladsch/flexmark/flexmark-ext-typographic/0.64.6/flexmark-ext-typographic-0.64.6.pom", + "sha1": "c5d3965ea3e8143783d980477624a86d832cfdbd" }, { - "path": "com/vladsch/flexmark/flexmark-ext-wikilink/0.60.2/flexmark-ext-wikilink-0.60.2.jar", - "sha1": "a5d8dc95935aac683bbe11ce75adb1652aaaecc7" + "path": "com/vladsch/flexmark/flexmark-ext-wikilink/0.64.6/flexmark-ext-wikilink-0.64.6.jar", + "sha1": "56c27e1a35997102c37de54b3356fdfdf31a8dc3" }, { - "path": "com/vladsch/flexmark/flexmark-ext-wikilink/0.60.2/flexmark-ext-wikilink-0.60.2.pom", - "sha1": "e5cc08eda5be4ee764fb2db8f83912d81c48516b" + "path": "com/vladsch/flexmark/flexmark-ext-wikilink/0.64.6/flexmark-ext-wikilink-0.64.6.pom", + "sha1": "e27ef72bfa2482c55a8b9227ef4a2133fc0b1a71" }, { - "path": "com/vladsch/flexmark/flexmark-ext-xwiki-macros/0.60.2/flexmark-ext-xwiki-macros-0.60.2.jar", - "sha1": "b8e4ff9a9acce31c86e6747d1eb214a8c6a1dabc" + "path": "com/vladsch/flexmark/flexmark-ext-xwiki-macros/0.64.6/flexmark-ext-xwiki-macros-0.64.6.jar", + "sha1": "247187bb190d64d5753bf5b36c6720dfe3be4128" }, { - "path": "com/vladsch/flexmark/flexmark-ext-xwiki-macros/0.60.2/flexmark-ext-xwiki-macros-0.60.2.pom", - "sha1": "569742e120816cc369056c16ead3bc6da591d161" + "path": "com/vladsch/flexmark/flexmark-ext-xwiki-macros/0.64.6/flexmark-ext-xwiki-macros-0.64.6.pom", + "sha1": "1f4355264c7a195142c1ed4dd3e6e52d73f73a93" }, { - "path": "com/vladsch/flexmark/flexmark-ext-yaml-front-matter/0.60.2/flexmark-ext-yaml-front-matter-0.60.2.jar", - "sha1": "3620a1f67d54fe9a2fabf72ecf85e161784eea44" + "path": "com/vladsch/flexmark/flexmark-ext-yaml-front-matter/0.64.6/flexmark-ext-yaml-front-matter-0.64.6.jar", + "sha1": "67bac33c44cc9743b9446fd8ddb03076adb3ca34" }, { - "path": "com/vladsch/flexmark/flexmark-ext-yaml-front-matter/0.60.2/flexmark-ext-yaml-front-matter-0.60.2.pom", - "sha1": "e8bf5ceae8aeea0e8ac82e5209417446f2cd3255" + "path": "com/vladsch/flexmark/flexmark-ext-yaml-front-matter/0.64.6/flexmark-ext-yaml-front-matter-0.64.6.pom", + "sha1": "8205bb41d1f1b5e19a3311efbd5cb2f0f31b36b4" }, { - "path": "com/vladsch/flexmark/flexmark-ext-youtube-embedded/0.60.2/flexmark-ext-youtube-embedded-0.60.2.jar", - "sha1": "cfa08ca03bd75b1552b09563dfe432a5487751e2" + "path": "com/vladsch/flexmark/flexmark-ext-youtube-embedded/0.64.6/flexmark-ext-youtube-embedded-0.64.6.jar", + "sha1": "30782ef4ea47b98c03d5b0985c5c88aa9d8835ab" }, { - "path": "com/vladsch/flexmark/flexmark-ext-youtube-embedded/0.60.2/flexmark-ext-youtube-embedded-0.60.2.pom", - "sha1": "16328c3639641212284ac3dd0f95f730ab315f84" + "path": "com/vladsch/flexmark/flexmark-ext-youtube-embedded/0.64.6/flexmark-ext-youtube-embedded-0.64.6.pom", + "sha1": "edd90998bbd9124f57908e1e68e639d3d10f44e1" }, { - "path": "com/vladsch/flexmark/flexmark-html2md-converter/0.60.2/flexmark-html2md-converter-0.60.2.jar", - "sha1": "e3c3088e04fc3b09694d13685ce37d8fb76dfb92" + "path": "com/vladsch/flexmark/flexmark-html2md-converter/0.64.6/flexmark-html2md-converter-0.64.6.jar", + "sha1": "2d106e0c0cf1c055c7384df5d5e05c2478dca75b" }, { - "path": "com/vladsch/flexmark/flexmark-html2md-converter/0.60.2/flexmark-html2md-converter-0.60.2.pom", - "sha1": "4d1158dadd616c992fe62078659178f02d3fe741" + "path": "com/vladsch/flexmark/flexmark-html2md-converter/0.64.6/flexmark-html2md-converter-0.64.6.pom", + "sha1": "8e752d3304ff37f7699922592324f69d283d75c7" }, { - "path": "com/vladsch/flexmark/flexmark-java/0.60.2/flexmark-java-0.60.2.pom", - "sha1": "62b238100f57faa0e3a0dddd07bcd743e8f1af17" + "path": "com/vladsch/flexmark/flexmark-java/0.64.6/flexmark-java-0.64.6.pom", + "sha1": "64e7fb4e04cefba53c8766fe3b0956681ef4d129" }, { - "path": "com/vladsch/flexmark/flexmark-jira-converter/0.60.2/flexmark-jira-converter-0.60.2.jar", - "sha1": "9f85300a9bc5473a4445cb8787cd29f1eb87717a" + "path": "com/vladsch/flexmark/flexmark-jira-converter/0.64.6/flexmark-jira-converter-0.64.6.jar", + "sha1": "49fe9c751060fa90118bc275466f8eee93330a8a" }, { - "path": "com/vladsch/flexmark/flexmark-jira-converter/0.60.2/flexmark-jira-converter-0.60.2.pom", - "sha1": "5afc389bc70009a46adf19b579b3682df83b653e" + "path": "com/vladsch/flexmark/flexmark-jira-converter/0.64.6/flexmark-jira-converter-0.64.6.pom", + "sha1": "6cf0c110731e28fd6e34ea2bacd571bd37f3a4c9" }, { - "path": "com/vladsch/flexmark/flexmark-pdf-converter/0.60.2/flexmark-pdf-converter-0.60.2.jar", - "sha1": "4654974a35cc8c655a19bcbbb10b7da672da65cc" + "path": "com/vladsch/flexmark/flexmark-pdf-converter/0.64.6/flexmark-pdf-converter-0.64.6.jar", + "sha1": "7c86f3677f568c7a428e5c749fd4cc06d04cddec" }, { - "path": "com/vladsch/flexmark/flexmark-pdf-converter/0.60.2/flexmark-pdf-converter-0.60.2.pom", - "sha1": "92c168236fb792459a46abf789906d95cdfd1ec0" + "path": "com/vladsch/flexmark/flexmark-pdf-converter/0.64.6/flexmark-pdf-converter-0.64.6.pom", + "sha1": "0e3cb914f933c91c773b96803125a9426a5e59a0" }, { - "path": "com/vladsch/flexmark/flexmark-profile-pegdown/0.60.2/flexmark-profile-pegdown-0.60.2.jar", - "sha1": "fec661c12c22d6c3fab82520891822c3235a367c" + "path": "com/vladsch/flexmark/flexmark-profile-pegdown/0.64.6/flexmark-profile-pegdown-0.64.6.jar", + "sha1": "d12e0075a9516acc28bccb8446e0747a959dfd2b" }, { - "path": "com/vladsch/flexmark/flexmark-profile-pegdown/0.60.2/flexmark-profile-pegdown-0.60.2.pom", - "sha1": "e2c023864c44c4c714c683acded036ad32920cbf" + "path": "com/vladsch/flexmark/flexmark-profile-pegdown/0.64.6/flexmark-profile-pegdown-0.64.6.pom", + "sha1": "e4b829e8c676425a601bf8a65aec3da951af9e4c" }, { - "path": "com/vladsch/flexmark/flexmark-util-ast/0.60.2/flexmark-util-ast-0.60.2.jar", - "sha1": "84176a7e141b449f9e3f88aec045784d180cfe1b" + "path": "com/vladsch/flexmark/flexmark-util-ast/0.64.6/flexmark-util-ast-0.64.6.jar", + "sha1": "03148be3402ac4a7691c386784823c7f3494c20b" }, { - "path": "com/vladsch/flexmark/flexmark-util-ast/0.60.2/flexmark-util-ast-0.60.2.pom", - "sha1": "4acc9e56bf8eafe3d2124e42a254ffbb55f2bc84" + "path": "com/vladsch/flexmark/flexmark-util-ast/0.64.6/flexmark-util-ast-0.64.6.pom", + "sha1": "9083182eeadd9920be2a6c414e9a25de90af1e94" }, { - "path": "com/vladsch/flexmark/flexmark-util-builder/0.60.2/flexmark-util-builder-0.60.2.jar", - "sha1": "14704b83570899a22389e633876c43fb0ba41e7c" + "path": "com/vladsch/flexmark/flexmark-util-builder/0.64.6/flexmark-util-builder-0.64.6.jar", + "sha1": "85292a943917a46a2bdfdcb5656c1cb91f4cef06" }, { - "path": "com/vladsch/flexmark/flexmark-util-builder/0.60.2/flexmark-util-builder-0.60.2.pom", - "sha1": "fdf2970078841ba1b76553ba868f928d9762beff" + "path": "com/vladsch/flexmark/flexmark-util-builder/0.64.6/flexmark-util-builder-0.64.6.pom", + "sha1": "43acac11759c30dcdfb311ef7e1b332a6361c765" }, { - "path": "com/vladsch/flexmark/flexmark-util-collection/0.60.2/flexmark-util-collection-0.60.2.jar", - "sha1": "58261382aa3af036cebf7e3e2bfc06d20b380f39" + "path": "com/vladsch/flexmark/flexmark-util-collection/0.64.6/flexmark-util-collection-0.64.6.jar", + "sha1": "c06f05aafab1c83f2b49f6c5e58fbb9a8aad433f" }, { - "path": "com/vladsch/flexmark/flexmark-util-collection/0.60.2/flexmark-util-collection-0.60.2.pom", - "sha1": "0d900fd257cc8f49f47d1c87897d3bcc6088eeba" + "path": "com/vladsch/flexmark/flexmark-util-collection/0.64.6/flexmark-util-collection-0.64.6.pom", + "sha1": "d4cf190bd777f7a8199fefd7e4b4fa16342a7b21" }, { - "path": "com/vladsch/flexmark/flexmark-util-data/0.60.2/flexmark-util-data-0.60.2.jar", - "sha1": "1f4a21f63f7e8c624a2f626ac199214654b60442" + "path": "com/vladsch/flexmark/flexmark-util-data/0.64.6/flexmark-util-data-0.64.6.jar", + "sha1": "a99b69beed9359d384fff9a9475c485cbf37956c" }, { - "path": "com/vladsch/flexmark/flexmark-util-data/0.60.2/flexmark-util-data-0.60.2.pom", - "sha1": "d9678d924d1d42f7971500ca1de3694ad4967b48" + "path": "com/vladsch/flexmark/flexmark-util-data/0.64.6/flexmark-util-data-0.64.6.pom", + "sha1": "3e7b42a797edc855d600bc36d487b8bd26f81faf" }, { - "path": "com/vladsch/flexmark/flexmark-util-dependency/0.60.2/flexmark-util-dependency-0.60.2.jar", - "sha1": "12a08b6f695e53863161c8df3a61cc03cf8cb82c" + "path": "com/vladsch/flexmark/flexmark-util-dependency/0.64.6/flexmark-util-dependency-0.64.6.jar", + "sha1": "138054fe981c705f02abd1d8d948eb5582fbc5ea" }, { - "path": "com/vladsch/flexmark/flexmark-util-dependency/0.60.2/flexmark-util-dependency-0.60.2.pom", - "sha1": "2fde998a851a8483a21e799f1b490eba641d59d2" + "path": "com/vladsch/flexmark/flexmark-util-dependency/0.64.6/flexmark-util-dependency-0.64.6.pom", + "sha1": "054c71c58604fc0213690fe4bd48d7fe67433981" }, { - "path": "com/vladsch/flexmark/flexmark-util-format/0.60.2/flexmark-util-format-0.60.2.jar", - "sha1": "f7b698daea094f10ed402d81ae3b4deef89cb4f9" + "path": "com/vladsch/flexmark/flexmark-util-format/0.64.6/flexmark-util-format-0.64.6.jar", + "sha1": "16b4975a85269e3e4639e0e5f0cb8a15cc142e7e" }, { - "path": "com/vladsch/flexmark/flexmark-util-format/0.60.2/flexmark-util-format-0.60.2.pom", - "sha1": "f2ae42e3579af750b90f2743d63e88452b4dc701" + "path": "com/vladsch/flexmark/flexmark-util-format/0.64.6/flexmark-util-format-0.64.6.pom", + "sha1": "95a8feeed97ca403e1a26dc0d09805aecd7bec27" }, { - "path": "com/vladsch/flexmark/flexmark-util-html/0.60.2/flexmark-util-html-0.60.2.jar", - "sha1": "4cb886716882d32201caedf1d9819ba065411290" + "path": "com/vladsch/flexmark/flexmark-util-html/0.64.6/flexmark-util-html-0.64.6.jar", + "sha1": "415c79bd96ace0c58da30045f8dc73073b070482" }, { - "path": "com/vladsch/flexmark/flexmark-util-html/0.60.2/flexmark-util-html-0.60.2.pom", - "sha1": "a4283bcb04cddb67a7d6224656a8c7681bea8cbb" + "path": "com/vladsch/flexmark/flexmark-util-html/0.64.6/flexmark-util-html-0.64.6.pom", + "sha1": "9183b5e221bb9da05d358c22bc669e7dc7ff3fa2" }, { - "path": "com/vladsch/flexmark/flexmark-util-misc/0.60.2/flexmark-util-misc-0.60.2.jar", - "sha1": "fe60af722e2e900cffcfc174a9d26e27e80e0047" + "path": "com/vladsch/flexmark/flexmark-util-misc/0.64.6/flexmark-util-misc-0.64.6.jar", + "sha1": "a84b340693ce22d812455390dcdac9dcd958238c" }, { - "path": "com/vladsch/flexmark/flexmark-util-misc/0.60.2/flexmark-util-misc-0.60.2.pom", - "sha1": "7d514fd762201345dee29964d93ea91aafc4e357" + "path": "com/vladsch/flexmark/flexmark-util-misc/0.64.6/flexmark-util-misc-0.64.6.pom", + "sha1": "4fe398386a28f7644d85605f1446dc8a8c0d7252" }, { - "path": "com/vladsch/flexmark/flexmark-util-options/0.60.2/flexmark-util-options-0.60.2.jar", - "sha1": "bdab984888357359b4bca1197fba6d1312cc4c75" + "path": "com/vladsch/flexmark/flexmark-util-options/0.64.6/flexmark-util-options-0.64.6.jar", + "sha1": "a39973dd0ea3c139e7b34a4bc64fd8e9722afa03" }, { - "path": "com/vladsch/flexmark/flexmark-util-options/0.60.2/flexmark-util-options-0.60.2.pom", - "sha1": "b727832a22878e9704a0d86a29e658374a1001e9" + "path": "com/vladsch/flexmark/flexmark-util-options/0.64.6/flexmark-util-options-0.64.6.pom", + "sha1": "44a9950dabf3dbc6815ae54019c22850476cf89e" }, { - "path": "com/vladsch/flexmark/flexmark-util-sequence/0.60.2/flexmark-util-sequence-0.60.2.jar", - "sha1": "55d2d9bd128e9974117ff133b79bf7f581953933" + "path": "com/vladsch/flexmark/flexmark-util-sequence/0.64.6/flexmark-util-sequence-0.64.6.jar", + "sha1": "1ae2cd22728557c2740812aeae799ccc8d50fabc" }, { - "path": "com/vladsch/flexmark/flexmark-util-sequence/0.60.2/flexmark-util-sequence-0.60.2.pom", - "sha1": "efd5a1c40536c662755973c4de7dda124596d53b" + "path": "com/vladsch/flexmark/flexmark-util-sequence/0.64.6/flexmark-util-sequence-0.64.6.pom", + "sha1": "982c5e7220e4a08ee378f97b0cb960ca0c58faa0" }, { - "path": "com/vladsch/flexmark/flexmark-util-visitor/0.60.2/flexmark-util-visitor-0.60.2.jar", - "sha1": "e2cf64e197ecaf33ca22196eca9c2b83a123dd72" + "path": "com/vladsch/flexmark/flexmark-util-visitor/0.64.6/flexmark-util-visitor-0.64.6.jar", + "sha1": "d2cd1af4ab5b654ca8c588900390c1611ffc8c4d" }, { - "path": "com/vladsch/flexmark/flexmark-util-visitor/0.60.2/flexmark-util-visitor-0.60.2.pom", - "sha1": "6b4a214b52cd55e8620647b94727336d88a05c6c" + "path": "com/vladsch/flexmark/flexmark-util-visitor/0.64.6/flexmark-util-visitor-0.64.6.pom", + "sha1": "8d950463677e7fc88f01f7b0467b33e37c5f78c7" }, { - "path": "com/vladsch/flexmark/flexmark-util/0.60.2/flexmark-util-0.60.2.jar", - "sha1": "98a508d0d6b8f5444a6eb1cd3d971453335ff024" + "path": "com/vladsch/flexmark/flexmark-util/0.64.6/flexmark-util-0.64.6.jar", + "sha1": "ca8dc5c99fddcceee61791885fcff1b2fb50f06b" }, { - "path": "com/vladsch/flexmark/flexmark-util/0.60.2/flexmark-util-0.60.2.pom", - "sha1": "18b88919aa421fbd2131c40f517f1122c763d121" + "path": "com/vladsch/flexmark/flexmark-util/0.64.6/flexmark-util-0.64.6.pom", + "sha1": "add67e78f62c3cff15a64b548d9a15503dc987a2" }, { - "path": "com/vladsch/flexmark/flexmark-youtrack-converter/0.60.2/flexmark-youtrack-converter-0.60.2.jar", - "sha1": "7fc14b300ae7fb3df26f53eb9a98bb5768685ba1" + "path": "com/vladsch/flexmark/flexmark-youtrack-converter/0.64.6/flexmark-youtrack-converter-0.64.6.jar", + "sha1": "eed74ea3b7495d9ca4001e59288f01aeae49d590" }, { - "path": "com/vladsch/flexmark/flexmark-youtrack-converter/0.60.2/flexmark-youtrack-converter-0.60.2.pom", - "sha1": "8f3966a49ec695016d5165c28196ac7ba6fa5623" + "path": "com/vladsch/flexmark/flexmark-youtrack-converter/0.64.6/flexmark-youtrack-converter-0.64.6.pom", + "sha1": "1d096b8fb54d7ce35a9234350eb58f90bd828560" }, { - "path": "com/vladsch/flexmark/flexmark/0.60.2/flexmark-0.60.2.jar", - "sha1": "954b8199998760fba7499b733d3855efec755f10" + "path": "com/vladsch/flexmark/flexmark/0.64.6/flexmark-0.64.6.jar", + "sha1": "d859a65013f6df2d46868bdcec643da9792f30ca" }, { - "path": "com/vladsch/flexmark/flexmark/0.60.2/flexmark-0.60.2.pom", - "sha1": "903cf837f733bd977246afb84a16cf49e25f0b92" + "path": "com/vladsch/flexmark/flexmark/0.64.6/flexmark-0.64.6.pom", + "sha1": "ff19594e0627972f4a53a8ed1d7e1c30b5ac2e5c" }, { "path": "commons-beanutils/commons-beanutils/1.6/commons-beanutils-1.6.pom", @@ -953,14 +969,6 @@ "path": "commons-cli/commons-cli/1.2/commons-cli-1.2.pom", "sha1": "e1b71e4b511c3c63f8b19d0302fe1d1c6e79035a" }, - { - "path": "commons-codec/commons-codec/1.10/commons-codec-1.10.jar", - "sha1": "4b95f4897fa13f2cd904aee711aeafc0c5295cd8" - }, - { - "path": "commons-codec/commons-codec/1.10/commons-codec-1.10.pom", - "sha1": "44b9477418d2942d45550f7e7c66c16262062d0e" - }, { "path": "commons-codec/commons-codec/1.11/commons-codec-1.11.jar", "sha1": "3acb4705652e16236558f0f4f2192cc33c3bd189" @@ -969,6 +977,14 @@ "path": "commons-codec/commons-codec/1.11/commons-codec-1.11.pom", "sha1": "093ee1760aba62d6896d578bd7d247d0fa52f0e7" }, + { + "path": "commons-codec/commons-codec/1.13/commons-codec-1.13.jar", + "sha1": "3f18e1aa31031d89db6f01ba05d501258ce69d2c" + }, + { + "path": "commons-codec/commons-codec/1.13/commons-codec-1.13.pom", + "sha1": "d3c2c675df030573f0d8b0e475e00d3a0f5235a4" + }, { "path": "commons-codec/commons-codec/1.2/commons-codec-1.2.jar", "sha1": "397f4731a9f9b6eb1907e224911c77ea3aa27a8b" @@ -1206,12 +1222,16 @@ "sha1": "d152f01fb849a11abbc3ef8d7ed0ae8e00b3b226" }, { - "path": "de/rototor/pdfbox/graphics2d/0.24/graphics2d-0.24.jar", - "sha1": "d6b5ec6e59188e97289edf5f680e544e5a3cc750" + "path": "de/rototor/pdfbox/graphics2d/0.32/graphics2d-0.32.jar", + "sha1": "d8892871a9a1446e94f25eb625a7eec3bfa31b15" }, { - "path": "de/rototor/pdfbox/graphics2d/0.24/graphics2d-0.24.pom", - "sha1": "331d47196489033aa021cf4ecc37a17fc6005777" + "path": "de/rototor/pdfbox/graphics2d/0.32/graphics2d-0.32.pom", + "sha1": "a2f1f51988edd793c7354162e60b6657d630dac5" + }, + { + "path": "de/rototor/pdfbox/pdfboxgraphics2d-parent/0.32/pdfboxgraphics2d-parent-0.32.pom", + "sha1": "f7bf999b969ec2599db2a09b969539fcc6745121" }, { "path": "dk/brics/automaton/automaton/1.11-8/automaton-1.11-8.jar", @@ -1678,12 +1698,12 @@ "sha1": "de55d73a30c7521f3d55e8141d360ffbdfd88caa" }, { - "path": "org/apache/commons/commons-collections4/4.1/commons-collections4-4.1.jar", - "sha1": "a4cf4688fe1c7e3a63aa636cc96d013af537768e" + "path": "org/apache/commons/commons-collections4/4.3/commons-collections4-4.3.jar", + "sha1": "1c262f70f9b3c2351f1d13a9a9bd10d2ec7cfbc4" }, { - "path": "org/apache/commons/commons-collections4/4.1/commons-collections4-4.1.pom", - "sha1": "56c31f5fa1096fa1b33bf2813f2913412c47db2c" + "path": "org/apache/commons/commons-collections4/4.3/commons-collections4-4.3.pom", + "sha1": "10df23463e67877d44fdcf7c856c37d359a62091" }, { "path": "org/apache/commons/commons-compress/1.11/commons-compress-1.11.jar", @@ -1797,10 +1817,6 @@ "path": "org/apache/commons/commons-parent/35/commons-parent-35.pom", "sha1": "d88c24ebb385e5404f34573f24362b17434e3f33" }, - { - "path": "org/apache/commons/commons-parent/38/commons-parent-38.pom", - "sha1": "b1fe2a39dc1f76d14fbc402982938ffb5ba1043a" - }, { "path": "org/apache/commons/commons-parent/39/commons-parent-39.pom", "sha1": "4bc32d3cda9f07814c548492af7bf19b21798d46" @@ -1825,6 +1841,10 @@ "path": "org/apache/commons/commons-parent/47/commons-parent-47.pom", "sha1": "391715f2f4f1b32604a201a2f4ea74a174e1f21c" }, + { + "path": "org/apache/commons/commons-parent/48/commons-parent-48.pom", + "sha1": "1cdeb626cf4f0cec0f171ec838a69922efc6ef95" + }, { "path": "org/apache/commons/commons-parent/5/commons-parent-5.pom", "sha1": "a0a168281558e7ae972f113fa128bc46b4973edd" @@ -4750,32 +4770,32 @@ "sha1": "9813ead8dc1379522a51ff27ee4c8bbb0d356439" }, { - "path": "org/apache/pdfbox/fontbox/2.0.16/fontbox-2.0.16.jar", - "sha1": "3f7819279a0b90a01b07a870d1d27dffd8de24db" + "path": "org/apache/pdfbox/fontbox/2.0.24/fontbox-2.0.24.jar", + "sha1": "df8ecb3006dfcd52355a5902096e5ec34f06112e" }, { - "path": "org/apache/pdfbox/fontbox/2.0.16/fontbox-2.0.16.pom", - "sha1": "b7434809b761c67ed1adea2cd7f1a3aa4d978a36" + "path": "org/apache/pdfbox/fontbox/2.0.24/fontbox-2.0.24.pom", + "sha1": "0b0b787f24b546460706d50f93594e33522e8d0d" }, { - "path": "org/apache/pdfbox/pdfbox-parent/2.0.16/pdfbox-parent-2.0.16.pom", - "sha1": "9699fb292c6352544aff5ba662e182a622d3f2cf" + "path": "org/apache/pdfbox/pdfbox-parent/2.0.24/pdfbox-parent-2.0.24.pom", + "sha1": "46bb28d861f8d03db8c1ff972133a10f0d951124" }, { - "path": "org/apache/pdfbox/pdfbox/2.0.16/pdfbox-2.0.16.jar", - "sha1": "5dce5e41fc472d02800df5ef060a1f3a58c36902" + "path": "org/apache/pdfbox/pdfbox/2.0.24/pdfbox-2.0.24.jar", + "sha1": "cb562ee5f43e29415af4477e62fbe668ef88d18b" }, { - "path": "org/apache/pdfbox/pdfbox/2.0.16/pdfbox-2.0.16.pom", - "sha1": "97f1728b684282369ef547b3dd6823b38c04e11c" + "path": "org/apache/pdfbox/pdfbox/2.0.24/pdfbox-2.0.24.pom", + "sha1": "b76ada0618094445191770c138005c8b97e0b2a1" }, { - "path": "org/apache/pdfbox/xmpbox/2.0.16/xmpbox-2.0.16.jar", - "sha1": "efc4fd9fd83ba7a5ec6e5c2995df6b20f46bad11" + "path": "org/apache/pdfbox/xmpbox/2.0.24/xmpbox-2.0.24.jar", + "sha1": "df8b7a6a363281f9f1365ed4b37580aa5d3f38f1" }, { - "path": "org/apache/pdfbox/xmpbox/2.0.16/xmpbox-2.0.16.pom", - "sha1": "fc5c25638339e5197c22c70d9bf08efd2ece0928" + "path": "org/apache/pdfbox/xmpbox/2.0.24/xmpbox-2.0.24.pom", + "sha1": "4b83e73d0ef4b0580bce283e24d5dfce0fe49349" }, { "path": "org/apache/struts/struts-core/1.3.8/struts-core-1.3.8.jar", @@ -4870,12 +4890,12 @@ "sha1": "57e0b6a607859774b2cdd680c6f2aab147b83a4f" }, { - "path": "org/bouncycastle/bcprov-jdk15on/1.67/bcprov-jdk15on-1.67.jar", - "sha1": "8c0998045da87dbc2f1d4b6480458ed811ca7b82" + "path": "org/bouncycastle/bcprov-jdk15on/1.69/bcprov-jdk15on-1.69.jar", + "sha1": "91e1628251cf3ca90093ce9d0fe67e5b7dab3850" }, { - "path": "org/bouncycastle/bcprov-jdk15on/1.67/bcprov-jdk15on-1.67.pom", - "sha1": "c622f23fc3d1acf7c0cf66755ad7455781c4d489" + "path": "org/bouncycastle/bcprov-jdk15on/1.69/bcprov-jdk15on-1.69.pom", + "sha1": "c9f3e7d46996214727e0df730b2a6214b49a0ac0" }, { "path": "org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar", @@ -4886,8 +4906,12 @@ "sha1": "fb8dca6f40fcb30f7b89de269940bf3316fb9845" }, { - "path": "org/checkerframework/checker-qual/3.5.0/checker-qual-3.5.0.jar", - "sha1": "2f50520c8abea66fbd8d26e481d3aef5c673b510" + "path": "org/checkerframework/checker-qual/3.37.0/checker-qual-3.37.0.jar", + "sha1": "ba74746d38026581c12166e164bb3c15e90cc4ea" + }, + { + "path": "org/checkerframework/checker-qual/3.37.0/checker-qual-3.37.0.pom", + "sha1": "2b5c81b974afb0dad5a99ee7d2540a0bbb0c3555" }, { "path": "org/checkerframework/checker-qual/3.5.0/checker-qual-3.5.0.pom", @@ -6042,12 +6066,12 @@ "sha1": "34346a37a2ae0397ece7a64bb61c5618f32a91c6" }, { - "path": "org/jetbrains/annotations/15.0/annotations-15.0.jar", - "sha1": "d40ab99147584cf6cfb5245be67b3fee2c7220f9" + "path": "org/jetbrains/annotations/24.0.1/annotations-24.0.1.jar", + "sha1": "13c5c75c4206580aa4d683bffee658caae6c9f43" }, { - "path": "org/jetbrains/annotations/15.0/annotations-15.0.pom", - "sha1": "061c533b685552908a13ff6af0f6deb0d531b312" + "path": "org/jetbrains/annotations/24.0.1/annotations-24.0.1.pom", + "sha1": "1b582e5b99fdfe09ca6c2ebdfdf84b6ded77f49e" }, { "path": "org/jline/jline-parent/3.21.0/jline-parent-3.21.0.pom", @@ -6062,12 +6086,12 @@ "sha1": "bd03ef78247c946d6762aa7c72a7e4f1a2c13ce3" }, { - "path": "org/jsoup/jsoup/1.11.3/jsoup-1.11.3.jar", - "sha1": "36da09a8f68484523fa2aaa100399d612b247d67" + "path": "org/jsoup/jsoup/1.15.4/jsoup-1.15.4.jar", + "sha1": "cd56eb47dcd4590ef6451f87e5ec33bddd1a9a51" }, { - "path": "org/jsoup/jsoup/1.11.3/jsoup-1.11.3.pom", - "sha1": "0adf4b6abe306af443469df2a4ed4f201529cd37" + "path": "org/jsoup/jsoup/1.15.4/jsoup-1.15.4.pom", + "sha1": "444c1da89e9136358cfb7ba41b33fda946dffef0" }, { "path": "org/junit/junit-bom/5.7.2/junit-bom-5.7.2.pom", From 47ee46fd44707baf725afb96b483f9b0a027eb17 Mon Sep 17 00:00:00 2001 From: Bruce Collie Date: Thu, 2 Nov 2023 17:25:41 +0000 Subject: [PATCH 4/4] Bump LLVM version in packaging to 15 (#3783) In https://github.com/runtimeverification/llvm-backend/pull/874 we bumped the minimum version of LLVM required by the LLVM backend to 15; we can safely do this now as we no longer need to support Ubuntu Focal. This PR is the corresponding update to K; it updates any remaining references to LLVM 14 to LLVM 15. ~~Can be reviewed, but don't merge until https://github.com/runtimeverification/homebrew-k/pull/2 is merged~~ Will unblock: https://github.com/runtimeverification/k/pull/3782 --- .github/workflows/release.yml | 4 ++-- .github/workflows/test-pr.yml | 4 ++-- flake.nix | 2 +- package/debian/control.jammy | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bf86be01c72..13eb8a2728b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -102,7 +102,7 @@ jobs: with: os: ubuntu distro: jammy - llvm: 14 + llvm: 15 pkg-name: kframework_amd64_ubuntu_jammy.deb build-package: package/debian/build-package jammy test-package: package/debian/test-package @@ -349,7 +349,7 @@ jobs: tag: k-release-ci-${{ github.sha }} os: ubuntu distro: jammy - llvm: 14 + llvm: 15 - name: 'Push Maven Packages' shell: bash {0} diff --git a/.github/workflows/test-pr.yml b/.github/workflows/test-pr.yml index d13803a5e11..9e19850cbdb 100644 --- a/.github/workflows/test-pr.yml +++ b/.github/workflows/test-pr.yml @@ -109,7 +109,7 @@ jobs: tag: k-ci-${{ github.sha }} os: ubuntu distro: jammy - llvm: 14 + llvm: 15 - name: 'Build and Test K' run: docker exec -t k-ci-${GITHUB_SHA} /bin/bash -c 'mvn verify --batch-mode -U' - name: 'Check out k-exercises' @@ -142,7 +142,7 @@ jobs: with: os: ubuntu distro: jammy - llvm: 14 + llvm: 15 build-package: package/debian/build-package jammy test-package: package/debian/test-package - name: On Failure, Upload the kore-exec.tar.gz file to the Summary Page diff --git a/flake.nix b/flake.nix index 71381cc01b1..be8c7b8fb71 100644 --- a/flake.nix +++ b/flake.nix @@ -34,7 +34,7 @@ let allOverlays = [ (_: _: { - llvm-version = 13; + llvm-version = 15; llvm-backend-build-type = "Release"; }) mavenix.overlay llvm-backend.overlays.default diff --git a/package/debian/control.jammy b/package/debian/control.jammy index 2a08ce17c6c..8cd6ea1264d 100644 --- a/package/debian/control.jammy +++ b/package/debian/control.jammy @@ -2,7 +2,7 @@ Source: kframework Section: devel Priority: optional Maintainer: Dwight Guth -Build-Depends: clang-14 , cmake , debhelper (>=10) , flex , libboost-test-dev , libfmt-dev , libgmp-dev , libjemalloc-dev , libmpfr-dev , libsecp256k1-dev , libyaml-dev , maven , openjdk-17-jdk , pkg-config , python3 , python3-dev , python3-distutils , python3-pip , zlib1g-dev +Build-Depends: clang-15 , cmake , debhelper (>=10) , flex , libboost-test-dev , libfmt-dev , libgmp-dev , libjemalloc-dev , libmpfr-dev , libsecp256k1-dev , libyaml-dev , maven , openjdk-17-jdk , pkg-config , python3 , python3-dev , python3-distutils , python3-pip , zlib1g-dev Standards-Version: 3.9.6 Homepage: https://github.com/runtimeverification/k @@ -10,7 +10,7 @@ Package: kframework Architecture: any Section: devel Priority: optional -Depends: bison , clang-14 , openjdk-17-jre-headless , flex , gcc , g++ , libboost-dev , libffi-dev , libfmt-dev , libgmp-dev , libjemalloc-dev , libmpfr-dev , libsecp256k1-0 , libtinfo-dev , libyaml-0-2 , libz3-4 , lld-14 , llvm-14 , pkg-config +Depends: bison , clang-15 , openjdk-17-jre-headless , flex , gcc , g++ , libboost-dev , libffi-dev , libfmt-dev , libgmp-dev , libjemalloc-dev , libmpfr-dev , libsecp256k1-0 , libtinfo-dev , libyaml-0-2 , libz3-4 , lld-15 , llvm-15 , pkg-config Recommends: z3 Description: K framework toolchain Includes K Framework compiler for K language definitions, and K interpreter