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
+''