diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..34a178f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,2 @@ +[*.{kt,kts}] +ktlint_standard_no-wildcard-imports = disabled diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..342514a --- /dev/null +++ b/.envrc @@ -0,0 +1,2 @@ +watch_file *.nix +use flake . diff --git a/.gitignore b/.gitignore index b63da45..d1aa5ad 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,7 @@ build/ !**/src/test/**/build/ ### IntelliJ IDEA ### -.idea/modules.xml -.idea/jarRepositories.xml -.idea/compiler.xml -.idea/libraries/ +.idea *.iws *.iml *.ipr @@ -39,4 +36,6 @@ bin/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store + +/result diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml deleted file mode 100644 index 1bec35e..0000000 --- a/.idea/codeStyles/Project.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index 79ee123..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index ce1c62c..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml deleted file mode 100644 index df543e3..0000000 --- a/.idea/inspectionProfiles/Project_Default.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml deleted file mode 100644 index fdf8d99..0000000 --- a/.idea/kotlinc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 78d37bc..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index 2b63946..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 75d30cf..a9e342e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,32 +1,40 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +allprojects { + repositories { + System.getenv()["NIX_MAVEN_REPO"]?.let { + mavenLocal { + url = uri(it) + metadataSources { + mavenPom() + gradleMetadata() + } + } + } + ?: run { mavenCentral() } + } +} + plugins { - kotlin("jvm") version "1.8.21" - kotlin("plugin.serialization") version "1.9.0" + kotlin("jvm") version "1.9.23" + // kotlin("plugin.serialization") version "1.9.23" application } -group = "org.example" -version = "1.0-SNAPSHOT" +group = "io.quickstrom" -repositories { - mavenCentral() -} +version = "0.1.0" dependencies { - testImplementation(kotlin("test")) implementation("org.nineml:coffeegrinder:3.2.1") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") + // implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") + testImplementation(kotlin("test")) + testImplementation("io.kotest:kotest-runner-junit5:5.8.0") + testImplementation("io.kotest:kotest-assertions-core:5.8.0") } -tasks.test { - useJUnitPlatform() -} +tasks.test { useJUnitPlatform() } -tasks.withType { - kotlinOptions.jvmTarget = "1.8" -} +tasks.withType { kotlinOptions.jvmTarget = "21" } -application { - mainClass.set("MainKt") -} \ No newline at end of file +application { mainClass.set("MainKt") } diff --git a/build.nix b/build.nix new file mode 100644 index 0000000..42b3b14 --- /dev/null +++ b/build.nix @@ -0,0 +1,57 @@ +{ lib, stdenv, jdk, gradle_8, ktlint, callPackage }: +let + + buildMavenRepo = callPackage ./maven-repo.nix { }; + + mavenRepo = buildMavenRepo { + name = "nix-maven-repo"; + repos = [ + "https://repo1.maven.org/maven2" + "https://plugins.gradle.org/m2" + "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" + ]; + deps = builtins.fromJSON (builtins.readFile ./deps.json); + }; +in stdenv.mkDerivation { + pname = "specstrom"; + version = "0.1.0"; + + src = ./.; + + nativeBuildInputs = [ gradle_8 ktlint ]; + + JDK_HOME = "${jdk.home}"; + + buildPhase = '' + runHook preBuild + export GRADLE_USER_HOME=$(mktemp -d) + export NIX_MAVEN_REPO=${mavenRepo} + gradle build -x test \ + --offline --no-daemon \ + --warning-mode=all --parallel --console=plain \ + -PnixMavenRepo=${mavenRepo} + runHook postBuild + ''; + + doCheck = true; + checkPhase = '' + runHook preCheck + ktlint src/**/*.kt + export GRADLE_USER_HOME=$TMP/gradle-home + export NIX_MAVEN_REPO=${mavenRepo} + gradle check \ + --offline --no-daemon \ + --warning-mode=all --parallel --console=plain \ + -PnixMavenRepo=${mavenRepo} + runHook postCheck + ''; + + installPhase = '' + runHook preInstall + mkdir -p $out + cp -r build/distributions/* $out + runHook postInstall + ''; + + dontStrip = true; +} diff --git a/deps.json b/deps.json new file mode 100644 index 0000000..f5deeca --- /dev/null +++ b/deps.json @@ -0,0 +1,406 @@ +[ + { + "group": "org.apiguardian", + "name": "apiguardian-api", + "version": "1.1.0", + "artifacts": { + "apiguardian-api-1.1.0.jar": "a9aae9ff8ae3e17a2a18f79175e82b16267c246fbbd3ca9dfbbb290b08dcfdd4", + "apiguardian-api-1.1.0.pom": "a945b9cb5cd9b77b2c711844e659c43ec070ef59d9f509fa9f4c1861b4862711" + } + }, + { + "group": "org.jetbrains", + "name": "annotations", + "version": "13.0", + "artifacts": { + "annotations-13.0.jar": "ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478", + "annotations-13.0.pom": "965aeb2bedff369819bdde1bf7a0b3b89b8247dd69c88b86375d76163bb8c397" + } + }, + { + "group": "org.jetbrains.intellij.deps", + "name": "trove4j", + "version": "1.0.20200330", + "artifacts": { + "trove4j-1.0.20200330.jar": "c5fd725bffab51846bf3c77db1383c60aaaebfe1b7fe2f00d23fe1b7df0a439d", + "trove4j-1.0.20200330.pom": "87721cbaa65a3c97d8b1ba9d207840f164c9fe38759fc9ea10ffe26565f8d3e9" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-android-extensions", + "version": "1.9.23", + "artifacts": { + "kotlin-android-extensions-1.9.23.jar": "61fd7648f931ff4e9bdbff49bf0987705763fbba9c7bb00b264811a36d111ac1", + "kotlin-android-extensions-1.9.23.pom": "d3ebc593b173ad3e2d1e2560b69c3314a4690c8da3274721e83a96aedc1611a0" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-build-common", + "version": "1.9.23", + "artifacts": { + "kotlin-build-common-1.9.23.jar": "22825a1efe1549137d1813ed79dc9ccaf54b4a8a2700a4ac7f708dc660248baf", + "kotlin-build-common-1.9.23.pom": "d9e3c7e61f5849490014fe810bfc104a9e9a44d565ed186c586bbb3f4fc3d3fb" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-build-tools-api", + "version": "1.9.23", + "artifacts": { + "kotlin-build-tools-api-1.9.23.jar": "82f847e25457b464837efef1da8502ec92532de7406e79205166ce0ecf4fc521", + "kotlin-build-tools-api-1.9.23.pom": "096923b625c97c667367966cc4ce92bf94c4e9ff7c53cb1d38486011ac750d58" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-build-tools-impl", + "version": "1.9.23", + "artifacts": { + "kotlin-build-tools-impl-1.9.23.jar": "eac2f04665871955a7d0ae4571969df2b08e7d337b2f12210066fd3ee01f5981", + "kotlin-build-tools-impl-1.9.23.pom": "fce2f23c4e9f073b21768bdf56a31ad96d338cdc03d05a157a45a5fdb2ffedb1" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-compiler-embeddable", + "version": "1.9.23", + "artifacts": { + "kotlin-compiler-embeddable-1.9.23.jar": "cc94064974bf9ebf59945e31217cf2d16a0cebaaf2487eb0748fc1cbd1787943", + "kotlin-compiler-embeddable-1.9.23.pom": "58b23cd4d82d5aa916a5c9cc99b3218eec55696068a2f6b70beddf6c3691fd15" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-compiler-runner", + "version": "1.9.23", + "artifacts": { + "kotlin-compiler-runner-1.9.23.jar": "c8595a3e1711c7453c7f960aaf12a170db4bda3d6fcba49ffc8e32cbfd000ca1", + "kotlin-compiler-runner-1.9.23.pom": "29e6e312919b75fe9a3878df9511cf4210dc26e59341cb2ee22483b7b4e072fe" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-daemon-client", + "version": "1.9.23", + "artifacts": { + "kotlin-daemon-client-1.9.23.jar": "e63154254919fd706fe9937c48db937ea9068a631f86de655a514bc1620f988d", + "kotlin-daemon-client-1.9.23.pom": "5fbd066acb6e40853980276c6835169928f666ab7c46512c26f24c9d030817d3" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-daemon-embeddable", + "version": "1.9.23", + "artifacts": { + "kotlin-daemon-embeddable-1.9.23.jar": "6f3b661b98267ad24e2f8fb7ad5d06be7d2ed61a5d05c267f4e4caa78df783d9", + "kotlin-daemon-embeddable-1.9.23.pom": "58546038be46a383663853d131dd76c4fb2743830ba97b74b27a35cf102d3d02" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugin", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugin-1.9.23-gradle82.jar": "bcc74a07c69dd11c94b260b1ee8a618969629ccaeac2e6ea0a779da3c3f7ec3f", + "kotlin-gradle-plugin-1.9.23.module": "60bd8150704d581c8eead4c1940876e8b028afe8b14b494010c50920472544a7" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugin-annotations", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugin-annotations-1.9.23.jar": "1da8ad060a5bc382b04f157271d3cdad6830714a2f4df4af7c40088d4b922164", + "kotlin-gradle-plugin-annotations-1.9.23.pom": "ebd691734e90afd5a3e8fa2a913af0f90e982f86ba2185a170322a1b0890a605" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugin-api", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugin-api-1.9.23.jar": "593cc0842d5fc097b95e0a602bff8c7a489f73743b873cb0b8eec92fce8a415b", + "kotlin-gradle-plugin-api-1.9.23.module": "ce68bb21a9d6f20b7b0e729fe32f9a547bb64b25e310f0f5e2f70c509d67edc4" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugin-idea", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugin-idea-1.9.23.jar": "8d1af87632d95148f122a9fa0ae2903c19ee6fab7d01e017f76e0d2c9a022c20", + "kotlin-gradle-plugin-idea-1.9.23.module": "1beba2ba2b5113de0533e515e17f56d5364e9b54225ff31fb4d8fec9f715d82c" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugin-idea-proto", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugin-idea-proto-1.9.23.jar": "8bbfdad14d3c3c50b32bf6bfe0f1c7027be54285c46daf79827cf93b5cb43d7f", + "kotlin-gradle-plugin-idea-proto-1.9.23.pom": "c74729f4d605900121669b4110ed45baf55e075ab53b63a642b90b3aff793422" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugin-model", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugin-model-1.9.23.jar": "3e58dfae5e43fc88365f52df3a344208c0100c975a72a94a2c4a09f661d32317", + "kotlin-gradle-plugin-model-1.9.23.module": "12f9a5a25e580831179e5da3049a013118bd076cde0a452e668f2ab1609acfbd" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-gradle-plugins-bom", + "version": "1.9.23", + "artifacts": { + "kotlin-gradle-plugins-bom-1.9.23.module": "d72345e255bf20a3a97ab5d01086b608c5d7d0cf3f6778a71e85cacbad41425a", + "kotlin-gradle-plugins-bom-1.9.23.pom": "d88bdeeed9b944cac718cdcf2940f815d8225eeccd21beca07ddd081f0d2428c" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-klib-commonizer-api", + "version": "1.9.23", + "artifacts": { + "kotlin-klib-commonizer-api-1.9.23.jar": "5df1164db1c345d86d0a1aa414909e367afb9782fe3fbcaf0e2af7a8bf62b839", + "kotlin-klib-commonizer-api-1.9.23.pom": "b125a9d7d71c193847af92a2271c6551b3d29755454b1c85d374b24ae755c33e" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-klib-commonizer-embeddable", + "version": "1.9.23", + "artifacts": { + "kotlin-klib-commonizer-embeddable-1.9.23.jar": "b80a38b4bb81fb03d0f307473d032d73b2778fa76b0346387e5a10dd833d728e", + "kotlin-klib-commonizer-embeddable-1.9.23.pom": "88b0403b667f715257ea00d776216493382093eef6eef501b2553a1d52071b68" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-native-utils", + "version": "1.9.23", + "artifacts": { + "kotlin-native-utils-1.9.23.jar": "5fd01485bd73e617be556bff4992ff012aaeb9f0d9c0084f37cb5d88a3bcad84", + "kotlin-native-utils-1.9.23.pom": "78268bea5b8bf50a95ee76312ae363cc0bd6aadd5df47430ac135a206ef8ebb6" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-project-model", + "version": "1.9.23", + "artifacts": { + "kotlin-project-model-1.9.23.jar": "8fcb3ce512abb452d7d431dbb2c312d5c4505d1762493b51b106afc147d99367", + "kotlin-project-model-1.9.23.pom": "9ef4b2f3d9d9f59ab0c2bf7eb8ef763205149938e0e78d2a231c478921c79745" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-reflect", + "version": "1.6.10", + "artifacts": { + "kotlin-reflect-1.6.10.jar": "3277ac102ae17aad10a55abec75ff5696c8d109790396434b496e75087854203", + "kotlin-reflect-1.6.10.pom": "57905524274a00ae028aaccc27283f6bc5925a934a046c1cc5d06c8ee4d6d5a9" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-script-runtime", + "version": "1.9.23", + "artifacts": { + "kotlin-script-runtime-1.9.23.jar": "75137e414a1a5b4b4d090f812d0e35eb30b4f0c923a53d69585456bb24fc1df8", + "kotlin-script-runtime-1.9.23.pom": "2d6c74b06a540e989cabd0530a16e7658190525f2f4d5a43ab9b1afe7414fc5f" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-scripting-common", + "version": "1.9.23", + "artifacts": { + "kotlin-scripting-common-1.9.23.jar": "8a2e567f3dbf373e61c01acd7884631ec8538465ab8ee978ac63296f8cc9af46", + "kotlin-scripting-common-1.9.23.pom": "fc28975b94dc40c0d90fd1175e22b1b646bad2c637ebcf9f4f6ab2d4e7bc5dd5" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-scripting-compiler-embeddable", + "version": "1.9.23", + "artifacts": { + "kotlin-scripting-compiler-embeddable-1.9.23.jar": "7b8039ff0b779d556ced00923035abd1334f0e5f2a88796182d02ba45f926d20", + "kotlin-scripting-compiler-embeddable-1.9.23.pom": "ed8ebffebe5499ed62486fa818127bb5dd501d74c4ab95c57e7c01ef3f8db968" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-scripting-compiler-impl-embeddable", + "version": "1.9.23", + "artifacts": { + "kotlin-scripting-compiler-impl-embeddable-1.9.23.jar": "90e53dd12f62dcd82343c12c0cb314adcff0cbc3988edb118d1e6689960e9d63", + "kotlin-scripting-compiler-impl-embeddable-1.9.23.pom": "f76de498ed76c46ae86656679807f72761223c3fa10a1131832006a4ab395ded" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-scripting-jvm", + "version": "1.9.23", + "artifacts": { + "kotlin-scripting-jvm-1.9.23.jar": "d3fca7ec951ff7826f97a75989f8dcaff60cf9e1e76bbdc220edf778376a6e64", + "kotlin-scripting-jvm-1.9.23.pom": "e2ef2bfb2eb6f21a7b72ba12edc59a150c7f2176c2b2c54fe2e860ee80230d87" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-stdlib", + "version": "1.9.23", + "artifacts": { + "kotlin-stdlib-1.9.23-all.jar": "cec38bc3302e72a8aaf9cde436b5a9071ee0331e2ad05e84d8bb897334d7e9d4", + "kotlin-stdlib-1.9.23.jar": "8910cc238807d86ef550cb1f0b10dd5ed40b35a4ec1a52525f760aede84ead37", + "kotlin-stdlib-1.9.23.module": "5195193b37dcdada2e1c0ab0d512c422b2ad76af3557843a1b9c3480f4e71d0e" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-test", + "version": "1.9.23", + "artifacts": { + "kotlin-test-1.9.23.jar": "00a6ece9717b31d7f81b9a4a7da56440cfd2889aa2ee3b44c535d6499f400351", + "kotlin-test-1.9.23.module": "ff6f607021c4638dbaf5a670db590e6e8ab904f3f1dce0a5ae939c5e841d7469" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-test-annotations-common", + "version": "1.9.23", + "artifacts": { + "kotlin-test-annotations-common-1.9.23.jar": "f2819e2bc9ef078707912fc67116580b5381b576e956a0a5e586779586eb1eae", + "kotlin-test-annotations-common-1.9.23.pom": "24fd722dcfec72c5252fbe52296b51cfe98b59d27c3eece9618a899fb0d0c2b0" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-test-common", + "version": "1.9.23", + "artifacts": { + "kotlin-test-common-1.9.23.jar": "f9b756f8e154ed185fd721d1828947f0273c3c5d5f0f729ba0e7570c53c58872", + "kotlin-test-common-1.9.23.pom": "395089c75c85bbd41562865e77bef2c7aa5b156f51538e812aca1153bf546ff1" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-test-junit5", + "version": "1.9.23", + "artifacts": { + "kotlin-test-junit5-1.9.23.jar": "7f8b03b7cfa45689f2e6f1dd8943d124c5876b93b8ea7e76c1e0f7f954a5cf11", + "kotlin-test-junit5-1.9.23.module": "52eb11ec938ecfdad2c3c652d2c239d97bcea7e3b81b39c34921e107dab99778" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-tooling-core", + "version": "1.9.23", + "artifacts": { + "kotlin-tooling-core-1.9.23.jar": "8938eb97e36320daa3e6fb2a60fd2a05b232ff4a557173c5019f045b8832d9f4", + "kotlin-tooling-core-1.9.23.pom": "7e20345488fbbf5b9fe99787360bd3ec744a6fea91a699bd11b561c3281b07d8" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-util-io", + "version": "1.9.23", + "artifacts": { + "kotlin-util-io-1.9.23.jar": "7a6dce40e78acbe66fc7d678eb741c877845a3cfd1c76c4d2bbf8ec845d2d929", + "kotlin-util-io-1.9.23.pom": "acd1f237809ee275a9c09e4402dd4539d04dec368c0906ec79c3f803abf067c8" + } + }, + { + "group": "org.jetbrains.kotlin", + "name": "kotlin-util-klib", + "version": "1.9.23", + "artifacts": { + "kotlin-util-klib-1.9.23.jar": "e4018b6b8fbc91e4d0a37ab81c050a81396868075108cd85082b925c79d3bc6d", + "kotlin-util-klib-1.9.23.pom": "fb3e45847d5d212e4c2b5db44451903c9e1f0e32f6987e1f59b9cc11c4c3898a" + } + }, + { + "group": "org.jetbrains.kotlin.jvm", + "name": "org.jetbrains.kotlin.jvm.gradle.plugin", + "version": "1.9.23", + "artifacts": { + "org.jetbrains.kotlin.jvm.gradle.plugin-1.9.23.pom": "fe99a0eeb7d605bd207fa1b32c6e36b00174ae42c1b240c3f8cac07c5edeb4ca" + } + }, + { + "group": "org.jetbrains.kotlinx", + "name": "kotlinx-coroutines-core-jvm", + "version": "1.5.0", + "artifacts": { + "kotlinx-coroutines-core-jvm-1.5.0.jar": "78d6cc7135f84d692ff3752fcfd1fa1bbe0940d7df70652e4f1eaeec0c78afbb", + "kotlinx-coroutines-core-jvm-1.5.0.module": "c885dd0281076c5843826de317e3cbcdc3d8859dbeef53ae1cfacd1b9c60f96e" + } + }, + { + "group": "org.junit", + "name": "junit-bom", + "version": "5.6.3", + "artifacts": { + "junit-bom-5.6.3.module": "f37a30b1a76ae37058ebcaac66b9192a480455f4a8f2f285a35153d0578c8faa" + } + }, + { + "group": "org.junit.jupiter", + "name": "junit-jupiter-api", + "version": "5.6.3", + "artifacts": { + "junit-jupiter-api-5.6.3.jar": "26a22fe54dca351da9edccbcaa3c3cdcf25862cef3d2e04aa9363029a7beaa9d", + "junit-jupiter-api-5.6.3.module": "a516f54464c438801365e5e8baf422b2a6dd256c4a1e1c5948178c9bde48d2b8" + } + }, + { + "group": "org.junit.jupiter", + "name": "junit-jupiter-engine", + "version": "5.6.3", + "artifacts": { + "junit-jupiter-engine-5.6.3.jar": "980fbd50df3eeeb3e6b0868a22977148b3ac78cfae1dff3d593d656f2328dab1", + "junit-jupiter-engine-5.6.3.module": "c0f6e764d8af73d8a834f8f9ec0fd2a6a6376040b9379718bc48c63781c4a66c" + } + }, + { + "group": "org.junit.platform", + "name": "junit-platform-commons", + "version": "1.6.3", + "artifacts": { + "junit-platform-commons-1.6.3.jar": "49be6439351fdb50f0b7827e555acad26504a8084b6bc4019b2e6d73bc9da91a", + "junit-platform-commons-1.6.3.module": "a81366ff29d1107f0347f4be1f56e9e2340b186062fac1a18163f05e8269d3a1" + } + }, + { + "group": "org.junit.platform", + "name": "junit-platform-engine", + "version": "1.6.3", + "artifacts": { + "junit-platform-engine-1.6.3.jar": "de3b86523a65d824fa8e148c5ec510c4e034701b43100773f8c2e35da80ba0ec", + "junit-platform-engine-1.6.3.module": "3c248b3eba7baddb0309f9efca135328a9ce70dd32c20d4c1a2998d5afd0a071" + } + }, + { + "group": "org.nineml", + "name": "coffeegrinder", + "version": "3.2.1", + "artifacts": { + "coffeegrinder-3.2.1.jar": "334e9bc25baa12e5fd44414d25aaaa7b1fd783f87c044c767afa6ed6376cac21", + "coffeegrinder-3.2.1.module": "0acb0fd986b3a9906e1804fff3977c36a3f2cace7bf0878903be787f480081e1" + } + }, + { + "group": "org.opentest4j", + "name": "opentest4j", + "version": "1.2.0", + "artifacts": { + "opentest4j-1.2.0.jar": "58812de60898d976fb81ef3b62da05c6604c18fd4a249f5044282479fc286af2", + "opentest4j-1.2.0.pom": "a96e671816c1ff8803bdec74c9241f025bdfb277da5d2b4ee02266405936f994" + } + } +] diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..f0ad09f --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": [ + "systems" + ] + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1712608508, + "narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4cba8b53da471aea2ab2b0c1f30a81e7c451f4b6", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "systems": "systems" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..1324d84 --- /dev/null +++ b/flake.nix @@ -0,0 +1,23 @@ +{ + description = "Specstrom build and development setup"; + + inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; }; + + inputs.systems.url = "github:nix-systems/default"; + + inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.flake-utils.inputs.systems.follows = "systems"; + + outputs = { self, systems, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + updateLocks = pkgs.callPackage ./update-locks.nix { }; + in { + devShells.default = pkgs.mkShell { + buildInputs = + [ pkgs.gradle_8 pkgs.temurin-bin-21 updateLocks pkgs.ktlint ]; + }; + packages.default = pkgs.callPackage ./build.nix { }; + }); +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e583..7f93135 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 070cb70..b82aa23 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787..1aa94a4 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index ac1b06f..6689b85 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/maven-repo.nix b/maven-repo.nix new file mode 100644 index 0000000..72b7c27 --- /dev/null +++ b/maven-repo.nix @@ -0,0 +1,142 @@ +{ lib, stdenv, buildEnv, fetchurl, writeTextDir }: + +{ name ? "maven-deps", repos ? [ ], deps ? [ ], extraPaths ? [ ] }: + +with lib; + +let + mavenize = sep: replaceStrings [ "." ] [ sep ]; + + fetch = { group, name, version, file, sha256 }: + fetchurl { + name = file; + urls = + map (repo: "${repo}/${mavenize "/" group}/${name}/${version}/${file}") + repos; + inherit sha256; + meta.platforms = platforms.all; + }; + + fetchDependency = { group, name, version, artifacts }: + let + fetchArtifact = file: sha256: + fetch { inherit group name version file sha256; }; + + # Each artifact uses the filename in the Gradle cache, which doesn't + # correspond to the filename in the Maven repo. The mapping of name to URL + # is provided by Gradle module metadata, so we fetch that first. See + # https://github.com/gradle/gradle/blob/master/subprojects/docs/src/docs/design/gradle-module-metadata-latest-specification.md + # for the file format. + isModule = hasSuffix ".module"; + moduleArtifacts = filterAttrs (file: _: isModule file) artifacts; + otherArtifacts = filterAttrs (file: _: !isModule file) artifacts; + + modules = mapAttrsToList fetchArtifact moduleArtifacts; + + replacements = listToAttrs (flatten (map (module: + let + json = builtins.fromJSON (builtins.readFile module); + variants = json.variants or [ ]; + files = flatten (map (v: v.files or [ ]) variants); + in map ({ name, url, ... }: nameValuePair name url) files) modules)); + + replaced = mapAttrs' + (file: sha256: nameValuePair (replacements.${file} or file) sha256) + otherArtifacts; + in if moduleArtifacts == { } then + mapAttrsToList fetchArtifact artifacts + else + modules ++ (mapAttrsToList fetchArtifact replaced); + + mkDep = { group, name, version, artifacts }@dep: + stdenv.mkDerivation { + pname = "${mavenize "-" group}-${name}"; + inherit version; + + srcs = fetchDependency dep; + + sourceRoot = "."; + + phases = "installPhase"; + + enableParallelBuilding = true; + preferLocalBuild = true; + + installPhase = '' + dest=$out/${mavenize "/" group}/${name}/${version} + mkdir -p $dest + for src in $srcs; do + cp $src $dest/$(stripHash $src) + done + ''; + }; + + mkMetadata = deps: + let + modules = groupBy' (meta: + { group, name, version, ... }: + let + isNewer = versionOlder meta.latest version; + isNewerRelease = versionOlder meta.release version; + in { + groupId = group; + artifactId = name; + latest = if isNewer then version else meta.latest; + release = if isNewerRelease then version else meta.release; + versions = meta.versions ++ [ version ]; + }) { + latest = ""; + release = ""; + versions = [ ]; + } ({ group, name, ... }: + "${mavenize "/" group}/${name}/maven-metadata.xml") deps; + in attrValues (mapAttrs (path: + { groupId, artifactId, latest, release, versions }: + let versions' = sort versionOlder (unique versions); + in writeTextDir path '' + + + ${groupId} + ${artifactId} + + ${optionalString (latest != "") "${latest}"} + ${optionalString (release != "") "${release}"} + + ${ + concatMapStringsSep "\n " (v: "${v}") + versions' + } + + + + '') modules); + + mkGradleRedirectionPoms = deps: + let + depsMissingPoms = filter ({ artifacts, ... }@dep: + any (f: hasSuffix ".module" f) (attrNames artifacts) + && !(any (f: hasSuffix ".pom" f) (attrNames artifacts))) deps; + in map ({ group, name, version, ... }: + writeTextDir + "${mavenize "/" group}/${name}/${version}/${name}-${version}.pom" '' + + + + + + + 4.0.0 + ${group} + ${name} + ${version} + + '') depsMissingPoms; + +in buildEnv { + inherit name; + paths = map mkDep deps ++ mkMetadata deps ++ mkGradleRedirectionPoms deps + ++ extraPaths; +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 3c4d3e0..ec69f1a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,3 +1,19 @@ - rootProject.name = "specstrom" +pluginManagement { + repositories { + System.getenv()["NIX_MAVEN_REPO"]?.let { + mavenLocal { + url = uri(it) + metadataSources { + mavenPom() + gradleMetadata() + } + } + } + ?: run { + mavenCentral() + gradlePluginPortal() + } + } +} diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt index 3878dc4..314a6ec 100644 --- a/src/main/kotlin/Main.kt +++ b/src/main/kotlin/Main.kt @@ -1,78 +1,93 @@ package io.quickstrom.specstrom + import io.quickstrom.specstrom.io.quickstrom.specstrom.Decl import java.io.File import java.io.FileReader fun main(args: Array) { - val lex = Lexer("test.strom",FileReader(File("test.strom"))) + val lex = Lexer("test.strom", FileReader(File("test.strom"))) val p = Parser(lex) - var syntaxMap = mutableMapOf( - 0 to listOf ( - Parser.SyntaxRule("_+_",Parser.Assoc.Left), - Parser.SyntaxRule("_-_",Parser.Assoc.Left) + var syntaxMap = + mutableMapOf( + 0 to + listOf( + Parser.SyntaxRule("_+_", Parser.Assoc.Left), + Parser.SyntaxRule("_-_", Parser.Assoc.Left), + ), + ) + val primops: MutableMap = + mutableMapOf( + "_+_" to Value.ValOp(Value.ValOpType.PLUS, listOf()), + "_-_" to Value.ValOp(Value.ValOpType.MINUS, listOf()), ) - ); - val primops : MutableMap = mutableMapOf( - "_+_" to Value.ValOp(Value.ValOpType.PLUS, listOf()), - "_-_" to Value.ValOp(Value.ValOpType.MINUS, listOf()), - ) - var env = Scope(primops,null); - var thunkCache : MutableList = mutableListOf(); + var env = Scope(primops, null) + var thunkCache: MutableList = mutableListOf() while (true) { val dec = p.parseDecl(syntaxMap.toSortedMap()) when (dec) { is Decl.Syntax -> { - syntaxMap.merge(dec.prec,listOf(Parser.SyntaxRule(dec.name,dec.assoc))) { a, b -> a + b } + syntaxMap.merge(dec.prec, listOf(Parser.SyntaxRule(dec.name, dec.assoc))) { a, b -> a + b } } + is Decl.Let -> { when (dec.binding) { is Pattern.LazyPattern -> { - env.bindings.put(dec.binding.name, - Value.Thunk(env, dec.body, thunkCache.size, - Value.BindingData(dec.binding.name,dec.position))) - thunkCache.add(null); + env.bindings.put( + dec.binding.name, + Value.Thunk( + env, + dec.body, + thunkCache.size, + Value.BindingData(dec.binding.name, dec.position), + ), + ) + thunkCache.add(null) } + is Pattern.StrictPattern -> { - val eval = Eval(dec.body,env, thunkCache) + val eval = Eval(dec.body, env, thunkCache) eval.execute() when (eval.mode) { Eval.Mode.RETURN -> { - match(env.bindings,dec.binding, eval.value!!) + match(env.bindings, dec.binding, eval.value!!) eval.value!!.print() println() } + Eval.Mode.ERROR -> { println(eval.error) } + Eval.Mode.EVAL -> { TODO() } } - } } - } + is Decl.Function -> {} is Decl.Action -> {} is Decl.Exec -> { - val eval = Eval(dec.body,env, thunkCache) + val eval = Eval(dec.body, env, thunkCache) eval.execute() when (eval.mode) { Eval.Mode.RETURN -> { eval.value!!.print() println() } + Eval.Mode.ERROR -> { println(eval.error) } + Eval.Mode.EVAL -> { TODO() } } } + else -> {} } } - -} \ No newline at end of file +} diff --git a/src/main/kotlin/io/quickstrom/specstrom/Decl.kt b/src/main/kotlin/io/quickstrom/specstrom/Decl.kt index 65eb606..080fcfe 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Decl.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Decl.kt @@ -7,8 +7,12 @@ import io.quickstrom.specstrom.Positioned sealed class Decl : Positioned() { data class Function(val name: String, val bindings: List, val body: Expr) : Decl() + data class Action(val name: String, val bindings: List, val body: Expr) : Decl() - data class Syntax(val name: String, val prec : Int, val assoc: Parser.Assoc) : Decl() + + data class Syntax(val name: String, val prec: Int, val assoc: Parser.Assoc) : Decl() + data class Let(val binding: Pattern, val body: Expr) : Decl() + data class Exec(val body: Expr) : Decl() -} \ No newline at end of file +} diff --git a/src/main/kotlin/io/quickstrom/specstrom/Eval.kt b/src/main/kotlin/io/quickstrom/specstrom/Eval.kt index fecb401..86e111a 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Eval.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Eval.kt @@ -1,6 +1,10 @@ package io.quickstrom.specstrom -fun match(to : MutableMap, pat : Pattern.StrictPattern, value : Value) : Boolean { +fun match( + to: MutableMap, + pat: Pattern.StrictPattern, + value: Value, +): Boolean { when (pat) { is Pattern.Var -> { return if (to.containsKey(pat.name)) { @@ -8,7 +12,7 @@ fun match(to : MutableMap, pat : Pattern.StrictPattern, value : Va } else { to[pat.name] = value if (value is Value.Closure) { - value.metadata = Value.BindingData(pat.name,pat.position) + value.metadata = Value.BindingData(pat.name, pat.position) } true } @@ -20,49 +24,58 @@ fun match(to : MutableMap, pat : Pattern.StrictPattern, value : Va is Pattern.ListLit -> { if (value is Value.ListVal) { if (pat.elements.size != value.elements.size) return false - for ((x,y) in pat.elements.zip(value.elements)) { - if (!match(to,x,y)) return false + for ((x, y) in pat.elements.zip(value.elements)) { + if (!match(to, x, y)) return false } - } else return false + } else { + return false + } } is Pattern.Con -> { if (value is Value.Con && value.name == pat.conName) { if (pat.elements.size != value.elements.size) return false - for ((x,y) in pat.elements.zip(value.elements)) { - if (!match(to,x,y)) return false + for ((x, y) in pat.elements.zip(value.elements)) { + if (!match(to, x, y)) return false } - } else return false + } else { + return false + } } is Pattern.Record -> { if (value is Value.RecordVal) { - for ((k,v) in pat.elements) { + for ((k, v) in pat.elements) { val subValue = value.elements[k] ?: return false - if (!match(to,v,subValue)) + if (!match(to, v, subValue)) { return false + } } - } else return false + } else { + return false + } } } return true } -class Eval(e : Expr, env: Scope, thunkCache : MutableList) { +class Eval(e: Expr, env: Scope, thunkCache: MutableList) { enum class Mode { EVAL, RETURN, - ERROR + ERROR, } + enum class Error { VariableNotFound, NotAFunction, - Unknown + Unknown, } + var expr: Expr? = e var error: Error? = null var value: Value? = null var mode: Mode = Mode.EVAL val stack: ArrayDeque = ArrayDeque() - var env: Scope = Scope(mutableMapOf(),env) + var env: Scope = Scope(mutableMapOf(), env) val thunkCache: MutableList = thunkCache fun execute() { @@ -71,7 +84,7 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { return } Mode.EVAL -> { - when (val e : Expr? = expr) { + when (val e: Expr? = expr) { is Expr.IntLit -> { mode = Mode.RETURN value = Value.IntVal(e.value) @@ -103,7 +116,7 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { if (!iter.hasNext()) { mode = Mode.RETURN expr = null - value = Value.Con(e.name,listOf()) + value = Value.Con(e.name, listOf()) } else { val first = iter.next() stack.addLast(Frame.ConFrame(e.name, iter)) @@ -111,19 +124,19 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { } } is Expr.RecordLit -> { - val iter: ListIterator> = e.elements.listIterator() + val iter: ListIterator> = e.elements.listIterator() if (!iter.hasNext()) { mode = Mode.RETURN expr = null value = Value.RecordVal(mapOf()) } else { - val (key,keyExp) = iter.next() - stack.addLast(Frame.RecordFrame(key,iter)) + val (key, keyExp) = iter.next() + stack.addLast(Frame.RecordFrame(key, iter)) expr = keyExp } } is Expr.Lambda -> { - value = Value.Closure(this.env,e.binding, e.body) + value = Value.Closure(this.env, e.binding, e.body) expr = null mode = Mode.RETURN } @@ -136,7 +149,7 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { mode = Mode.RETURN expr = null } else { - stack.addLast(Frame.ThunkCallFrame(this.env,v.cacheIndex,v.metadata)) + stack.addLast(Frame.ThunkCallFrame(this.env, v.cacheIndex, v.metadata)) expr = v.body env = v.scope } @@ -182,13 +195,19 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { when (func.binding) { is Pattern.LazyPattern -> { stack.removeLast() - val hm : MutableMap = - mutableMapOf(func.binding.name to - Value.Thunk(env, f.right, thunkCache.size, - Value.BindingData(func.binding.name,func.binding.position))) + val hm: MutableMap = + mutableMapOf( + func.binding.name to + Value.Thunk( + env, + f.right, + thunkCache.size, + Value.BindingData(func.binding.name, func.binding.position), + ), + ) thunkCache.add(null) - stack.addLast(Frame.FunCallFrame (env,func.metadata)) - env = Scope (hm, func.scope) + stack.addLast(Frame.FunCallFrame(env, func.metadata)) + env = Scope(hm, func.scope) expr = func.body mode = Mode.EVAL value = null @@ -220,7 +239,7 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { if (!success) { value = Value.Null } else { - //TODO: TCO? + // TODO: TCO? stack.addLast(Frame.FunCallFrame(env, f.left.metadata)) env = Scope(hm, f.left.scope) expr = f.left.body @@ -247,7 +266,7 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { is Frame.ConFrame -> { expr = f.shift(value!!) if (expr == null) { - value = Value.Con(f.name,f.elements) + value = Value.Con(f.name, f.elements) } else { mode = Mode.EVAL value = null @@ -266,4 +285,4 @@ class Eval(e : Expr, env: Scope, thunkCache : MutableList) { } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/io/quickstrom/specstrom/Expr.kt b/src/main/kotlin/io/quickstrom/specstrom/Expr.kt index e982547..6800c65 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Expr.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Expr.kt @@ -1,17 +1,23 @@ package io.quickstrom.specstrom - sealed class Expr : Positioned() { data class BoolLit(val value: Boolean) : Expr() + data class IntLit(val value: Int) : Expr() + data class ListLit(val elements: List) : Expr() - data class RecordLit(val elements: List>) : Expr() + + data class RecordLit(val elements: List>) : Expr() + data class ConLit(val name: String, val elements: List) : Expr() + data class App(val left: Expr, val right: Expr) : Expr() + data class Lambda(val binding: Pattern, val body: Expr) : Expr() + data class Var(val name: String) : Expr() - fun at(pos : Position?) : Expr { + fun at(pos: Position?): Expr { position = pos return this } diff --git a/src/main/kotlin/io/quickstrom/specstrom/Frame.kt b/src/main/kotlin/io/quickstrom/specstrom/Frame.kt index ca85fc7..8999a63 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Frame.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Frame.kt @@ -3,33 +3,42 @@ package io.quickstrom.specstrom sealed class Frame : Positioned() { class ListFrame(private val elementsToGo: ListIterator) : Frame() { val elements: MutableList = mutableListOf() + fun shift(value: Value): Expr? { elements.add(value) if (!elementsToGo.hasNext()) return null return elementsToGo.next() } } - class RecordFrame(private var currentKey: String, private val elementsToGo: ListIterator>) : + + class RecordFrame(private var currentKey: String, private val elementsToGo: ListIterator>) : Frame() { val elements: MutableMap = mutableMapOf() + fun shift(value: Value): Expr? { elements[currentKey] = value if (!elementsToGo.hasNext()) return null - val (key,expr) = elementsToGo.next() + val (key, expr) = elementsToGo.next() currentKey = key return expr } } + class ConFrame(val name: String, private val elementsToGo: ListIterator) : Frame() { val elements: MutableList = mutableListOf() + fun shift(value: Value): Expr? { elements.add(value) if (!elementsToGo.hasNext()) return null return elementsToGo.next() } } + data class AppFrameLeft(val right: Expr) : Frame() + data class AppFrameRight(val left: Value) : Frame() - data class FunCallFrame(val env: Scope, val metadata : Value.BindingData?) : Frame() - data class ThunkCallFrame(val env: Scope, val index: Int, val metadata : Value.BindingData) : Frame() + + data class FunCallFrame(val env: Scope, val metadata: Value.BindingData?) : Frame() + + data class ThunkCallFrame(val env: Scope, val index: Int, val metadata: Value.BindingData) : Frame() } diff --git a/src/main/kotlin/io/quickstrom/specstrom/Lexer.kt b/src/main/kotlin/io/quickstrom/specstrom/Lexer.kt index 9de2a9d..0a097e9 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Lexer.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Lexer.kt @@ -4,15 +4,16 @@ import java.io.BufferedReader import java.io.PushbackReader import java.io.Reader - - -class Lexer(filename : String, reader : Reader) : Iterator { - class PositionedReader(var pos : Positioned.Position, reader : Reader) { - private val reader : PushbackReader = PushbackReader(BufferedReader(reader)) +class Lexer(filename: String, reader: Reader) : Iterator { + class PositionedReader(var pos: Positioned.Position, reader: Reader) { + private val reader: PushbackReader = PushbackReader(BufferedReader(reader)) var oldCol = 0 - fun read() : Int { + + fun read(): Int { val x = reader.read() - if (x == -1 || x == 65535) { return -1 } + if (x == -1 || x == 65535) { + return -1 + } if (x == '\n'.code) { pos.row += 1 oldCol = pos.col @@ -23,19 +24,22 @@ class Lexer(filename : String, reader : Reader) : Iterator { } return x } - fun unread(c : Int) { + + fun unread(c: Int) { reader.unread(c) if (c == '\n'.code) { pos.row -= 1 pos.col = oldCol - oldCol = 0 //this is a bug if we backtrack too much, but shouldn't happen + oldCol = 0 // this is a bug if we backtrack too much, but shouldn't happen } else { pos.col -= 1 oldCol = 0 } } } - private val reader = PositionedReader(Positioned.Position(filename,1,1), reader) + + private val reader = PositionedReader(Positioned.Position(filename, 1, 1), reader) + override fun hasNext(): Boolean { val x = reader.read() if (x < 0) return false @@ -48,9 +52,13 @@ class Lexer(filename : String, reader : Reader) : Iterator { return when (c.toChar()) { '(' -> Tok.LParen ')' -> Tok.RParen - else -> { reader.unread(c); null } + else -> { + reader.unread(c) + null + } } } + private fun lexInteger(): Tok? { var b = 0 var v: Int @@ -62,23 +70,30 @@ class Lexer(filename : String, reader : Reader) : Iterator { if (c.isDigit()) { b = b * 10 + c.digitToInt() read = true - } else break + } else { + break + } } reader.unread(v) return if (!read) null else Tok.IntLit(b) } + private fun lexSingleIdent(): Tok? { val v = reader.read() if (v < 0) return null return when (v.toChar()) { in "[]{};," -> Tok.Ident(v.toChar().toString()) - else -> { reader.unread(v); null } + else -> { + reader.unread(v) + null + } } } + private fun lexIdent(): Tok? { val b = StringBuilder() var v: Int - var type = 0; + var type = 0 while (true) { v = reader.read() if (v < 0) break @@ -88,15 +103,18 @@ class Lexer(filename : String, reader : Reader) : Iterator { b.append(c) } else if (type <= 0 && (c.isLetterOrDigit() || c in "'!?@#$")) { b.append(c) - type = -1; + type = -1 } else if (type >= 0 && !(c.isWhitespace() || c in "[]{};," || c in "()\"\'`")) { b.append(c) - type = 1; - } else break + type = 1 + } else { + break + } } reader.unread(v) return if (b.isEmpty()) null else Tok.Ident(b.toString()) } + private fun skipWhitespace() { var v: Int while (true) { @@ -107,9 +125,14 @@ class Lexer(filename : String, reader : Reader) : Iterator { } reader.unread(v) } + override fun next(): Tok { skipWhitespace() - val pos = Positioned.Position(reader.pos.file,reader.pos.row,reader.pos.col) - return (lexInteger() ?: lexParens() ?: lexSingleIdent() ?: lexIdent() ?: Tok.Unknown(reader.read().toChar())).at(pos) + val pos = Positioned.Position(reader.pos.file, reader.pos.row, reader.pos.col) + return ( + lexInteger() + ?: lexParens() ?: lexSingleIdent() ?: lexIdent() ?: Tok.Unknown(reader.read().toChar()) + ) + .at(pos) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/io/quickstrom/specstrom/Parser.kt b/src/main/kotlin/io/quickstrom/specstrom/Parser.kt index 6c7990c..e0da74d 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Parser.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Parser.kt @@ -10,56 +10,73 @@ import org.nineml.coffeegrinder.trees.GenericTree import org.nineml.coffeegrinder.trees.GenericTreeBuilder import java.util.* -class Parser(lex : Lexer) { +class Parser(lex: Lexer) { sealed interface SyntaxItem { - - fun show() : String + fun show(): String object Lower : SyntaxItem { override fun show(): String { return "_" } } + object Same : SyntaxItem { override fun show(): String { return "_" } } + object Any : SyntaxItem { override fun show(): String { return "_" } } - @JvmInline value class Ident(val name : String) : SyntaxItem { + + @JvmInline value class Ident(val name: String) : SyntaxItem { override fun show(): String { return name } } } + enum class Assoc { - Left, Right, None + Left, + Right, + None, } - class SyntaxRule(spec : String, assoc : Assoc) { - val bits : List + + class SyntaxRule(spec: String, assoc: Assoc) { + val bits: List + init { val strings = spec.split("_") - val strings2 = List(strings.size) { index -> listOf(strings[index], "_")} - .flatten().dropLast(1).filter { !it.isEmpty() } - bits = strings2.mapIndexed { index, str -> - if (str == "_") - if (index == 0 && assoc == Assoc.Left) SyntaxItem.Same - else if (index == 0) SyntaxItem.Lower - else if (index == strings2.lastIndex && assoc == Assoc.Right) SyntaxItem.Same - else if (index == strings2.lastIndex) SyntaxItem.Lower - else SyntaxItem.Any - else - SyntaxItem.Ident(str) - } + val strings2 = + List(strings.size) { index -> listOf(strings[index], "_") } + .flatten().dropLast(1).filter { !it.isEmpty() } + bits = + strings2.mapIndexed { index, str -> + if (str == "_") { + if (index == 0 && assoc == Assoc.Left) { + SyntaxItem.Same + } else if (index == 0) { + SyntaxItem.Lower + } else if (index == strings2.lastIndex && assoc == Assoc.Right) { + SyntaxItem.Same + } else if (index == strings2.lastIndex) { + SyntaxItem.Lower + } else { + SyntaxItem.Any + } + } else { + SyntaxItem.Ident(str) + } + } } } + var grammar = SourceGrammar() - var result : GearleyResult? = null - val lexer : Lexer = lex + var result: GearleyResult? = null + val lexer: Lexer = lex var anyExpr: NonterminalSymbol = grammar.getNonterminal("expression") var basicExpr: NonterminalSymbol = grammar.getNonterminal("basic expression") var exprList: NonterminalSymbol = grammar.getNonterminal("sequence of expressions") @@ -86,64 +103,74 @@ class Parser(lex : Lexer) { val colon = TerminalSymbol(Tok.Ident(":")) val semi = TerminalSymbol(Tok.Ident(";")) - fun setupGrammar(syntax : SortedMap>) { + fun setupGrammar(syntax: SortedMap>) { grammar = SourceGrammar() anyExpr = grammar.getNonterminal("expression") basicExpr = grammar.getNonterminal("basic expression") exprList = grammar.getNonterminal("sequence of expressions") fieldList = grammar.getNonterminal("sequence of field assignments") decl = grammar.getNonterminal("declaration") - grammar.addRule(exprList,) - grammar.addRule(exprList,anyExpr) - grammar.addRule(exprList,anyExpr,comma, exprList) - grammar.addRule(fieldList,) - grammar.addRule(fieldList,fieldName, colon, anyExpr) - grammar.addRule(fieldList,fieldName, colon, anyExpr,comma, fieldList) - grammar.addRule(basicExpr,identifier) - grammar.addRule(basicExpr,integer) - grammar.addRule(basicExpr,colon,identifier) - grammar.addRule(basicExpr,lParen,anyExpr,rParen) - grammar.addRule(basicExpr,lBracket,exprList,rBracket) - grammar.addRule(basicExpr,lBrace,fieldList,rBrace) - grammar.addRule(basicExpr,basicExpr,lParen, exprList, rParen) - grammar.addRule(basicExpr,tilde,identifier) - grammar.addRule(basicExpr,funKwd,lParen,exprList,rParen,lBrace,anyExpr, rBrace) + grammar.addRule(exprList) + grammar.addRule(exprList, anyExpr) + grammar.addRule(exprList, anyExpr, comma, exprList) + grammar.addRule(fieldList) + grammar.addRule(fieldList, fieldName, colon, anyExpr) + grammar.addRule(fieldList, fieldName, colon, anyExpr, comma, fieldList) + grammar.addRule(basicExpr, identifier) + grammar.addRule(basicExpr, integer) + grammar.addRule(basicExpr, colon, identifier) + grammar.addRule(basicExpr, lParen, anyExpr, rParen) + grammar.addRule(basicExpr, lBracket, exprList, rBracket) + grammar.addRule(basicExpr, lBrace, fieldList, rBrace) + grammar.addRule(basicExpr, basicExpr, lParen, exprList, rParen) + grammar.addRule(basicExpr, tilde, identifier) + grammar.addRule(basicExpr, funKwd, lParen, exprList, rParen, lBrace, anyExpr, rBrace) var lowerNonterminal = basicExpr - for ((k,rules) in syntax) { + for ((k, rules) in syntax) { val currentNonterminal = grammar.getNonterminal("(" + k.toString() + ")") grammar.addRule(currentNonterminal, lowerNonterminal) for (r in rules) { - grammar.addRule(currentNonterminal,r.bits.map { - when (it) { - is SyntaxItem.Ident -> TerminalSymbol(Tok.Ident(it.name)) - is SyntaxItem.Any -> anyExpr - is SyntaxItem.Lower -> lowerNonterminal - is SyntaxItem.Same -> currentNonterminal - } - }) + grammar.addRule( + currentNonterminal, + r.bits.map { + when (it) { + is SyntaxItem.Ident -> TerminalSymbol(Tok.Ident(it.name)) + is SyntaxItem.Any -> anyExpr + is SyntaxItem.Lower -> lowerNonterminal + is SyntaxItem.Same -> currentNonterminal + } + }, + ) } lowerNonterminal = currentNonterminal } grammar.addRule(anyExpr, lowerNonterminal) - grammar.addRule(decl,letKwd,anyExpr,equals,anyExpr, semi) - grammar.addRule(decl,syntaxKwd,identifier,integer, semi) - grammar.addRule(decl,syntaxKwd,identifier,integer,leftKwd, semi) - grammar.addRule(decl,syntaxKwd,identifier,integer,rightKwd, semi) - grammar.addRule(decl,execKwd,anyExpr, semi) + grammar.addRule(decl, letKwd, anyExpr, equals, anyExpr, semi) + grammar.addRule(decl, syntaxKwd, identifier, integer, semi) + grammar.addRule(decl, syntaxKwd, identifier, integer, leftKwd, semi) + grammar.addRule(decl, syntaxKwd, identifier, integer, rightKwd, semi) + grammar.addRule(decl, execKwd, anyExpr, semi) } - fun fromDecl(pt : GenericTree) : Decl { + fun fromDecl(pt: GenericTree): Decl { val p = pt as GenericBranch val kwd = p.children[0] as GenericLeaf when (kwd.token.value) { "syntax" -> { - return Decl.Syntax((pt.children[1] as GenericLeaf).token.value,((pt.children[2] as GenericLeaf).token as Tok.IntLit).value, - if (pt.children.size > 3 && (pt.children[3] as GenericLeaf).token.value == "left") { Parser.Assoc.Left } - else if (pt.children.size > 3 && (pt.children[3] as GenericLeaf).token.value == "right") { Parser.Assoc.Right } - else { Parser.Assoc.None} ) + return Decl.Syntax( + (pt.children[1] as GenericLeaf).token.value, + ((pt.children[2] as GenericLeaf).token as Tok.IntLit).value, + if (pt.children.size > 3 && (pt.children[3] as GenericLeaf).token.value == "left") { + Parser.Assoc.Left + } else if (pt.children.size > 3 && (pt.children[3] as GenericLeaf).token.value == "right") { + Parser.Assoc.Right + } else { + Parser.Assoc.None + }, + ) } "let" -> { - return Decl.Let(exprToPattern(fromAnyExpr(p.children[1])),fromAnyExpr(p.children[3])) + return Decl.Let(exprToPattern(fromAnyExpr(p.children[1])), fromAnyExpr(p.children[3])) } "exec" -> { return Decl.Exec(fromAnyExpr(p.children[1])) @@ -151,7 +178,8 @@ class Parser(lex : Lexer) { else -> TODO() } } - fun fromAnyExpr(pt : GenericTree) : Expr { + + fun fromAnyExpr(pt: GenericTree): Expr { var cur = pt while (cur is GenericBranch && cur.children.size == 1 && cur.symbol != basicExpr) { cur = cur.children[0] @@ -160,8 +188,8 @@ class Parser(lex : Lexer) { return fromBasicExpr(cur) } val name = StringBuilder() - val args : MutableList = mutableListOf() - var pos : Positioned.Position? = null + val args: MutableList = mutableListOf() + var pos: Positioned.Position? = null for (c in cur.children) { if (c is GenericBranch) { name.append('_') @@ -173,37 +201,43 @@ class Parser(lex : Lexer) { } } } - var func : Expr = Expr.Var(name.toString()).at(pos) + var func: Expr = Expr.Var(name.toString()).at(pos) for (arg in args) { func = Expr.App(func, arg).at(func.position) } return func - } - fun fromExprList(pt : GenericTree) : List { - var cur : GenericTree? = pt + + fun fromExprList(pt: GenericTree): List { + var cur: GenericTree? = pt val list = mutableListOf() while (cur is GenericBranch && cur.symbol == exprList) { if (!cur.children.isEmpty()) { list.add(fromAnyExpr(cur.children[0])) cur = if (cur.children.size == 3) cur.children[2] else null - } else break + } else { + break + } } return list } - fun fromFieldList(pt : GenericTree) : List> { - var cur : GenericTree? = pt - val list = mutableListOf>() + + fun fromFieldList(pt: GenericTree): List> { + var cur: GenericTree? = pt + val list = mutableListOf>() while (cur is GenericBranch && cur.symbol == fieldList) { if (!cur.children.isEmpty()) { - val p = Pair((cur.children[0] as GenericLeaf).token.value,fromAnyExpr(cur.children[2])); + val p = Pair((cur.children[0] as GenericLeaf).token.value, fromAnyExpr(cur.children[2])) list.add(p) cur = if (cur.children.size == 5) cur.children[4] else null - } else break; + } else { + break + } } return list } - fun fromBasicExpr(pt : GenericTree) : Expr { + + fun fromBasicExpr(pt: GenericTree): Expr { when (pt.children.size) { 1 -> { // literal return when (val v = (pt.children[0] as GenericLeaf).token) { @@ -211,13 +245,17 @@ class Parser(lex : Lexer) { else -> Expr.Var(v.value).at((v as Tok).position) } } - 2 -> { //constructor literal or lazy pattern + 2 -> { // constructor literal or lazy pattern val c0 = pt.children[0] if (c0 is GenericLeaf && c0.token.value == ":") { return Expr.ConLit((pt.children[1] as GenericLeaf).token.value, listOf()).at((c0.token as Tok).position) } else if (c0 is GenericLeaf) { - return Expr.App(Expr.Var("~_").at((c0.token as Tok).position), - Expr.Var((pt.children[1] as GenericLeaf).token.value).at(((pt.children[1] as GenericLeaf).token as Tok).position)) + return Expr.App( + Expr.Var("~_").at((c0.token as Tok).position), + Expr.Var( + (pt.children[1] as GenericLeaf).token.value, + ).at(((pt.children[1] as GenericLeaf).token as Tok).position), + ) .at((c0.token as Tok).position) } } @@ -235,7 +273,7 @@ class Parser(lex : Lexer) { var func = fromBasicExpr(pt.children[0]) val args = fromExprList(pt.children[2]) if (func is Expr.ConLit) { - func = Expr.ConLit(func.name,func.elements + args).at(func.position) + func = Expr.ConLit(func.name, func.elements + args).at(func.position) } else { for (arg in args) { func = Expr.App(func, arg).at(func.position) @@ -247,7 +285,7 @@ class Parser(lex : Lexer) { val args = fromExprList(pt.children[2]) var body = fromAnyExpr(pt.children[5]) for (arg in args.reversed()) { - body = Expr.Lambda(exprToPattern(arg),body).at(((pt.children[0] as GenericLeaf).token as Tok).position) + body = Expr.Lambda(exprToPattern(arg), body).at(((pt.children[0] as GenericLeaf).token as Tok).position) } return body } @@ -255,9 +293,11 @@ class Parser(lex : Lexer) { } throw Exception() } - fun exprToPattern(exp : Expr) : Pattern { - return if (exp is Expr.App && exp.left is Expr.Var && exp.right is Expr.Var - && exp.left.name == "~_") { + + fun exprToPattern(exp: Expr): Pattern { + return if (exp is Expr.App && exp.left is Expr.Var && exp.right is Expr.Var && + exp.left.name == "~_" + ) { val ret = Pattern.LazyPattern(exp.right.name) ret.position = exp.left.position ret @@ -265,35 +305,40 @@ class Parser(lex : Lexer) { exprToStrictPattern(exp) } } - fun exprToStrictPattern(exp : Expr) : Pattern.StrictPattern { + + fun exprToStrictPattern(exp: Expr): Pattern.StrictPattern { return when (exp) { is Expr.Var -> Pattern.Var(exp.name) is Expr.App -> TODO() is Expr.BoolLit -> Pattern.BoolLit(exp.value) - is Expr.ConLit -> Pattern.Con(exp.name,exp.elements.map(::exprToStrictPattern)) + is Expr.ConLit -> Pattern.Con(exp.name, exp.elements.map(::exprToStrictPattern)) is Expr.IntLit -> Pattern.IntLit(exp.value) is Expr.Lambda -> TODO() is Expr.ListLit -> Pattern.ListLit(exp.elements.map(::exprToStrictPattern)) - is Expr.RecordLit -> Pattern.Record(buildMap { - for ((x,y) in exp.elements) { - put(x,exprToStrictPattern(y)) - } - }) + is Expr.RecordLit -> + Pattern.Record( + buildMap { + for ((x, y) in exp.elements) { + put(x, exprToStrictPattern(y)) + } + }, + ) }.at(exp.position) } - fun parseDecl(syntax : SortedMap>) : Decl { + + fun parseDecl(syntax: SortedMap>): Decl { setupGrammar(syntax) val opts = grammar.parserOptions opts.prefixParsing = true - result = if (result == null) { - val parser = grammar.getParser(opts,"declaration") - parser.parse(lexer) - } else { - result!!.continueParsing(grammar.getParser(opts, "declaration")) - } + result = + if (result == null) { + val parser = grammar.getParser(opts, "declaration") + parser.parse(lexer) + } else { + result!!.continueParsing(grammar.getParser(opts, "declaration")) + } val builder = GenericTreeBuilder() result!!.arborist.getTree(builder) return fromDecl(builder.tree) } - -} \ No newline at end of file +} diff --git a/src/main/kotlin/io/quickstrom/specstrom/Pattern.kt b/src/main/kotlin/io/quickstrom/specstrom/Pattern.kt index de50be6..efe559b 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Pattern.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Pattern.kt @@ -2,18 +2,23 @@ package io.quickstrom.specstrom sealed class Pattern : Positioned() { data class LazyPattern(val name: String) : Pattern() + sealed class StrictPattern : Pattern() { - fun at(pos : Position?) : StrictPattern { + fun at(pos: Position?): StrictPattern { position = pos return this } } + data class IntLit(val value: Int) : StrictPattern() + data class BoolLit(val value: Boolean) : StrictPattern() + data class ListLit(val elements: List) : StrictPattern() + data class Record(val elements: Map) : StrictPattern() - data class Con(val conName: String, val elements: List) : StrictPattern() - data class Var(val name: String) : StrictPattern() + data class Con(val conName: String, val elements: List) : StrictPattern() + data class Var(val name: String) : StrictPattern() } diff --git a/src/main/kotlin/io/quickstrom/specstrom/Positioned.kt b/src/main/kotlin/io/quickstrom/specstrom/Positioned.kt index ba7925b..0796836 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Positioned.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Positioned.kt @@ -2,5 +2,6 @@ package io.quickstrom.specstrom abstract class Positioned { data class Position(var file: String, var row: Int, var col: Int) + var position: Position? = null } diff --git a/src/main/kotlin/io/quickstrom/specstrom/Scope.kt b/src/main/kotlin/io/quickstrom/specstrom/Scope.kt index 5ac5de3..21ba2db 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Scope.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Scope.kt @@ -3,7 +3,7 @@ package io.quickstrom.specstrom data class Scope(val bindings: MutableMap, val next: Scope?) { fun lookup(id: String): Value? { var x: Value? = null - var it : Scope? = this + var it: Scope? = this while (it != null && x == null) { x = it.bindings[id] it = it.next diff --git a/src/main/kotlin/io/quickstrom/specstrom/Tok.kt b/src/main/kotlin/io/quickstrom/specstrom/Tok.kt index 375550b..a8e3edd 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Tok.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Tok.kt @@ -1,66 +1,78 @@ package io.quickstrom.specstrom -import org.nineml.coffeegrinder.tokens.Token; -sealed abstract class Tok : Token(listOf()) { +import org.nineml.coffeegrinder.tokens.Token - var position : Positioned.Position? = null - fun at(pos : Positioned.Position) : Tok { +abstract sealed class Tok : Token(listOf()) { + var position: Positioned.Position? = null + + fun at(pos: Positioned.Position): Tok { position = pos return this } - sealed abstract class TokSelector : Token(listOf()) { + abstract sealed class TokSelector : Token(listOf()) { object AnyIdent : TokSelector() { override fun matches(input: Token?): Boolean { return (input is Tok.Ident) } + override fun getValue(): String { return "[identifier]" } } + object FieldName : TokSelector() { override fun matches(input: Token?): Boolean { - return (input is Tok.Ident && input.name.all{ it.isLetterOrDigit() }) + return (input is Tok.Ident && input.name.all { it.isLetterOrDigit() }) } + override fun getValue(): String { return "[field name]" } } + object AnyInteger : TokSelector() { override fun matches(input: Token?): Boolean { return (input is Tok.IntLit) } + override fun getValue(): String { return "[integer]" } } } - data class Ident(val name : String) : Tok() { + + data class Ident(val name: String) : Tok() { override fun getValue(): String { return name } } - data class IntLit(val value : Int) : Tok() { + + data class IntLit(val value: Int) : Tok() { override fun getValue(): String { return value.toString() } } + object LParen : Tok() { override fun getValue(): String { return "(" } } + object RParen : Tok() { override fun getValue(): String { return ")" } } - data class Unknown(val c : Char) : Tok() { + + data class Unknown(val c: Char) : Tok() { override fun getValue(): String { return c.toString() } } + override fun matches(input: Token?): Boolean { return (input == this) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/io/quickstrom/specstrom/Value.kt b/src/main/kotlin/io/quickstrom/specstrom/Value.kt index 2f18012..624754b 100644 --- a/src/main/kotlin/io/quickstrom/specstrom/Value.kt +++ b/src/main/kotlin/io/quickstrom/specstrom/Value.kt @@ -1,17 +1,29 @@ package io.quickstrom.specstrom sealed interface Value { - data class BindingData(val name : String, val position: Positioned.Position?) + data class BindingData(val name: String, val position: Positioned.Position?) enum class ValOpType { - PLUS, MINUS, TIMES, DIVIDE, MOD, LESS, GREATER, LESSEQ, GREATEREQ, EQ, NEQ, NOT + PLUS, + MINUS, + TIMES, + DIVIDE, + MOD, + LESS, + GREATER, + LESSEQ, + GREATEREQ, + EQ, + NEQ, + NOT, } - data class ValOp(val primop : ValOpType, val args: List) : Value { + data class ValOp(val primop: ValOpType, val args: List) : Value { override fun print() { print(primop) } - fun applyTo(value : Value) : Value { + + fun applyTo(value: Value): Value { if (args.isEmpty()) { return when (primop) { ValOpType.NOT -> if (value is BoolVal) BoolVal(!value.value) else Null @@ -21,7 +33,7 @@ sealed interface Value { val c0 = args[0] if (primop == ValOpType.PLUS && c0 is IntVal && value is IntVal) { return IntVal(c0.value + value.value) - } else if (primop == ValOpType.MINUS && c0 is IntVal && value is IntVal) { + } else if (primop == ValOpType.MINUS && c0 is IntVal && value is IntVal) { return IntVal(c0.value - value.value) } else { return Null @@ -30,7 +42,6 @@ sealed interface Value { } } - @JvmInline value class IntVal(val value: Int) : Value { override fun print() { print(value) @@ -76,6 +87,7 @@ sealed interface Value { } } } + data class Con(val name: String, val elements: List) : Value { override fun print() { print(":") @@ -93,18 +105,21 @@ sealed interface Value { } } } + data class Closure(val scope: Scope, val binding: Pattern, val body: Expr) : Value { - var metadata : BindingData? = null + var metadata: BindingData? = null + override fun print() { print("") } - } - data class Thunk(val scope: Scope, val body: Expr, val cacheIndex: Int, var metadata : BindingData) : Value { + + data class Thunk(val scope: Scope, val body: Expr, val cacheIndex: Int, var metadata: BindingData) : Value { override fun print() { print("") } } + object Null : Value { override fun print() { print("null") diff --git a/update-locks.nix b/update-locks.nix new file mode 100644 index 0000000..4d83083 --- /dev/null +++ b/update-locks.nix @@ -0,0 +1,14 @@ +{ lib, writeShellScriptBin, gradle, yq }: + +writeShellScriptBin "update-locks" '' + set -eu -o pipefail + ${gradle}/bin/gradle dependencies --write-locks + ${gradle}/bin/gradle --write-verification-metadata sha256 dependencies + ${yq}/bin/xq ' + ."verification-metadata".components.component | + map({ group: ."@group", name: ."@name", version: ."@version", + artifacts: [([.artifact] | flatten | .[] | {(."@name"): .sha256."@value"})] | add + }) + ' gradle/verification-metadata.xml > deps.json + rm gradle/verification-metadata.xml +''