Merge branch 'main' into mirror

This commit is contained in:
Tony Garnock-Jones 2024-04-15 09:53:46 +02:00
commit 6d82440704
131 changed files with 2671 additions and 1750 deletions

View File

@ -16,13 +16,13 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.992.4",
"@preserves/core": "0.995.200",
"@syndicate-lang/core": "*",
"@syndicate-lang/html": "*",
"@syndicate-lang/ws-relay": "*"
},
"devDependencies": {
"@preserves/schema-cli": "0.992.5",
"@preserves/schema-cli": "0.995.201",
"@syndicate-lang/ts-plugin": "*",
"@syndicate-lang/tsc": "*",
"rollup": "^2.60",

View File

@ -1,6 +1,6 @@
let ?ds = dataspace
# Connect using <route [<ws "...">] <ref "syndicate" [] #[acowDB2/oI+6aSEC3YIxGg]>>
# Connect using <route [<ws "...">] <ref {oid: "syndicate" sig: #[acowDB2/oI+6aSEC3YIxGg]}>
<bind <ref {oid: "syndicate" key: #x""}> $ds #f>
# Connect using <route [<ws "...">] <noise { service: "syndicate", key: #x"21f6cd4e11e7e37711d6b3084ff18cded8fc8abf293aa47d43e8bb86dda65516" }>>

View File

@ -1,7 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { fromJS, Bytes, Dataspace, Ref, Sturdy, AnyValue, Reader, Schemas, Embedded, stringify } from "@syndicate-lang/core";
import { fromJS, Bytes, Dataspace, Ref, Sturdy, AnyValue, Reader, Schemas, stringify } from "@syndicate-lang/core";
import { boot as bootHtml, Anchor, template as html, HtmlFragments, GlobalEvent, UIAttribute, UIChangeableProperty } from "@syndicate-lang/html";
import { boot as bootWakeDetector, WakeEvent } from "./wake-detector";
import { boot as bootWsRelay } from "@syndicate-lang/ws-relay";
@ -46,12 +46,9 @@ function bootChat(ds: Ref) {
during G.ResolvePath({
"route": route,
"addr": $addr,
"control": $control_e: Embedded,
"resolved": G.Resolved.accepted($remoteDs_e: Embedded),
"control": $control: Ref,
"resolved": G.Resolved.accepted($remoteDs: Ref),
}) => {
const remoteDs = remoteDs_e.embeddedValue;
const control = control_e.embeddedValue;
on message WakeEvent() => at control {
send message G.ForceDisconnect();
}

View File

@ -2,30 +2,30 @@
# yarn lockfile v1
"@preserves/core@0.992", "@preserves/core@^0.992.2":
version "0.992.2"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.992.2.tgz#b3acc7badd25ccccbf8e034bb641c6cfad987c41"
integrity sha512-aibJ8c9mLcCf3MhXeLWv0hevfkHgu3pJmBDzhN9AGXMIw0/fO3uEEnLM1oPaFIPWnQG4WybiXTUh2wD1CoxABg==
"@preserves/core@0.995.200", "@preserves/core@^0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@preserves/schema-cli@0.992":
version "0.992.2"
resolved "https://registry.yarnpkg.com/@preserves/schema-cli/-/schema-cli-0.992.2.tgz#53defa05b0bd34cf5032255d761076797254ce8f"
integrity sha512-ICJ0fqj3haJZosU7h8APm3GkoUaZs+BHKfj80BD8wuBf4iSLa4GAYASYThLZT/tlxU2iK1j4NghrG6/tCIj99w==
"@preserves/schema-cli@0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema-cli/-/schema-cli-0.995.201.tgz#e87cb7ba51b225ff6ea96f177c5388907adf6717"
integrity sha512-n/lpVgWBY1UTRySPXIwWG4Yu87OrQ9b7Xo8zPPQzD/DJDTEDT3y3SUujY7UTF1pQn09xRGnfPnDu1RoRCv2J3w==
dependencies:
"@preserves/core" "^0.992.2"
"@preserves/schema" "^0.992.2"
"@preserves/core" "^0.995.200"
"@preserves/schema" "^0.995.201"
chalk "^4.1"
chokidar "^3.5"
commander "^7.2"
glob "^7.1"
minimatch "^3.0"
"@preserves/schema@0.992", "@preserves/schema@^0.992.2":
version "0.992.2"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.992.2.tgz#975598b166500adc79f0d4e0cf2ae6dea3c2c111"
integrity sha512-I1zM9EWY0URw2zuRHLyROqVA9uqGhzQjuCpnTC8MeJToPt+xwVCXGl/NJYKhgofB14ZAgKT98h6YrLDR3yR6ug==
"@preserves/schema@^0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.995.201.tgz#827ad539afb0fdf68ba885ee3ff43db0fd473aa5"
integrity sha512-0SuhwOEAfxtrAeOTZ8V1yNEcHHHEbfUmoFawrF+vzTQFNZRz/X3LF1FM6wOiJlHtb7tBr4B+rHXX8jfNrqrdkA==
dependencies:
"@preserves/core" "^0.992.2"
"@preserves/core" "^0.995.200"
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -36,52 +36,49 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.19.1.tgz#506e4e6e9f6a0b7bd0b5f6a61ad6e98c3a9ccae6"
integrity sha512-2CMtEhyb8cg/pcJWgEdsaPtb6TJS0EbgeHcvCRyEFm3gdENxrNHVpxTVznSNAJnZosMu1KbK735kkviH9etkjw==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.992"
"@preserves/schema" "0.992"
salty-crypto "0.3.1"
"@syndicate-lang/html@*":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/html/-/html-0.19.1.tgz#21611a6c5718f01c00ac3b18e191548a6dd16538"
integrity sha512-qr4T065GIuMAI3VKAsYmUWcDyqTq/yGQndrG/Ub+L1P2ivU3AbU/0cuFUQVgFIZmoW/iqG9BQzjIUV8xiOsArw==
version "0.33.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/html/-/html-0.33.0.tgz#c53e6bf8a52b17c3747f4270713a8c9234f984af"
integrity sha512-xhN6NZOgLxlAQOyWG0JAgtyF1e1yQvrpNh5RBAPnucFYC024yo1ggZ08+KiaulhsoIKvRbBE6FU6p9dDm4/tpQ==
dependencies:
"@syndicate-lang/core" "^0.19.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/ts-plugin@*":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.19.1.tgz#c7ecf4e836314e16d0849a539ab4b22f7d4c10aa"
integrity sha512-o7niu1QnhAONisil83jVnWK3ipwz8obB0iruJ1++W3nXEM2nW7yGPuJNyLwkk1cFuPzfknm/DFdf6WKz9CsJGw==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.34.0.tgz#df92f9044eeba528c80c41c5c9df49ee28902411"
integrity sha512-OCO6Hm0euz2hZk6tYTrJQNEM8iDBeQ/dgpW2a/UP52XSP6fYj0OvUVfn+35ZkIL64S+zDsJjL/6XFN05UZyRGA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.19.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/tsc@*":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.19.1.tgz#25d48aa1a29e51c983d1ab6d8ab184eed26b465a"
integrity sha512-Uul57ynMS3L6CRIponNyUQ4vmblA4iCXyIsjtsi3QktvFJ9DTV4MRJAXjq72662jjLneY/LKWuCPXFKG62PyQA==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.34.0.tgz#1056fba7f639bbf436d0c2ecd2717edc4c1e612a"
integrity sha512-Ufj3xsdXMbMCavWsEkX/pFyXRpNIWRW+LFew1icD14DoSLqyBcoUEvskolOSgkSzC53tDjbd4/LXDVofIjIyUA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.19.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
"@syndicate-lang/ws-relay@*":
version "0.20.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ws-relay/-/ws-relay-0.20.1.tgz#4d4fbc401e5eb8a474aedf5112f9e1de3391bff8"
integrity sha512-sv3r/eyQicBQFVJ8MrS2/OUOPtbr54fkgC6dGN0IdRIeMUFdsxn7HlF3Tumo9I9oOTMNL3Ye+Xkc0sKSLqm8ng==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ws-relay/-/ws-relay-0.34.0.tgz#8b450ef18b22ca8e0c159c7925a1068796ad2c71"
integrity sha512-PT24Pp+ol/wWMSp/6H8i5zu7CgXm5nh0UsfpxJ3ZpvWFs/rIsoMflL/g+C1Q4DW9oFTn6/WFs07VdSLmE2/Uog==
dependencies:
"@preserves/core" "0.992"
"@syndicate-lang/core" "^0.19.1"
"@syndicate-lang/core" "^0.32.0"
salty-crypto "0.3"
"@types/estree@0.0.39":
@ -120,9 +117,9 @@ balanced-match@^1.0.0:
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
version "2.3.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
brace-expansion@^1.1.7:
version "1.1.11"
@ -148,9 +145,9 @@ chalk@^4.1:
supports-color "^7.1.0"
chokidar@^3.5:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
@ -204,9 +201,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -12,6 +12,8 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.995.200",
"@preserves/schema": "0.995.201",
"@syndicate-lang/core": "*"
},
"devDependencies": {

View File

@ -2,17 +2,17 @@
# yarn lockfile v1
"@preserves/core@0.990", "@preserves/core@^0.990.0":
version "0.990.0"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.990.0.tgz#c57c1c3d5159fc17477a4205d5a94a78fbf5b1aa"
integrity sha512-Mx013USv9JU1SrtMxaJISETBy2LZ402xH8ZnQI4JzG6W27ZwGV36DQrXAfF0x6cOmZMGKwJNqQrvmFhh7mEn6w==
"@preserves/core@0.995.200", "@preserves/core@^0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@preserves/schema@0.990.1":
version "0.990.1"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.990.1.tgz#233e25855194ce0f6ffaa9968d59e50b7dc8635a"
integrity sha512-FdvH0peM7U+Yag8FUZ2CYqDTEWjX88+HWwAfVfndtGAwEOTyjqvAQib0aI9lRPPXHodtaNR9/mLFmZBqve80Ew==
"@preserves/schema@0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.995.201.tgz#827ad539afb0fdf68ba885ee3ff43db0fd473aa5"
integrity sha512-0SuhwOEAfxtrAeOTZ8V1yNEcHHHEbfUmoFawrF+vzTQFNZRz/X3LF1FM6wOiJlHtb7tBr4B+rHXX8jfNrqrdkA==
dependencies:
"@preserves/core" "^0.990.0"
"@preserves/core" "^0.995.200"
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -23,45 +23,43 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.18.1.tgz#5cd2931acdab76150c0406428521e4746e62f18b"
integrity sha512-90d0YJCZJVrkxLe+fs5Z+vgigU3wux8VOnPje2E8Q/MXXecjHcBCQWQfcdwUxBdfPSFq9KdQS7g7VFqhu3X7mA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.990"
"@preserves/schema" "0.990.1"
salty-crypto "0.3.1"
"@syndicate-lang/syndicatec@*":
version "0.18.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/syndicatec/-/syndicatec-0.18.2.tgz#e594f270705c3203a7e26420bc5df2b568977244"
integrity sha512-iUVKqxmiXMC8uYM5bXdyssY6mtVGI5RQRAtmtikji81XJoYb5pfqGlSkMB6n6x7Cde4OsrzeMJYTJ9q7LvEcsQ==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/syndicatec/-/syndicatec-0.34.0.tgz#f3b88507b633552fe1f41f24def5121c0cafeaeb"
integrity sha512-h3MPifJdXZTS3JVcvRG8GXMJMPBH4RYmJ3B7c2sjM826Pf6O8zT47Vuv1y2WyD9PS8BiSCI01uOR0W5AVJJT5w==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
"@syndicate-lang/ts-plugin@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.18.1.tgz#0567774f0d7cef6b498cf39bda6717bc334f7213"
integrity sha512-wQJhQxGLjf3cW2w9RUGToZofsd3iG6GQPTHtRYnAYjyiCdxSb7fhZf7TNRkRv3m20Q1XIUSTiLg3ChU+1I9eEA==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.34.0.tgz#df92f9044eeba528c80c41c5c9df49ee28902411"
integrity sha512-OCO6Hm0euz2hZk6tYTrJQNEM8iDBeQ/dgpW2a/UP52XSP6fYj0OvUVfn+35ZkIL64S+zDsJjL/6XFN05UZyRGA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/tsc@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.18.1.tgz#e56522052f792b8dad0bd21c6181b7c801ea893b"
integrity sha512-arNOK+0NnjCdg6lisOOBD4piMBAxV3OR5frDAQ+DI+44gruvY20Tzen2SFMre7vvr+xVkyQwiHH9VVrgtIQRkw==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.34.0.tgz#1056fba7f639bbf436d0c2ecd2717edc4c1e612a"
integrity sha512-Ufj3xsdXMbMCavWsEkX/pFyXRpNIWRW+LFew1icD14DoSLqyBcoUEvskolOSgkSzC53tDjbd4/LXDVofIjIyUA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
@ -137,9 +135,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -12,6 +12,8 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.995.200",
"@preserves/schema": "0.995.201",
"@syndicate-lang/core": "*"
},
"devDependencies": {

View File

@ -2,17 +2,17 @@
# yarn lockfile v1
"@preserves/core@0.990", "@preserves/core@^0.990.0":
version "0.990.0"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.990.0.tgz#c57c1c3d5159fc17477a4205d5a94a78fbf5b1aa"
integrity sha512-Mx013USv9JU1SrtMxaJISETBy2LZ402xH8ZnQI4JzG6W27ZwGV36DQrXAfF0x6cOmZMGKwJNqQrvmFhh7mEn6w==
"@preserves/core@0.995.200", "@preserves/core@^0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@preserves/schema@0.990.1":
version "0.990.1"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.990.1.tgz#233e25855194ce0f6ffaa9968d59e50b7dc8635a"
integrity sha512-FdvH0peM7U+Yag8FUZ2CYqDTEWjX88+HWwAfVfndtGAwEOTyjqvAQib0aI9lRPPXHodtaNR9/mLFmZBqve80Ew==
"@preserves/schema@0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.995.201.tgz#827ad539afb0fdf68ba885ee3ff43db0fd473aa5"
integrity sha512-0SuhwOEAfxtrAeOTZ8V1yNEcHHHEbfUmoFawrF+vzTQFNZRz/X3LF1FM6wOiJlHtb7tBr4B+rHXX8jfNrqrdkA==
dependencies:
"@preserves/core" "^0.990.0"
"@preserves/core" "^0.995.200"
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -23,27 +23,25 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.18.1.tgz#5cd2931acdab76150c0406428521e4746e62f18b"
integrity sha512-90d0YJCZJVrkxLe+fs5Z+vgigU3wux8VOnPje2E8Q/MXXecjHcBCQWQfcdwUxBdfPSFq9KdQS7g7VFqhu3X7mA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.990"
"@preserves/schema" "0.990.1"
salty-crypto "0.3.1"
"@syndicate-lang/tsc@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.18.1.tgz#e56522052f792b8dad0bd21c6181b7c801ea893b"
integrity sha512-arNOK+0NnjCdg6lisOOBD4piMBAxV3OR5frDAQ+DI+44gruvY20Tzen2SFMre7vvr+xVkyQwiHH9VVrgtIQRkw==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.34.0.tgz#1056fba7f639bbf436d0c2ecd2717edc4c1e612a"
integrity sha512-Ufj3xsdXMbMCavWsEkX/pFyXRpNIWRW+LFew1icD14DoSLqyBcoUEvskolOSgkSzC53tDjbd4/LXDVofIjIyUA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
@ -119,9 +117,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -12,6 +12,7 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.995.200",
"@syndicate-lang/core": "*"
},
"devDependencies": {

View File

@ -2,17 +2,10 @@
# yarn lockfile v1
"@preserves/core@0.990", "@preserves/core@^0.990.0":
version "0.990.0"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.990.0.tgz#c57c1c3d5159fc17477a4205d5a94a78fbf5b1aa"
integrity sha512-Mx013USv9JU1SrtMxaJISETBy2LZ402xH8ZnQI4JzG6W27ZwGV36DQrXAfF0x6cOmZMGKwJNqQrvmFhh7mEn6w==
"@preserves/schema@0.990.1":
version "0.990.1"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.990.1.tgz#233e25855194ce0f6ffaa9968d59e50b7dc8635a"
integrity sha512-FdvH0peM7U+Yag8FUZ2CYqDTEWjX88+HWwAfVfndtGAwEOTyjqvAQib0aI9lRPPXHodtaNR9/mLFmZBqve80Ew==
dependencies:
"@preserves/core" "^0.990.0"
"@preserves/core@0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -23,27 +16,25 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.18.1.tgz#5cd2931acdab76150c0406428521e4746e62f18b"
integrity sha512-90d0YJCZJVrkxLe+fs5Z+vgigU3wux8VOnPje2E8Q/MXXecjHcBCQWQfcdwUxBdfPSFq9KdQS7g7VFqhu3X7mA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.990"
"@preserves/schema" "0.990.1"
salty-crypto "0.3.1"
"@syndicate-lang/syndicatec@*":
version "0.18.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/syndicatec/-/syndicatec-0.18.2.tgz#e594f270705c3203a7e26420bc5df2b568977244"
integrity sha512-iUVKqxmiXMC8uYM5bXdyssY6mtVGI5RQRAtmtikji81XJoYb5pfqGlSkMB6n6x7Cde4OsrzeMJYTJ9q7LvEcsQ==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/syndicatec/-/syndicatec-0.34.0.tgz#f3b88507b633552fe1f41f24def5121c0cafeaeb"
integrity sha512-h3MPifJdXZTS3JVcvRG8GXMJMPBH4RYmJ3B7c2sjM826Pf6O8zT47Vuv1y2WyD9PS8BiSCI01uOR0W5AVJJT5w==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
@ -119,9 +110,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -12,6 +12,8 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.995.200",
"@preserves/schema": "0.995.201",
"@syndicate-lang/core": "*"
},
"devDependencies": {

View File

@ -2,17 +2,17 @@
# yarn lockfile v1
"@preserves/core@0.990", "@preserves/core@^0.990.0":
version "0.990.0"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.990.0.tgz#c57c1c3d5159fc17477a4205d5a94a78fbf5b1aa"
integrity sha512-Mx013USv9JU1SrtMxaJISETBy2LZ402xH8ZnQI4JzG6W27ZwGV36DQrXAfF0x6cOmZMGKwJNqQrvmFhh7mEn6w==
"@preserves/core@0.995.200", "@preserves/core@^0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@preserves/schema@0.990.1":
version "0.990.1"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.990.1.tgz#233e25855194ce0f6ffaa9968d59e50b7dc8635a"
integrity sha512-FdvH0peM7U+Yag8FUZ2CYqDTEWjX88+HWwAfVfndtGAwEOTyjqvAQib0aI9lRPPXHodtaNR9/mLFmZBqve80Ew==
"@preserves/schema@0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.995.201.tgz#827ad539afb0fdf68ba885ee3ff43db0fd473aa5"
integrity sha512-0SuhwOEAfxtrAeOTZ8V1yNEcHHHEbfUmoFawrF+vzTQFNZRz/X3LF1FM6wOiJlHtb7tBr4B+rHXX8jfNrqrdkA==
dependencies:
"@preserves/core" "^0.990.0"
"@preserves/core" "^0.995.200"
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -23,27 +23,25 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.18.1.tgz#5cd2931acdab76150c0406428521e4746e62f18b"
integrity sha512-90d0YJCZJVrkxLe+fs5Z+vgigU3wux8VOnPje2E8Q/MXXecjHcBCQWQfcdwUxBdfPSFq9KdQS7g7VFqhu3X7mA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.990"
"@preserves/schema" "0.990.1"
salty-crypto "0.3.1"
"@syndicate-lang/syndicatec@*":
version "0.18.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/syndicatec/-/syndicatec-0.18.2.tgz#e594f270705c3203a7e26420bc5df2b568977244"
integrity sha512-iUVKqxmiXMC8uYM5bXdyssY6mtVGI5RQRAtmtikji81XJoYb5pfqGlSkMB6n6x7Cde4OsrzeMJYTJ9q7LvEcsQ==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/syndicatec/-/syndicatec-0.34.0.tgz#f3b88507b633552fe1f41f24def5121c0cafeaeb"
integrity sha512-h3MPifJdXZTS3JVcvRG8GXMJMPBH4RYmJ3B7c2sjM826Pf6O8zT47Vuv1y2WyD9PS8BiSCI01uOR0W5AVJJT5w==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
@ -119,9 +117,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -3,6 +3,7 @@
<meta charset=utf-8>
<meta name="viewport" content="width=device-width, initial-scale=0.67, maximum-scale=0.67, user-scalable=no">
<link href="css/style.css" rel="stylesheet" type="text/css">
<script src="node_modules/@preserves/core/dist/preserves.js"></script>
<script src="node_modules/@syndicate-lang/core/dist/syndicate.js"></script>
<script src="node_modules/@syndicate-lang/html/dist/syndicate-html.js"></script>
<script src="node_modules/@syndicate-lang/timer/dist/syndicate-timer.js"></script>

View File

@ -12,6 +12,8 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.995.200",
"@preserves/schema": "0.995.201",
"@syndicate-lang/core": "*",
"@syndicate-lang/html": "*",
"@syndicate-lang/timer": "*"

View File

@ -1,7 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Record, Dataspace, Double, floatValue, Ref, stringify } from '@syndicate-lang/core';
import { Turn, Dataspace, Double, floatValue, Ref, Facet } from '@syndicate-lang/core';
import { boot as bootHtml, WindowEvent, template, Anchor } from '@syndicate-lang/html';
import { boot as bootTimer, PeriodicTick } from '@syndicate-lang/timer';
@ -86,9 +86,7 @@ function spawnGame(mainDs: Ref) {
on (ypos.value > BOARD_HEIGHT - FLAPPY_HEIGHT) {
ypos.value = BOARD_HEIGHT - FLAPPY_HEIGHT;
react {
assert GameOver();
}
assert GameOver();
}
}
@ -141,14 +139,14 @@ function spawnGame(mainDs: Ref) {
react {
const pipeNumber = nextPipe.value++;
spawn linked named ['pipe', pipeNumber] {
runPipe(pipeNumber);
runPipe(pipeNumber, Turn.activeFacet);
}
}
}
}
}
function runPipe(i: number) {
function runPipe(i: number, mainPipeFacet: Facet) {
const xlocation = (i + 1) * 324;
let ui = new Anchor();
@ -159,21 +157,17 @@ function spawnGame(mainDs: Ref) {
+ PILLAR_HEAD_HEIGHT * 3;
const lowerHeight = FIELD_HEIGHT - upperHeight - PILLAR_GAP;
stop on (xpos.value < -(PILLAR_WIDTH + FLAPPY_XPOS));
stop mainPipeFacet on (xpos.value < -(PILLAR_WIDTH + FLAPPY_XPOS));
at gameDs {
react {
stop on (xpos.value <= 0) send message IncreaseScore();
}
once (xpos.value <= 0) send message IncreaseScore();
on asserted Position($flappyXpos, _) =>
xpos.value = xlocation - floatValue(flappyXpos);
on asserted Position($xpos, $ypos) => {
if (touchingPillar(floatValue(xpos), floatValue(ypos))) {
react {
assert GameOver();
}
assert GameOver();
}
}
}

View File

@ -2,17 +2,17 @@
# yarn lockfile v1
"@preserves/core@0.990", "@preserves/core@^0.990.0":
version "0.990.0"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.990.0.tgz#c57c1c3d5159fc17477a4205d5a94a78fbf5b1aa"
integrity sha512-Mx013USv9JU1SrtMxaJISETBy2LZ402xH8ZnQI4JzG6W27ZwGV36DQrXAfF0x6cOmZMGKwJNqQrvmFhh7mEn6w==
"@preserves/core@0.995.200", "@preserves/core@^0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@preserves/schema@0.990.1":
version "0.990.1"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.990.1.tgz#233e25855194ce0f6ffaa9968d59e50b7dc8635a"
integrity sha512-FdvH0peM7U+Yag8FUZ2CYqDTEWjX88+HWwAfVfndtGAwEOTyjqvAQib0aI9lRPPXHodtaNR9/mLFmZBqve80Ew==
"@preserves/schema@0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.995.201.tgz#827ad539afb0fdf68ba885ee3ff43db0fd473aa5"
integrity sha512-0SuhwOEAfxtrAeOTZ8V1yNEcHHHEbfUmoFawrF+vzTQFNZRz/X3LF1FM6wOiJlHtb7tBr4B+rHXX8jfNrqrdkA==
dependencies:
"@preserves/core" "^0.990.0"
"@preserves/core" "^0.995.200"
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -23,49 +23,47 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.18.1.tgz#5cd2931acdab76150c0406428521e4746e62f18b"
integrity sha512-90d0YJCZJVrkxLe+fs5Z+vgigU3wux8VOnPje2E8Q/MXXecjHcBCQWQfcdwUxBdfPSFq9KdQS7g7VFqhu3X7mA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.990"
"@preserves/schema" "0.990.1"
salty-crypto "0.3.1"
"@syndicate-lang/html@*":
version "0.18.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/html/-/html-0.18.2.tgz#276f70a209d90cf938eb27ebdddadfb1c299f234"
integrity sha512-VTMqrXLFvUQH/TWxTG+YZjUqymoNprde1bhJ2JQ1xyqlHAB82tYXZRJA+/qn93mFs6jCEN9vzvXyNbmJuyYH7Q==
version "0.33.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/html/-/html-0.33.0.tgz#c53e6bf8a52b17c3747f4270713a8c9234f984af"
integrity sha512-xhN6NZOgLxlAQOyWG0JAgtyF1e1yQvrpNh5RBAPnucFYC024yo1ggZ08+KiaulhsoIKvRbBE6FU6p9dDm4/tpQ==
dependencies:
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/timer@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/timer/-/timer-0.18.1.tgz#64f1364eaea77b9ec5b77d41a464baeadf32031b"
integrity sha512-49acCxOpOR4LgW9ENQ32+A/wF+fQgvAwhsBS4phzk3DB/Yj9opFZW5MOlMP4R9+iyoN1Nocwq0OO89QGnqg9Wg==
version "0.33.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/timer/-/timer-0.33.0.tgz#cdb38ebe777332ec58a5b0b9483db809275a61de"
integrity sha512-cBon+nk8zvNeU4zC6tg7nhgJnmrRoXHYE140UK3gscNFcg1LZ1d7q9WxfVTzFtRocRBslv6pworSwCDn3Go7TQ==
dependencies:
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/ts-plugin@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.18.1.tgz#0567774f0d7cef6b498cf39bda6717bc334f7213"
integrity sha512-wQJhQxGLjf3cW2w9RUGToZofsd3iG6GQPTHtRYnAYjyiCdxSb7fhZf7TNRkRv3m20Q1XIUSTiLg3ChU+1I9eEA==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.34.0.tgz#df92f9044eeba528c80c41c5c9df49ee28902411"
integrity sha512-OCO6Hm0euz2hZk6tYTrJQNEM8iDBeQ/dgpW2a/UP52XSP6fYj0OvUVfn+35ZkIL64S+zDsJjL/6XFN05UZyRGA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/tsc@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.18.1.tgz#e56522052f792b8dad0bd21c6181b7c801ea893b"
integrity sha512-arNOK+0NnjCdg6lisOOBD4piMBAxV3OR5frDAQ+DI+44gruvY20Tzen2SFMre7vvr+xVkyQwiHH9VVrgtIQRkw==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.34.0.tgz#1056fba7f639bbf436d0c2ecd2717edc4c1e612a"
integrity sha512-Ufj3xsdXMbMCavWsEkX/pFyXRpNIWRW+LFew1icD14DoSLqyBcoUEvskolOSgkSzC53tDjbd4/LXDVofIjIyUA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
@ -141,9 +139,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -3,6 +3,7 @@
<head>
<title>Syndicate: Table Example</title>
<meta charset="utf-8">
<script src="node_modules/@preserves/core/dist/preserves.js"></script>
<script src="node_modules/@syndicate-lang/core/dist/syndicate.js"></script>
<script src="node_modules/@syndicate-lang/html/dist/syndicate-html.js"></script>
</head>

View File

@ -14,6 +14,8 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"license": "GPL-3.0+",
"dependencies": {
"@preserves/core": "0.995.200",
"@preserves/schema": "0.995.201",
"@syndicate-lang/core": "*",
"@syndicate-lang/html": "*"
},

View File

@ -1,7 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Dataspace, Embedded, Value, Ref } from '@syndicate-lang/core';
import { Dataspace, Value, Ref } from '@syndicate-lang/core';
import { boot as bootHtml, UIEvent, GlobalEvent, HtmlFragments, template, Anchor } from '@syndicate-lang/html';
assertion type Person(id, firstName, lastName, address, age);
@ -42,7 +42,7 @@ Dataspace.boot(ds => {
spawn named 'controller' {
on message GlobalEvent('table#the-table th', 'click', $e) => {
const event = (e as Embedded<Ref>).embeddedValue.target.data as Event;
const event = (e as Ref).target.data as Event;
send message SetSortColumn(JSON.parse((event.target as HTMLElement).dataset.column!));
}
}

View File

@ -2,17 +2,17 @@
# yarn lockfile v1
"@preserves/core@0.990", "@preserves/core@^0.990.0":
version "0.990.0"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.990.0.tgz#c57c1c3d5159fc17477a4205d5a94a78fbf5b1aa"
integrity sha512-Mx013USv9JU1SrtMxaJISETBy2LZ402xH8ZnQI4JzG6W27ZwGV36DQrXAfF0x6cOmZMGKwJNqQrvmFhh7mEn6w==
"@preserves/core@0.995.200", "@preserves/core@^0.995.200":
version "0.995.200"
resolved "https://registry.yarnpkg.com/@preserves/core/-/core-0.995.200.tgz#65575cf8f9320e73b5d37fa9ac9d6881a33fd3a6"
integrity sha512-htZ2x+hltUpKoPsviWSuelzZW96po9zVSsN0RZEih60FahNX0R2LCqFJ6v5lyATuQ9oHALVi0w8w4rtf8oiAJw==
"@preserves/schema@0.990.1":
version "0.990.1"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.990.1.tgz#233e25855194ce0f6ffaa9968d59e50b7dc8635a"
integrity sha512-FdvH0peM7U+Yag8FUZ2CYqDTEWjX88+HWwAfVfndtGAwEOTyjqvAQib0aI9lRPPXHodtaNR9/mLFmZBqve80Ew==
"@preserves/schema@0.995.201":
version "0.995.201"
resolved "https://registry.yarnpkg.com/@preserves/schema/-/schema-0.995.201.tgz#827ad539afb0fdf68ba885ee3ff43db0fd473aa5"
integrity sha512-0SuhwOEAfxtrAeOTZ8V1yNEcHHHEbfUmoFawrF+vzTQFNZRz/X3LF1FM6wOiJlHtb7tBr4B+rHXX8jfNrqrdkA==
dependencies:
"@preserves/core" "^0.990.0"
"@preserves/core" "^0.995.200"
"@rollup/pluginutils@^3.0.9":
version "3.1.0"
@ -23,42 +23,40 @@
estree-walker "^1.0.1"
picomatch "^2.2.2"
"@syndicate-lang/compiler@^0.13.2":
version "0.13.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.13.2.tgz#e66de9f5828efb88ebe62266d014e13620961996"
integrity sha512-GQa7GVkerWxoVqY3NtRZXS8aLqIsVfdA8KvgNSDb8fTNV8TKGLDxQRurtcCiuEKG9mtfnDTpk8i28HbijKw6fA==
"@syndicate-lang/compiler@^0.21.1":
version "0.21.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/compiler/-/compiler-0.21.1.tgz#b6316bac14d053c313b3442be68f532a60c47cb3"
integrity sha512-daaYh1i0XmoHt6eTtO4gWblfVKMjp9trwxqR62wUSONY3gtJ5Bn4hG3dMgfoMz2NvOWbJHaGz/95J0jRubITxA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.18.1":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.18.1.tgz#5cd2931acdab76150c0406428521e4746e62f18b"
integrity sha512-90d0YJCZJVrkxLe+fs5Z+vgigU3wux8VOnPje2E8Q/MXXecjHcBCQWQfcdwUxBdfPSFq9KdQS7g7VFqhu3X7mA==
"@syndicate-lang/core@*", "@syndicate-lang/core@^0.32.0":
version "0.32.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/core/-/core-0.32.0.tgz#0efbbff176cac2969c2b6ba70a19965add3a2c61"
integrity sha512-ERVXk0W1xLaKvUa79Ek74YvqfBU543cUTb2GJvp76TP5k1jA97q9GzhddicS/s8lqu8SUC1+IXmKiJk0NX2TWQ==
dependencies:
"@preserves/core" "0.990"
"@preserves/schema" "0.990.1"
salty-crypto "0.3.1"
"@syndicate-lang/html@*":
version "0.18.2"
resolved "https://registry.yarnpkg.com/@syndicate-lang/html/-/html-0.18.2.tgz#276f70a209d90cf938eb27ebdddadfb1c299f234"
integrity sha512-VTMqrXLFvUQH/TWxTG+YZjUqymoNprde1bhJ2JQ1xyqlHAB82tYXZRJA+/qn93mFs6jCEN9vzvXyNbmJuyYH7Q==
version "0.33.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/html/-/html-0.33.0.tgz#c53e6bf8a52b17c3747f4270713a8c9234f984af"
integrity sha512-xhN6NZOgLxlAQOyWG0JAgtyF1e1yQvrpNh5RBAPnucFYC024yo1ggZ08+KiaulhsoIKvRbBE6FU6p9dDm4/tpQ==
dependencies:
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/ts-plugin@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.18.1.tgz#0567774f0d7cef6b498cf39bda6717bc334f7213"
integrity sha512-wQJhQxGLjf3cW2w9RUGToZofsd3iG6GQPTHtRYnAYjyiCdxSb7fhZf7TNRkRv3m20Q1XIUSTiLg3ChU+1I9eEA==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/ts-plugin/-/ts-plugin-0.34.0.tgz#df92f9044eeba528c80c41c5c9df49ee28902411"
integrity sha512-OCO6Hm0euz2hZk6tYTrJQNEM8iDBeQ/dgpW2a/UP52XSP6fYj0OvUVfn+35ZkIL64S+zDsJjL/6XFN05UZyRGA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
"@syndicate-lang/tsc@*":
version "0.18.1"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.18.1.tgz#e56522052f792b8dad0bd21c6181b7c801ea893b"
integrity sha512-arNOK+0NnjCdg6lisOOBD4piMBAxV3OR5frDAQ+DI+44gruvY20Tzen2SFMre7vvr+xVkyQwiHH9VVrgtIQRkw==
version "0.34.0"
resolved "https://registry.yarnpkg.com/@syndicate-lang/tsc/-/tsc-0.34.0.tgz#1056fba7f639bbf436d0c2ecd2717edc4c1e612a"
integrity sha512-Ufj3xsdXMbMCavWsEkX/pFyXRpNIWRW+LFew1icD14DoSLqyBcoUEvskolOSgkSzC53tDjbd4/LXDVofIjIyUA==
dependencies:
"@syndicate-lang/compiler" "^0.13.2"
"@syndicate-lang/core" "^0.18.1"
"@syndicate-lang/compiler" "^0.21.1"
"@syndicate-lang/core" "^0.32.0"
glob "^7.1.6"
yargs "^16.2.0"
@ -134,9 +132,9 @@ emoji-regex@^8.0.0:
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
version "3.1.2"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
estree-walker@^1.0.1:
version "1.0.1"

View File

@ -6,7 +6,7 @@
"packages/*/examples/*/"
],
"devDependencies": {
"@preserves/core": "0.992.4",
"@preserves/core": "0.995.200",
"@rollup/plugin-node-resolve": "^13.0",
"@types/jest": "^27.0",
"@types/node": "^14",

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
const SyndicateBrowserStdenv = {
autoboot: true,

View File

@ -1,6 +1,6 @@
{
"name": "@syndicate-lang/browser-stdenv",
"version": "0.23.3",
"version": "0.33.0",
"description": "Aggregated Syndicate and Preserves scripts for in-browser use",
"homepage": "https://github.com/syndicate-lang/syndicate-js/tree/main/packages/browser-stdenv",
"license": "GPL-3.0+",
@ -15,15 +15,15 @@
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"scripts": {
"prepare": "./build-aggregate.sh",
"clean": "rm -rf index.js index.min.js",
"clean": "rm -rf index.js index.min.js *.js.map",
"veryclean": "yarn run clean && rm -rf node_modules"
},
"dependencies": {
"@preserves/core": "0.992.4",
"@preserves/schema": "0.992.5",
"@syndicate-lang/compiler": "^0.18.0",
"@syndicate-lang/core": "^0.23.0",
"@syndicate-lang/html2": "^0.24.2",
"@syndicate-lang/ws-relay": "^0.25.0"
"@preserves/core": "0.995.200",
"@preserves/schema": "0.995.201",
"@syndicate-lang/compiler": "^0.21.1",
"@syndicate-lang/core": "^0.32.0",
"@syndicate-lang/html2": "^0.33.0",
"@syndicate-lang/ws-relay": "^0.34.0"
}
}

View File

@ -0,0 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export default {
preset: 'ts-jest',
testEnvironment: 'node',
};

View File

@ -1,6 +1,6 @@
{
"name": "@syndicate-lang/compiler",
"version": "0.18.0",
"version": "0.21.1",
"description": "Syndicate/JS compiler library",
"homepage": "https://github.com/syndicate-lang/syndicate-js/tree/main/packages/compiler",
"license": "GPL-3.0+",
@ -18,7 +18,13 @@
"rollup": "../../node_modules/.bin/rollup -c",
"rollup:watch": "../../node_modules/.bin/rollup -c -w",
"clean": "rm -rf lib dist",
"veryclean": "yarn run clean && rm -rf node_modules"
"veryclean": "yarn run clean && rm -rf node_modules",
"test": "../../node_modules/.bin/jest",
"test:watch": "yarn test --watch"
},
"devDependencies": {
"@types/js-beautify": "1.14",
"js-beautify": "1.15"
},
"main": "dist/syndicate-compiler.js",
"module": "lib/index.js",

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { SyndicateRollup } from '../../rollup.js';
const r = new SyndicateRollup('syndicate-compiler', { globalName: 'SyndicateCompiler' });

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import {
isToken, isTokenType, replace, commaJoin, startPos, fixPos, joinItems,
@ -7,7 +7,7 @@ import {
Items, Pattern, Templates, Substitution, TokenType,
SourceMap, CodeWriter, TemplateFunction, Token, SpanIndex, match, TokenBase, getRange, Pos,
} from '../syntax/index.js';
} from '../syntax/index';
import {
SyndicateParser, SyndicateTypedParser,
Identifier,
@ -17,7 +17,8 @@ import {
compilePattern,
SpawnStatement,
} from './grammar.js';
FacetToStop,
} from './grammar';
export function stripShebang(items: Items): Items {
if ((items.length > 0) &&
@ -116,20 +117,43 @@ function binderTypeGuard(t: TemplateFunction): (binder: Binder, index: number) =
export function expand(tree: Items, ctx: ExpansionContext): Items {
const macro = new Templates(undefined, { extraDelimiters: ':' });
function terminalWrap(t: TemplateFunction, isTerminal: boolean, body: Statement): Statement {
if (isTerminal) {
return t`__SYNDICATE__.Turn.active._stop(__SYNDICATE__.Turn.activeFacet, () => {${body}})`
function terminalWrap(
t: TemplateFunction,
facetToStop: FacetToStop | 'none' | 'once-wrapper',
body: Statement,
): Statement {
if (facetToStop === 'none') {
return walk(body);
} else {
return body;
const toStop =
facetToStop === 'default' ? 'currentSyndicateFacet' :
facetToStop === 'once-wrapper' ? '__once_facet' :
walk(facetToStop);
const resetCurrentSyndicateFacet =
facetToStop === 'once-wrapper' ? [] :
t`const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;`;
return t`__SYNDICATE__.Turn.active._stop(${toStop}, () => {${resetCurrentSyndicateFacet}${walk(body)}})`;
}
}
function facetWrap(t: TemplateFunction, items: Items): Items {
return t`__SYNDICATE__.Turn.active.facet(() => {${items}})`;
function facetWrap(
t: TemplateFunction,
facetName: Identifier | 'default' | 'once-wrapper',
items: Items,
): Items {
if (facetName === 'once-wrapper') {
return t`__SYNDICATE__.Turn.active.facet(() => {const __once_facet = __SYNDICATE__.Turn.activeFacet; ${items}});`;
} else {
const defaultLabel = t`const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet; `;
const customLabel = facetName === 'default'
? []
: t`const ${facetName.text} = currentSyndicateFacet; `;
return t`__SYNDICATE__.Turn.active.facet(() => {${defaultLabel}${customLabel}${items}});`;
}
}
function x<T>(p: Pattern<T>, f: (v: T, t: TemplateFunction) => Items) {
tree = replace(tree, p, (v, start) => f(v, macro.template(fixPos(start))));
tree = replace(tree, null, p, (v, start) => f(v, macro.template(fixPos(start))));
}
function xf<T extends TurnAction>(p: Pattern<T>, f: (v: T, t: TemplateFunction) => Items) {
@ -144,7 +168,7 @@ export function expand(tree: Items, ctx: ExpansionContext): Items {
// following transformations matters.
xf(ctx.parser.duringStatement, (s, t) => {
let spawn = match(ctx.parser.spawn, s.body, null);
let spawn = match(ctx.parser.spawn, s.body, null, null);
if (spawn !== null) {
if (spawn.linkedToken !== null) {
ctx.emitError(`during ... spawn doesn't need "linked", it's always linked`,
@ -155,7 +179,7 @@ export function expand(tree: Items, ctx: ExpansionContext): Items {
let body = (spawn === null)
? walk(s.body)
: expandSpawn(spawn, t, t`__SYNDICATE__.Turn.activeFacet.preventInertCheck();`);
: expandSpawn(spawn, t, t` __SYNDICATE__.Turn.activeFacet.preventInertCheck();`);
const sa = compilePattern(s.pattern);
const assertion = t`__SYNDICATE__.Observe({
@ -185,8 +209,9 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')}
? t`, new __SYNDICATE__.Set([${commaJoin(s.initialAssertions.map(walk))}])`
: ``;
*/
const n = spawn.name === void 0 ? '' : t` __SYNDICATE__.Turn.activeFacet.actor.name = ${walk(spawn.name)};`;
return t`__SYNDICATE__.Dataspace._spawn${spawn.linkedToken ? 'Link': ''}(() => {${n} ${inject} ${walk(spawn.body)} });`;
const f = t` const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;`;
const n = spawn.name === void 0 ? '' : t` currentSyndicateFacet.actor.name = ${walk(spawn.name)};`;
return t`__SYNDICATE__.Dataspace._spawn${spawn.linkedToken ? 'Link': ''}(() => {${f}${n}${inject}${walk(spawn.body)}});`;
}
x(ctx.parser.spawn, expandSpawn);
@ -226,10 +251,10 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')}
t`_dataflow(() => {${walk(s.body)}});`);
x(ctx.parser.eventHandlerEndpointStatement, (s, t) => {
const wrap = s.once ? (i: Items) => facetWrap(t, i) : (i: Items) => i;
const wrap = s.once ? (i: Items) => facetWrap(t, 'once-wrapper', i) : (i: Items) => i;
if (s.triggerType === 'dataflow') {
return wrap(t`__SYNDICATE__.Turn.active._dataflow(() => { if (${walk(s.predicate)}) { ${terminalWrap(t, s.terminal, walk(s.body))} } });`);
return wrap(t`__SYNDICATE__.Turn.active._dataflow(() => { if (${walk(s.predicate)}) { ${terminalWrap(t, s.facetToStop, s.body)} } });`);
}
if (s.triggerType === 'stop') {
@ -247,19 +272,19 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')}
case 'asserted':
entity = t`{
assert: (${ctx.argDecl(t, '__vs', '__SYNDICATE__.AnyValue')}, ${ctx.argDecl(t, '__handle', '__SYNDICATE__.Handle')}) => {
${guardBody(terminalWrap(t, s.terminal, walk(s.body)))}
${guardBody(terminalWrap(t, s.facetToStop, s.body))}
}
}`;
break;
case 'retracted':
entity = t`__SYNDICATE__.assertionObserver((${ctx.argDecl(t, '__vs', '__SYNDICATE__.AnyValue')}) => {
${guardBody(t`return () => { ${terminalWrap(t, s.terminal, walk(s.body))} };`)}
${guardBody(t`return () => { ${terminalWrap(t, s.facetToStop, s.body)} };`)}
})`;
break;
case 'message':
entity = t`{
message: (${ctx.argDecl(t, '__vs', '__SYNDICATE__.AnyValue')}) => {
${guardBody(terminalWrap(t, s.terminal, walk(s.body)))}
${guardBody(terminalWrap(t, s.facetToStop, s.body))}
}
}`;
break;
@ -294,10 +319,9 @@ ${joinItems(sa.captureBinders.map(binderTypeGuard(t)), '\n')}
xf(ctx.parser.messageSendStatement, (s, t) => t`message(currentSyndicateTarget, ${walk(s.expr)});`);
x(ctx.parser.reactStatement, (s, t) => facetWrap(t, s.body));
x(ctx.parser.reactStatement, (s, t) => facetWrap(t, s.label ?? 'default', s.body));
x(ctx.parser.stopStatement, (s, t) =>
t`__SYNDICATE__.Turn.active._stop(__SYNDICATE__.Turn.activeFacet, () => {${walk(s.body)}});`)
x(ctx.parser.stopStatement, (s, t) => t`${terminalWrap(t, s.facetToStop, s.body)};`);
return tree;
}

View File

@ -1,16 +1,17 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import {
Token, Items, TokenBase, TokenType,
Token, Items, TokenBase, TokenType, Pos,
Pattern,
foldItems, match, anonymousTemplate as template, commaJoin,
advancePos,
scope, bind, seq, alt, upTo, atom, atomString, group,
scope, bind, seq, seqTuple, alt, upTo, atom, atomString, group,
repeat, option, withoutSpace, map, mapm, rest, discard,
value, succeed, fail, separatedOrTerminatedBy, not,
} from '../syntax/index.js';
import * as Matcher from '../syntax/matcher.js';
} from '../syntax/index';
import * as Matcher from '../syntax/matcher';
//---------------------------------------------------------------------------
// AST types
@ -50,8 +51,14 @@ export interface StatementTurnAction extends TurnAction {
body: Statement;
}
export type FacetToStop = 'default' | Expr;
export interface StopStatement extends StatementTurnAction {
facetToStop: FacetToStop;
}
export interface GenericEventEndpointStatement extends StatementTurnAction {
terminal: boolean;
facetToStop: FacetToStop | 'none' | 'once-wrapper';
once: boolean;
isDynamic: boolean;
}
@ -90,6 +97,7 @@ export interface DuringStatement extends FacetSetupAction {
}
export interface ReactStatement extends FacetSetupAction {
label: Identifier | null;
}
export interface AtStatement {
@ -174,16 +182,29 @@ export class SyndicateParser {
return group('{', map(rest, items => (acc?.push(... items), items)));
}
readonly statementBoundary = alt<any>(atom(';'), Matcher.newline);
readonly statementBoundary = alt<any>(
atom(';'),
Matcher.newline,
seq(Matcher.end, i => {
if (i.context === null || i.context === '{') return discard(i);
// ^ toplevel, or inside braces, so presumably statement context
return fail(i); // otherwise, parens or brackets presumably, so not statement context
}),
);
readonly exprBoundary = alt<any>(atom(';'), atom(','), group('{', discard), Matcher.end);
readonly identifier: Pattern<Identifier> = atom();
get binder(): Pattern<Binder> { return scope(o => bind(o, 'id', this.identifier)); }
binder(... _extraStops: Pattern<any>[]): Pattern<Binder> { return scope(o => bind(o, 'id', this.identifier)); }
readonly defaultBinder = this.binder();
expr(... extraStops: Pattern<any>[]): Pattern<Expr> {
return withoutSpace(upTo(alt(this.exprBoundary, ... extraStops)));
}
expr1(... extraStops: Pattern<any>[]): Pattern<Expr> {
return mapm(this.expr(... extraStops), e => e.length ? succeed(e) : fail);
}
propertyNameExpr(): Pattern<Expr> {
const dq = template`"`;
return alt<Expr>(
@ -229,7 +250,7 @@ export class SyndicateParser {
map(scope(
(l: { b: Binder, init: Expr }) =>
seq(kw('let'),
bind(l, 'b', this.binder),
bind(l, 'b', this.defaultBinder),
atom('='),
bind(l, 'init', this.headerExpr))),
l => {
@ -243,7 +264,7 @@ export class SyndicateParser {
readonly fieldDeclarationStatement: Pattern<FieldDeclarationStatement> =
this.turnAction(o => {
return seq(atom('field'),
bind(o, 'field', this.binder),
bind(o, 'field', this.defaultBinder),
option(seq(atom('='), bind(o, 'init', this.expr()))),
this.statementBoundary);
});
@ -271,22 +292,25 @@ export class SyndicateParser {
mandatoryIfNotTerminal(o: GenericEventEndpointStatement, p: Pattern<any>): Pattern<any> {
return i => {
return (o.terminal) ? option(p)(i) : p(i);
return (o.facetToStop !== 'none') ? option(p)(i) : p(i);
};
}
// Principal: Turn
readonly eventHandlerEndpointStatement: Pattern<EventHandlerEndpointStatement> =
this.turnAction(o => {
o.terminal = false;
o.facetToStop = 'none';
o.once = false;
o.isDynamic = true;
o.body = [];
return seq(alt(seq(option(map(atom('stop'), _ => o.terminal = true)),
return seq(alt(seq(option(seq(atom('stop'),
map(option(this.expr1(atom('on'))), es => {
o.facetToStop = es.length ? es[0] : 'default';
}))),
atom('on')),
map(atom('once'), _ => {
o.terminal = true;
o.once = true;
o.facetToStop = 'once-wrapper';
})),
alt<any>(seq(map(group('(', bind(o as DataflowEndpointStatement, 'predicate',
this.expr())),
@ -294,7 +318,7 @@ export class SyndicateParser {
this.mandatoryIfNotTerminal(o, this.statement(o.body))),
mapm(seq(bind(o, 'triggerType', atomString('stop')),
option(this.statement(o.body))),
v => o.terminal ? fail : succeed(v)),
v => ((o.facetToStop !== 'none') || o.once) ? fail : succeed(v)),
seq(bind(o, 'triggerType',
alt(atomString('asserted'),
atomString('retracted'),
@ -311,7 +335,7 @@ export class SyndicateParser {
scope(o => seq(bind(o, 'expectedUse', alt(atomString('message'), atomString('assertion'))),
atom('type'),
bind(o, 'label', this.identifier),
group('(', bind(o, 'fields', repeat(this.binder, { separator: atom(',') }))),
group('(', bind(o, 'fields', repeat(this.defaultBinder, { separator: atom(',') }))),
option(seq(atom('='),
bind(o, 'wireName', withoutSpace(upTo(this.statementBoundary))))),
this.statementBoundary));
@ -338,12 +362,23 @@ export class SyndicateParser {
// Principal: Turn
readonly reactStatement: Pattern<ReactStatement> =
this.turnAction(o => {
o.label = null;
o.body = [];
return seq(atom('react'), this.block(o.body));
return seq(option(map(seqTuple(this.identifier, atom(':')),
([i, _colon]) => o.label = i)),
atom('react'),
this.block(o.body));
});
// Principal: Turn
readonly stopStatement = this.blockTurnAction(atom('stop'));
readonly stopStatement: Pattern<StopStatement> =
this.turnAction(o => {
o.facetToStop = 'default';
o.body = [];
return seq(atom('stop'),
option(map(this.expr1(), e => o.facetToStop = e)),
alt(this.block(o.body), this.statementBoundary));
});
// Principal: none
readonly atStatement: Pattern<AtStatement> =
@ -374,12 +409,22 @@ export class SyndicateParser {
// {expr: expr, ...} - constant
// other - constant
readonly pCaptureBinder: Pattern<Binder> =
mapm(this.binder, i => {
return i.id.text.startsWith('$')
? succeed({ id: { ... i.id, text: i.id.text.slice(1) }, type: i.type })
: fail;
pCaptureBinder = (b: Pattern<Binder>): Pattern<Binder> =>
mapm(b, i => {
if (i.id.text.startsWith('$')) {
const adjustedStart: Pos = { ... i.id.start };
advancePos(adjustedStart, ' ');
const adjustedId: Token = {
... i.id,
start: adjustedStart,
text: i.id.text.slice(1),
};
return succeed({ id: adjustedId, type: i.type });
} else {
return fail;
}
});
readonly pCaptureDefaultBinder = this.pCaptureBinder(this.defaultBinder);
readonly pDiscard: Pattern<void> =
mapm(this.identifier, i => i.text === '_' ? succeed(void 0) : fail);
@ -407,7 +452,7 @@ export class SyndicateParser {
hasCapturesOrDiscards(e: Expr): boolean {
return foldItems(e,
t => match(alt<any>(this.pCaptureBinder, this.pDiscard), [t], null) !== null,
t => match(alt<any>(this.pCaptureDefaultBinder, this.pDiscard), [t], null, '(') !== null,
(_g, b, _k) => b,
bs => bs.some(b => b));
}
@ -470,7 +515,7 @@ export class SyndicateParser {
// });
// } else
if (this.hasCapturesOrDiscards(o.ctor)) {
const r = match(this.pCaptureBinder, o.ctor, null);
const r = match(this.pCaptureDefaultBinder, o.ctor, null, '(');
if (r !== null && o.arguments.length === 1) {
return succeed({
type: 'PCapture',
@ -487,7 +532,7 @@ export class SyndicateParser {
scope<PCapture>(o => {
o.type = 'PCapture';
o.inner = { type: 'PDiscard' };
return bind(o, 'binder', this.pCaptureBinder);
return bind(o, 'binder', this.pCaptureBinder(this.binder(... extraStops)));
}),
map(this.expr(... extraStops), e => ({ type: 'PConstant', value: e }))
));
@ -495,10 +540,10 @@ export class SyndicateParser {
}
export class SyndicateTypedParser extends SyndicateParser {
get binder(): Pattern<Binder> {
binder(... extraStops: Pattern<any>[]): Pattern<Binder> {
return scope(o => seq(bind(o, 'id', this.identifier),
option(seq(atom(':'),
bind(o, 'type', this.type(atom('=')))))));
bind(o, 'type', this.type(atom('='), ... extraStops))))));
}
}

View File

@ -1,6 +1,6 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export * as Grammar from './grammar.js';
export * as Codegen from './codegen.js';
export { compile, CompileOptions } from './codegen.js';
export * as Grammar from './grammar';
export * as Codegen from './codegen';
export { compile, CompileOptions } from './codegen';

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export * as Syntax from './syntax/index.js';
export * from './compiler/index.js';
export * as Syntax from './syntax/index';
export * from './compiler/index';

View File

@ -1,10 +1,10 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Token, TokenType, Item, Items, isGroup } from './tokens.js';
import { Pos, startPos, advancePos } from './position.js';
import { vlqEncode } from './vlq.js';
import { SpanInfo } from './span.js';
import { Token, TokenType, Item, Items, isGroup } from './tokens';
import { Pos, startPos, advancePos } from './position';
import { vlqEncode } from './vlq';
import { SpanInfo } from './span';
export interface SourceMap {
version: 3;

View File

@ -1,13 +1,13 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export * from './codewriter.js';
export * from './list.js';
export * from './matcher.js';
export * from './position.js';
export * from './reader.js';
export * from './scanner.js';
export * from './span.js';
export * from './template.js';
export * from './tokens.js';
export * from './vlq.js';
export * from './codewriter';
export * from './list';
export * from './matcher';
export * from './position';
export * from './reader';
export * from './scanner';
export * from './span';
export * from './template';
export * from './tokens';
export * from './vlq';

View File

@ -1,26 +1,27 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export interface List<T> extends Iterable<T> {
export interface List<T, C> extends Iterable<T> {
item: T | null;
next: List<T> | null;
next: List<T, C> | null;
context: C;
toArray(): Array<T>;
}
export function atEnd<T>(xs: List<T>): xs is (List<T> & { item: null, next: null }) {
export function atEnd<T, C>(xs: List<T, C>): xs is (List<T, C> & { item: null, next: null }) {
return xs.item === null;
}
export function notAtEnd<T>(xs: List<T>): xs is (List<T> & { item: T, next: List<T> }) {
export function notAtEnd<T, C>(xs: List<T, C>): xs is (List<T, C> & { item: T, next: List<T, C> }) {
return xs.item !== null;
}
export class ArrayList<T> implements List<T> {
export class ArrayList<T, C> implements List<T, C> {
readonly items: Array<T>;
readonly index: number = 0;
constructor(items: Array<T>, index = 0) {
constructor(items: Array<T>, public context: C, index = 0) {
this.items = items;
this.index = index;
}
@ -29,9 +30,9 @@ export class ArrayList<T> implements List<T> {
return this.items[this.index] ?? null;
}
get next(): List<T> | null {
get next(): List<T, C> | null {
if (this.index >= this.items.length) return null;
return new ArrayList(this.items, this.index + 1);
return new ArrayList(this.items, this.context, this.index + 1);
}
toArray(): Array<T> {
@ -39,7 +40,7 @@ export class ArrayList<T> implements List<T> {
}
[Symbol.iterator](): Iterator<T> {
let i: List<T> = this;
let i: List<T, C> = this;
return {
next(): IteratorResult<T> {
if (notAtEnd(i)) {

View File

@ -1,34 +1,38 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import {
Token, TokenType, Items, Item,
isGroup, isToken, isSpace, isTokenType,
} from './tokens.js';
import { Pos, startPos } from './position.js';
import { List, ArrayList, atEnd, notAtEnd } from './list.js';
} from './tokens';
import { Pos, startPos } from './position';
import { List, ArrayList, atEnd, notAtEnd } from './list';
//---------------------------------------------------------------------------
// Patterns over Item
export type PatternResult<T> = [T, List<Item>] | null;
export type Pattern<T> = (i: List<Item>) => PatternResult<T>;
export type ItemContext = string /* the opener of the containing group, if any */ | null;
export type ItemList = List<Item, ItemContext>;
export type PatternResult<T> = [T, ItemList] | null;
export type Pattern<T> = (i: ItemList) => PatternResult<T>;
export function match<T,F>(p: Pattern<T>, items: Items, failure: F): T | F {
const r = p(new ArrayList(items));
export type PatternTypeArg<P> = P extends Pattern<infer T> ? T : never;
export function match<T,F>(p: Pattern<T>, items: Items, failure: F, context: ItemContext): T | F {
const r = p(new ArrayList(items, context));
if (r === null) return failure;
if (notAtEnd(skipSpace(r[1]))) return failure;
return r[0];
}
export const noItems = new ArrayList<Item>([]);
export const noItems = (c: ItemContext) => new ArrayList([], c);
export const fail: Pattern<never> = _i => null;
export function succeed<T>(t: T): Pattern<T> { return i => [t, i]; }
export const discard: Pattern<void> = _i => [void 0, noItems];
export const rest: Pattern<Items> = i => [i.toArray(), noItems];
export const end: Pattern<void> = i => atEnd(skipSpace(i)) ? [void 0, noItems] : null;
export const discard: Pattern<void> = i => [void 0, noItems(i.context)];
export const rest: Pattern<Items> = i => [i.toArray(), noItems(i.context)];
export const end: Pattern<void> = i => atEnd(skipSpace(i)) ? [void 0, noItems(i.context)] : null;
export const pos: Pattern<Pos> = i => notAtEnd(i) ? [i.item.start, i] : null;
export const newline: Pattern<Item> = i => {
@ -37,12 +41,12 @@ export const newline: Pattern<Item> = i => {
return [i.item, i.next];
};
export function skipSpace(i: List<Item>): List<Item> {
export function skipSpace(i: ItemList): ItemList {
while (notAtEnd(i) && isSpace(i.item)) i = i.next;
return i;
}
export function collectSpace(i: List<Item>, acc: Array<Item>): List<Item> {
export function collectSpace(i: ItemList, acc: Array<Item>): ItemList {
while (notAtEnd(i) && isSpace(i.item)) {
acc.push(i.item);
i = i.next;
@ -78,6 +82,22 @@ export function seq(... patterns: Pattern<any>[]): Pattern<any> {
};
}
export function seqTuple<Patterns extends [...Pattern<any>[]]>(
... patterns: Patterns
): Pattern<{ [I in keyof Patterns]: PatternTypeArg<Patterns[I]> } & { length: Patterns['length'] }>
{
return i => {
const rs = [];
for (const p of patterns) {
const r = p(i);
if (r === null) return null;
rs.push(r[0]);
i = r[1];
}
return [rs as unknown as PatternTypeArg<ReturnType<typeof seqTuple<Patterns>>>, i];
};
}
export function alt<T>(... alts: Pattern<T>[]): Pattern<T> {
return i => {
for (const a of alts) {
@ -115,7 +135,7 @@ export function bind<T, K extends keyof T>(target: T, key: K, pattern: Pattern<T
};
}
export function exec(thunk: (i: List<Item>) => void): Pattern<void> {
export function exec(thunk: (i: ItemList) => void): Pattern<void> {
return i => {
thunk(i);
return [void 0, i];
@ -156,7 +176,7 @@ export function group<T>(opener: string, items: Pattern<T>, options: GroupOption
if (!notAtEnd(i)) return null;
if (!isGroup(i.item)) return null;
if (i.item.open.text !== opener) return null;
const r = items(new ArrayList(i.item.items));
const r = items(new ArrayList(i.item.items, opener));
if (r === null) return null;
if (!atEnd(r[1])) return null;
return [r[0], (options.advance ?? true) ? i.next : i];
@ -203,7 +223,7 @@ export function upTo(p: Pattern<any>): Pattern<Items> {
export function separatedBy<T>(itemPattern: Pattern<T>, separator: Pattern<any>): Pattern<T[]> {
return i => {
const acc: T[] = [];
if (end(i) !== null) return [acc, noItems];
if (end(i) !== null) return [acc, noItems(i.context)];
while (true) {
{
const r = itemPattern(i);
@ -214,7 +234,7 @@ export function separatedBy<T>(itemPattern: Pattern<T>, separator: Pattern<any>)
{
const r = separator(i);
if (r === null) {
if (end(i) !== null) return [acc, noItems];
if (end(i) !== null) return [acc, noItems(i.context)];
return null;
}
i = r[1];
@ -229,7 +249,7 @@ export function separatedOrTerminatedBy<T>(
): Pattern<T[]> {
return i => {
const acc: T[] = [];
if (end(i) !== null) return [acc, noItems];
if (end(i) !== null) return [acc, noItems(i.context)];
while (true) {
{
const r = itemPattern(i);
@ -240,11 +260,11 @@ export function separatedOrTerminatedBy<T>(
{
const r = separator(i);
if (r === null) {
if (end(i) !== null) return [acc, noItems];
if (end(i) !== null) return [acc, noItems(i.context)];
return null;
} else {
i = r[1];
if (end(i) !== null) return [acc, noItems];
if (end(i) !== null) return [acc, noItems(i.context)];
}
}
}
@ -290,12 +310,13 @@ export function option<T>(p: Pattern<T>): Pattern<T[]> {
export function replace<T>(
items: Items,
outerContext: ItemContext,
p: Pattern<T>,
f: (t: T, start: Pos, end: Pos) => Items,
end: Pos = items.length > 0 ? items[items.length - 1].end : startPos(null)) : Items
{
const walkItems = (items: Items, end: Pos): Items => {
let i: List<Item> = new ArrayList(items);
end: Pos = items.length > 0 ? items[items.length - 1].end : startPos(null),
) : Items {
const walkItems = (items: Items, end: Pos, context: ItemContext): Items => {
let i: ItemList = new ArrayList(items, context);
const acc: Items = [];
while (notAtEnd(i = collectSpace(i, acc))) {
const r = p(i);
@ -309,11 +330,14 @@ export function replace<T>(
acc.push(i.item);
i = i.next;
} else {
acc.push({ ... i.item, items: walkItems(i.item.items, i.item.end) });
acc.push({
... i.item,
items: walkItems(i.item.items, i.item.end, i.item.open.text),
});
i = i.next;
}
}
return acc;
};
return walkItems(items, end);
return walkItems(items, end, outerContext);
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export interface Pos {
line: number;

View File

@ -1,9 +1,9 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { TokenType, Token, Group, GroupInProgress, Item, Items, finishGroup } from './tokens.js';
import { Pos, startPos } from './position.js';
import { Scanner, StringScanner } from './scanner.js';
import { TokenType, Token, Group, GroupInProgress, Item, Items, finishGroup } from './tokens';
import { Pos, startPos } from './position';
import { Scanner, StringScanner } from './scanner';
function matchingParen(c: string): string | null {
switch (c) {
@ -134,23 +134,10 @@ export class LaxReader implements IterableIterator<Item> {
case TokenType.SPACE:
case TokenType.NEWLINE:
case TokenType.ATOM:
this.drop();
if (g === null) {
this.drop();
return t;
}
if (t.text === ';') {
while ('(['.indexOf(g.open.text) >= 0) {
this.stack.pop();
const outer = this.stackTop();
if (outer === null) {
// do not drop the semicolon here
return finishGroup(g, t.start);
}
outer.items.push(finishGroup(g, t.start));
g = outer;
}
}
this.drop();
g.items.push(t);
break;

View File

@ -1,8 +1,8 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { TokenType, Token, Item, GroupInProgress } from './tokens.js';
import { Pos, advancePos } from './position.js';
import { TokenType, Token, Item, GroupInProgress } from './tokens';
import { Pos, advancePos } from './position';
export abstract class Scanner implements IterableIterator<Token> {
readonly pos: Pos;

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export class SpanResult<T> {
readonly searchTarget: number;

View File

@ -1,10 +1,10 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Items } from './tokens.js';
import { Pos, startPos } from './position.js';
import { laxRead, LaxReadOptions } from './reader.js';
import * as M from './matcher.js';
import { Items } from './tokens';
import { Pos, startPos } from './position';
import { laxRead, LaxReadOptions } from './reader';
import * as M from './matcher';
const substPat = M.scope((o: { pos: Pos }) =>
M.seq(M.atom('$'),
@ -29,7 +29,7 @@ export class Templates {
this.readOptions = readOptions;
}
template(start0: Pos | string = this.defaultPos): TemplateFunction {
template(start0: Pos | string = this.defaultPos, context: M.ItemContext = null): TemplateFunction {
const start = (typeof start0 === 'string') ? startPos(start0) : start0;
return (consts, ... vars) => {
const sourcePieces = [consts[0]];
@ -53,6 +53,7 @@ export class Templates {
(this.readOptions.extraDelimiters ?? '') + '$',
synthetic: true,
}),
context,
substPat,
sub => toItems(this.readOptions, vars[i++], sub.pos));
};

View File

@ -1,7 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Pos } from './position.js';
import { Pos } from './position';
export enum TokenType {
SPACE,

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
const inverse_alphabet =

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
const __SYNDICATE__ = Syndicate;
const currentSyndicateTarget = Syndicate.Dataspace.global;
@ -20,7 +20,7 @@ const currentSyndicateTarget = Syndicate.Dataspace.global;
const sourceCode = sourceUrl ? await (await fetch(sourceUrl)).text() : script.innerHTML;
const compilationResult = SyndicateCompiler.compile({
name: sourceUrl || 'anonymous-script-tag',
name: sourceUrl || script.id || 'anonymous-script-tag',
source: sourceCode,
module: isModule ? 'es6' : 'none',
runtime: isModule ? void 0 : 'Syndicate',

View File

@ -0,0 +1,213 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { compile, CompileOptions, Syntax } from '../src/index';
import Pos = Syntax.Pos;
import './test-utils';
import { js as format } from 'js-beautify';
type Error = { message: string, start: Pos | undefined, end: Pos | undefined };
function translate(source: string, options: Partial<CompileOptions> = {}): { code: string, errors: Error[] } {
const errors: Error[] = [];
const result = compile({
... options,
module: 'none',
source,
emitError: (message, start, end) => errors.push({ message, start, end }),
});
return { code: result.text, errors };
}
function translateNoErrors(source: string, options?: Partial<CompileOptions>): string {
const o = translate(source, options);
expect(o.errors.length).toBe(0);
return o.code;
}
function expectCodeEqual(input: string, output: string, options?: Partial<CompileOptions>) {
expect(format(translateNoErrors(input, options))).toBe(format(output));
}
describe('react', () => {
it('without label', () => expectCodeEqual(`react { a; b; c; }`, `
__SYNDICATE__.Turn.active.facet(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b; c;
});`));
it('with label', () => expectCodeEqual(`someLabel: react { a; b; c; }`, `
__SYNDICATE__.Turn.active.facet(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
const someLabel = currentSyndicateFacet;
a; b; c;
});`));
});
describe('spawn', () => {
it('without name', () => expectCodeEqual(`spawn { a; b; c; }`, `
__SYNDICATE__.Dataspace._spawn(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b; c;
});`));
it('with name', () => expectCodeEqual(`spawn named 'foo' { a; b; c; }`, `
__SYNDICATE__.Dataspace._spawn(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
currentSyndicateFacet.actor.name = 'foo';
a; b; c;
});`));
// At present, the expr() parser accepts *empty input*. TODO: something better.
it('with missing name (known incorrect parsing and codegen)', () =>
expectCodeEqual(`spawn named { a; b; c; }`, `
__SYNDICATE__.Dataspace._spawn(() => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
currentSyndicateFacet.actor.name = ;
a; b; c;
});`));
});
describe('stop', () => {
it('non-statement', () => expectCodeEqual(`(stop)`, `(stop)`));
it('toplevel end-delimited statement', () => expectCodeEqual(`stop`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('nested end-delimited statement', () => expectCodeEqual(`{ stop }`, `
{
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});
}`));
it('without facet, without body', () => expectCodeEqual(`stop;`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('without facet, empty body', () => expectCodeEqual(`stop {}`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('without facet, non-empty body', () => expectCodeEqual(`stop { a; b; }`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b;
});`));
it('with facet, without body', () => expectCodeEqual(`stop x.y;`, `
__SYNDICATE__.Turn.active._stop(x.y, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('with facet, empty body', () => expectCodeEqual(`stop x.y {}`, `
__SYNDICATE__.Turn.active._stop(x.y, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});`));
it('with facet, non-empty body', () => expectCodeEqual(`stop x.y { a; b; }`, `
__SYNDICATE__.Turn.active._stop(x.y, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
a; b;
});`));
it('nested stop, no labels', () => expectCodeEqual(`stop { stop; }`, `
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});
});`));
});
describe('during', () => {
it('stop in body', () => expectCodeEqual(`during P => { a; stop; b; }`, `
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.lit(__SYNDICATE__.fromJS(P)))),
observer: __SYNDICATE__.Turn.ref(__SYNDICATE__.assertionFacetObserver(
(__vs) => {
if (Array.isArray(__vs)) {
a;
__SYNDICATE__.Turn.active._stop(currentSyndicateFacet, () => {
const currentSyndicateFacet = __SYNDICATE__.Turn.activeFacet;
});
b;
}
}
))
})
}));`));
it('capture with type at top', () => expectCodeEqual(`during $v: T => { ok() }`, `
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.bind((__SYNDICATE__.QuasiValue._)))),
observer: __SYNDICATE__.Turn.ref(__SYNDICATE__.assertionFacetObserver(
(__vs: __SYNDICATE__.AnyValue) => {
if (Array.isArray(__vs)) {
const __v_0 = T.__from_preserve__(__vs[0]);
if (__v_0 === void 0) return;
const v = __v_0;
ok()
}
}
))
})
}));
`, { typescript: true }));
});
describe('once', () => {
it('basics with block', () => expectCodeEqual(`once asserted P => { a; b; }`, `
__SYNDICATE__.Turn.active.facet(() => {
const __once_facet = __SYNDICATE__.Turn.activeFacet;
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.lit(__SYNDICATE__.fromJS(P)))),
observer: __SYNDICATE__.Turn.ref({
assert: (__vs, __handle) => {
if (Array.isArray(__vs)) {
__SYNDICATE__.Turn.active._stop(__once_facet, () => { a; b; })
}
}
}),
}),
}));
});`));
it('basics with statement', () => expectCodeEqual(`once asserted P => x;`, `
__SYNDICATE__.Turn.active.facet(() => {
const __once_facet = __SYNDICATE__.Turn.activeFacet;
__SYNDICATE__.Turn.active.assertDataflow(() => ({
target: currentSyndicateTarget,
assertion: __SYNDICATE__.Observe({
pattern: __SYNDICATE__.QuasiValue.finish((__SYNDICATE__.QuasiValue.lit(__SYNDICATE__.fromJS(P)))),
observer: __SYNDICATE__.Turn.ref({
assert: (__vs, __handle) => {
if (Array.isArray(__vs)) {
__SYNDICATE__.Turn.active._stop(__once_facet, () => {x;})
}
}
}),
}),
}));
});`));
});

View File

@ -0,0 +1,30 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Grammar, Syntax } from '../src/index';
import './test-utils';
describe('statement boundary', () => {
function stmt(input: string): [string, string] | null {
const parser = new Grammar.SyndicateParser();
const tree = Syntax.laxRead(input);
const items: Syntax.Items = [];
const r = parser.statement(items)(new Syntax.ArrayList(tree, '{'));
if (r === null) return null;
return [Syntax.itemText(items), Syntax.itemText(r[1].toArray())];
}
it('should include semicolon', () => {
expect(stmt('i am a statement ; ')).toEqual(['i am a statement;', ' ']);
});
it('should include newline', () => {
expect(stmt('i am a statement \n ')).toEqual(['i am a statement\n', ' ']);
});
it('should include closing brace on the same line', () => {
// Note that `" remainder is in outer group"` is discarded by `laxRead`.
expect(stmt('i am a statement } remainder is in outer group'))
.toEqual(['i am a statement', '']);
});
});

View File

@ -0,0 +1,38 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { is, preserves } from '@preserves/core';
declare global {
namespace jest {
interface Matchers<R> {
is(expected: any): R;
toThrowFilter(f: (e: Error) => boolean): R;
}
}
}
expect.extend({
is(actual, expected) {
return is(actual, expected)
? { message: () => preserves`expected ${actual} not to be Preserves.is to ${expected}`,
pass: true }
: { message: () => preserves`expected ${actual} to be Preserves.is to ${expected}`,
pass: false };
},
toThrowFilter(thunk, f) {
try {
thunk();
return { message: () => preserves`expected an exception`, pass: false };
} catch (e) {
if (f(e)) {
return { message: () => preserves`expected an exception not matching the filter`,
pass: true };
} else {
return { message: () => preserves`expected an exception matching the filter: ${(e as any)?.constructor?.name}`,
pass: false };
}
}
}
});

View File

@ -1,6 +1,6 @@
#!/usr/bin/env node
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import {
Pattern as P,

View File

@ -1,6 +1,6 @@
#!/usr/bin/env -S npx ts-node -O '{"module": "commonjs"}'
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import {
Pattern as P,

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export default {
preset: 'ts-jest',

View File

@ -5,10 +5,10 @@ ActionDescription =
/ @spawnActor <spawn-actor @detail OptionalAny @initialAssertions #{protocol.Handle}>
/ @stopActor <stop-actor @error OptionalAny>
/ @inertCheck <inert-check>
/ <assert @target #!any @crossSpace bool @handle protocol.Handle @assertion any>
/ <retract @target #!any @crossSpace bool @handle protocol.Handle>
/ <message @target #!any @assertion any>
/ <sync @target #!any @callback #!any>
/ <assert @target #:any @crossSpace bool @handle protocol.Handle @assertion any>
/ <retract @target #:any @crossSpace bool @handle protocol.Handle>
/ <message @target #:any @assertion any>
/ <sync @target #:any @callback #:any>
.
OptionalAny = <none> / <some @value any> .

View File

@ -1,6 +1,6 @@
{
"name": "@syndicate-lang/core",
"version": "0.23.0",
"version": "0.32.0",
"description": "Syndicate/JS for browser and node.js",
"homepage": "https://github.com/syndicate-lang/syndicate-js/tree/main/packages/core",
"license": "GPL-3.0+",
@ -21,7 +21,7 @@
"rollup:watch": "../../node_modules/.bin/rollup -c -w",
"test": "../../node_modules/.bin/jest",
"cover": "../../node_modules/.bin/nyc --reporter=html ../../node_modules/.bin/jest",
"clean": "rm -rf lib dist",
"clean": "rm -rf lib dist ./src/gen",
"veryclean": "yarn run clean && rm -rf node_modules"
},
"main": "dist/syndicate.js",
@ -29,11 +29,11 @@
"types": "lib/index.d.ts",
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"devDependencies": {
"@preserves/core": "0.992.4",
"@preserves/schema-cli": "0.992.5"
"@preserves/core": "0.995.200",
"@preserves/schema-cli": "0.995.201"
},
"peerDependencies": {
"@preserves/core": "0.992.4"
"@preserves/core": "0.995.200"
},
"dependencies": {
"salty-crypto": "0.3.1"

View File

@ -2,15 +2,15 @@
tcp-remote„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³ TcpPeerInfo´³rec´³lit³tcp-peer„´³tupleµ´³named³handle´³embedded³any„„´³named³local´³refµ„³TcpLocal„„´³named³remote´³refµ„³ TcpRemote„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³http„´³schema·³version°³ definitions·³Chunk´³orµµ±string´³atom³String„„µ±bytes´³atom³
ByteString„„„„³Headers´³dictof´³atom³Symbol„´³atom³String„„³MimeType´³atom³Symbol„³
QueryValue´³orµµ±string´³atom³String„„µ±file´³rec´³lit³file„´³tupleµ´³named³filename´³atom³String„„´³named³headers´³refµ„³Headers„„´³named³body´³atom³
ByteString„„„„„„„„³ HostPattern´³orµµ±host´³atom³String„„µ±any´³lit€„„„„³ HttpBinding´³rec´³lit³ http-bind„´³tupleµ´³named³host´³refµ„³ HostPattern„„´³named³port´³atom³ SignedInteger„„´³named³method´³refµ„³ MethodPattern„„´³named³path´³refµ„³ PathPattern„„´³named³handler´³embedded´³refµ„³ HttpRequest„„„„„„³ HttpContext´³rec´³lit³request„´³tupleµ´³named³req´³refµ„³ HttpRequest„„´³named³res´³embedded´³refµ„³ HttpResponse„„„„„„³ HttpRequest´³rec´³lit³ http-request„´³tupleµ´³named³sequenceNumber´³atom³ SignedInteger„„´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„´³named³method´³atom³Symbol„„´³named³path´³seqof´³atom³String„„„´³named³headers´³refµ„³Headers„„´³named³query´³dictof´³atom³Symbol„´³seqof´³refµ„³
ByteString„„„„„„„„³ HostPattern´³orµµ±host´³atom³String„„µ±any´³lit€„„„„³ HttpBinding´³rec´³lit³ http-bind„´³tupleµ´³named³host´³refµ„³ HostPattern„„´³named³port´³atom³ SignedInteger„„´³named³method´³refµ„³ MethodPattern„„´³named³path´³refµ„³ PathPattern„„´³named³handler´³embedded´³refµ„³ HttpRequest„„„„„„³ HttpContext´³rec´³lit³request„´³tupleµ´³named³req´³refµ„³ HttpRequest„„´³named³res´³embedded´³refµ„³ HttpResponse„„„„„„³ HttpRequest´³rec´³lit³ http-request„´³tupleµ´³named³sequenceNumber´³atom³ SignedInteger„„´³named³host´³refµ„³ RequestHost„„´³named³port´³atom³ SignedInteger„„´³named³method´³atom³Symbol„„´³named³path´³seqof´³atom³String„„„´³named³headers´³refµ„³Headers„„´³named³query´³dictof´³atom³Symbol„´³seqof´³refµ„³
QueryValue„„„„´³named³body´³refµ„³ RequestBody„„„„„³ HttpService´³rec´³lit³ http-service„´³tupleµ´³named³host´³refµ„³ HostPattern„„´³named³port´³atom³ SignedInteger„„´³named³method´³refµ„³ MethodPattern„„´³named³path´³refµ„³ PathPattern„„„„„³ PathPattern´³seqof´³refµ„³PathPatternElement„„³ RequestBody´³orµµ±present´³atom³
ByteString„„µ±absent´³lit€„„„„³ HttpListener´³rec´³lit³ http-listener„´³tupleµ´³named³port´³atom³ SignedInteger„„„„„³ HttpResponse´³orµµ±status´³rec´³lit³status„´³tupleµ´³named³code´³atom³ SignedInteger„„´³named³message´³atom³String„„„„„„µ±header´³rec´³lit³header„´³tupleµ´³named³name´³atom³Symbol„„´³named³value´³atom³String„„„„„„µ±chunk´³rec´³lit³chunk„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„µ±done´³rec´³lit³done„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„„„³ MethodPattern´³orµµ±any´³lit€„„µ±specific´³atom³Symbol„„„„³PathPatternElement´³orµµ±label´³atom³String„„µ±wildcard´³lit³_„„µ±rest´³lit³...„„„„„³ embeddedType€„„µ³noise„´³schema·³version°³ definitions·³Packet´³orµµ±complete´³atom³
ByteString„„µ±absent´³lit€„„„„³ RequestHost´³orµµ±present´³atom³String„„µ±absent´³lit€„„„„³ HttpListener´³rec´³lit³ http-listener„´³tupleµ´³named³port´³atom³ SignedInteger„„„„„³ HttpResponse´³orµµ±status´³rec´³lit³status„´³tupleµ´³named³code´³atom³ SignedInteger„„´³named³message´³atom³String„„„„„„µ±header´³rec´³lit³header„´³tupleµ´³named³name´³atom³Symbol„„´³named³value´³atom³String„„„„„„µ±chunk´³rec´³lit³chunk„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„µ±done´³rec´³lit³done„´³tupleµ´³named³chunk´³refµ„³Chunk„„„„„„„„³ MethodPattern´³orµµ±any´³lit€„„µ±specific´³atom³Symbol„„„„³PathPatternElement´³orµµ±label´³atom³String„„µ±wildcard´³lit³_„„µ±rest´³lit³...„„„„„³ embeddedType€„„µ³noise„´³schema·³version°³ definitions·³Packet´³orµµ±complete´³atom³
ByteString„„µ±
fragmented´³seqof´³atom³
ByteString„„„„„³ NoiseSpec´³andµ´³dict·³key´³named³key´³atom³
ByteString„„³service´³named³service´³refµ„³ServiceSelector„„„„´³named³protocol´³refµ„³ NoiseProtocol„„´³named³ preSharedKeys´³refµ„³NoisePreSharedKeys„„„„³ NoiseProtocol´³orµµ±present´³dict·³protocol´³named³protocol´³atom³String„„„„„µ±invalid´³dict·³protocol´³named³protocol³any„„„„µ±absent´³dict·„„„„„³ NoiseStepType´³lit³noise„³SecretKeyField´³orµµ±present´³dict·³ secretKey´³named³ secretKey´³atom³
ByteString„„„„„³ Initiator´³rec´³lit³ initiator„´³tupleµ´³named³initiatorSession´³embedded´³refµ„³Packet„„„„„„³ NoiseSpec´³andµ´³dict·³key´³named³key´³atom³
ByteString„„³service´³named³service´³refµ„³ServiceSelector„„„„´³named³protocol´³refµ„³ NoiseProtocol„„´³named³ preSharedKeys´³refµ„³NoisePreSharedKeys„„„„³ SessionItem´³orµµ± Initiator´³refµ„³ Initiator„„µ±Packet´³refµ„³Packet„„„„³ NoiseProtocol´³orµµ±present´³dict·³protocol´³named³protocol´³atom³String„„„„„µ±invalid´³dict·³protocol´³named³protocol³any„„„„µ±absent´³dict·„„„„„³ NoiseStepType´³lit³noise„³SecretKeyField´³orµµ±present´³dict·³ secretKey´³named³ secretKey´³atom³
ByteString„„„„„µ±invalid´³dict·³ secretKey´³named³ secretKey³any„„„„µ±absent´³dict·„„„„„³DefaultProtocol´³lit±!Noise_NK_25519_ChaChaPoly_BLAKE2s„³NoiseStepDetail´³refµ„³ServiceSelector„³ServiceSelector³any³NoiseServiceSpec´³andµ´³named³base´³refµ„³ NoiseSpec„„´³named³ secretKey´³refµ„³SecretKeyField„„„„³NoisePreSharedKeys´³orµµ±present´³dict·³ preSharedKeys´³named³ preSharedKeys´³seqof´³atom³
ByteString„„„„„„µ±invalid´³dict·³ preSharedKeys´³named³ preSharedKeys³any„„„„µ±absent´³dict·„„„„„³NoisePathStepDetail´³refµ„³ NoiseSpec„³NoiseDescriptionDetail´³refµ„³NoiseServiceSpec„„³ embeddedType„„µ³timer„´³schema·³version°³ definitions·³SetTimer´³rec´³lit³ set-timer„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„´³named³kind´³refµ„³ TimerKind„„„„„³ LaterThan´³rec´³lit³
ByteString„„„„„„µ±invalid´³dict·³ preSharedKeys´³named³ preSharedKeys³any„„„„µ±absent´³dict·„„„„„³NoisePathStepDetail´³refµ„³ NoiseSpec„³NoiseDescriptionDetail´³refµ„³NoiseServiceSpec„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³timer„´³schema·³version°³ definitions·³SetTimer´³rec´³lit³ set-timer„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„´³named³kind´³refµ„³ TimerKind„„„„„³ LaterThan´³rec´³lit³
later-than„´³tupleµ´³named³seconds´³atom³Double„„„„„³ TimerKind´³orµµ±relative´³lit³relative„„µ±absolute´³lit³absolute„„µ±clear´³lit³clear„„„„³ TimerExpired´³rec´³lit³ timer-expired„´³tupleµ´³named³label³any„´³named³seconds´³atom³Double„„„„„„³ embeddedType€„„µ³trace„´³schema·³version°³ definitions·³Oid³any³Name´³orµµ± anonymous´³rec´³lit³ anonymous„´³tupleµ„„„„µ±named´³rec´³lit³named„´³tupleµ´³named³name³any„„„„„„„³Target´³rec´³lit³entity„´³tupleµ´³named³actor´³refµ„³ActorId„„´³named³facet´³refµ„³FacetId„„´³named³oid´³refµ„³Oid„„„„„³TaskId³any³TurnId³any³ActorId³any³FacetId³any³ TurnCause´³orµµ±turn´³rec´³lit³ caused-by„´³tupleµ´³named³id´³refµ„³TurnId„„„„„„µ±cleanup´³rec´³lit³cleanup„´³tupleµ„„„„µ±linkedTaskRelease´³rec´³lit³linked-task-release„´³tupleµ´³named³id´³refµ„³TaskId„„´³named³reason´³refµ„³LinkedTaskReleaseReason„„„„„„µ±periodicActivation´³rec´³lit³periodic-activation„´³tupleµ´³named³period´³atom³Double„„„„„„µ±delay´³rec´³lit³delay„´³tupleµ´³named³ causingTurn´³refµ„³TurnId„„´³named³amount´³atom³Double„„„„„„µ±external´³rec´³lit³external„´³tupleµ´³named³ description³any„„„„„„„³ TurnEvent´³orµµ±assert´³rec´³lit³assert„´³tupleµ´³named³ assertion´³refµ„³AssertionDescription„„´³named³handle´³refµ³protocol„³Handle„„„„„„µ±retract´³rec´³lit³retract„´³tupleµ´³named³handle´³refµ³protocol„³Handle„„„„„„µ±message´³rec´³lit³message„´³tupleµ´³named³body´³refµ„³AssertionDescription„„„„„„µ±sync´³rec´³lit³sync„´³tupleµ´³named³peer´³refµ„³Target„„„„„„µ± breakLink´³rec´³lit³
break-link„´³tupleµ´³named³source´³refµ„³ActorId„„´³named³handle´³refµ³protocol„³Handle„„„„„„„„³
ExitStatus´³orµµ±ok´³lit³ok„„µ±Error´³refµ³protocol„³Error„„„„³
@ -24,7 +24,7 @@ ByteString
ByteString„„´³named³oid³any„„´³named³caveats´³seqof´³refµ³sturdy„³Caveat„„„„„µ±general´³refµ³
gatekeeper„³Route„„„„³StandardTransport´³orµµ±wsUrl´³atom³String„„µ±other³any„„„„³ embeddedType€„„µ³stream„´³schema·³version°³ definitions·³Mode´³orµµ±bytes´³lit³bytes„„µ±lines´³refµ„³LineMode„„µ±packet´³rec´³lit³packet„´³tupleµ´³named³size´³atom³ SignedInteger„„„„„„µ±object´³rec´³lit³object„´³tupleµ´³named³ description³any„„„„„„„³Sink´³orµµ±source´³rec´³lit³source„´³tupleµ´³named³
controller´³embedded´³refµ„³Source„„„„„„„µ± StreamError´³refµ„³ StreamError„„µ±data´³rec´³lit³data„´³tupleµ´³named³payload³any„´³named³mode´³refµ„³Mode„„„„„„µ±eof´³rec´³lit³eof„´³tupleµ„„„„„„³Source´³orµµ±sink´³rec´³lit³sink„´³tupleµ´³named³
controller´³embedded´³refµ„³Sink„„„„„„„µ± StreamError´³refµ„³ StreamError„„µ±credit´³rec´³lit³credit„´³tupleµ´³named³amount´³refµ„³ CreditAmount„„´³named³mode´³refµ„³Mode„„„„„„„„³LineMode´³orµµ±lf´³lit³lf„„µ±crlf´³lit³crlf„„„„³ StreamError´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„„„„³ CreditAmount´³orµµ±count´³atom³ SignedInteger„„µ± unbounded´³lit³ unbounded„„„„³StreamConnection´³rec´³lit³stream-connection„´³tupleµ´³named³source´³embedded´³refµ„³Source„„„´³named³sink´³embedded´³refµ„³Sink„„„´³named³spec³any„„„„³StreamListenerError´³rec´³lit³stream-listener-error„´³tupleµ´³named³spec³any„´³named³message´³atom³String„„„„„³StreamListenerReady´³rec´³lit³stream-listener-ready„´³tupleµ´³named³spec³any„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³sturdy„´³schema·³version°³ definitions·³Lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„³Oid´³atom³ SignedInteger„³Alts´³rec´³lit³or„´³tupleµ´³named³ alternatives´³seqof´³refµ„³Rewrite„„„„„„³PAnd´³rec´³lit³and„´³tupleµ´³named³patterns´³seqof´³refµ„³Pattern„„„„„„³PNot´³rec´³lit³not„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³TRef´³rec´³lit³ref„´³tupleµ´³named³binding´³atom³ SignedInteger„„„„„³PAtom´³orµµ±Boolean´³lit³Boolean„„µ±Float´³lit³Float„„µ±Double´³lit³Double„„µ± SignedInteger´³lit³ SignedInteger„„µ±String´³lit³String„„µ±
controller´³embedded´³refµ„³Sink„„„„„„„µ± StreamError´³refµ„³ StreamError„„µ±credit´³rec´³lit³credit„´³tupleµ´³named³amount´³refµ„³ CreditAmount„„´³named³mode´³refµ„³Mode„„„„„„„„³LineMode´³orµµ±lf´³lit³lf„„µ±crlf´³lit³crlf„„„„³ StreamError´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„„„„³ CreditAmount´³orµµ±count´³atom³ SignedInteger„„µ± unbounded´³lit³ unbounded„„„„³StreamConnection´³rec´³lit³stream-connection„´³tupleµ´³named³source´³embedded´³refµ„³Source„„„´³named³sink´³embedded´³refµ„³Sink„„„´³named³spec³any„„„„³StreamListenerError´³rec´³lit³stream-listener-error„´³tupleµ´³named³spec³any„´³named³message´³atom³String„„„„„³StreamListenerReady´³rec´³lit³stream-listener-ready„´³tupleµ´³named³spec³any„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³sturdy„´³schema·³version°³ definitions·³Lit´³rec´³lit³lit„´³tupleµ´³named³value³any„„„„³Oid´³atom³ SignedInteger„³Alts´³rec´³lit³or„´³tupleµ´³named³ alternatives´³seqof´³refµ„³Rewrite„„„„„„³PAnd´³rec´³lit³and„´³tupleµ´³named³patterns´³seqof´³refµ„³Pattern„„„„„„³PNot´³rec´³lit³not„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³TRef´³rec´³lit³ref„´³tupleµ´³named³binding´³atom³ SignedInteger„„„„„³PAtom´³orµµ±Boolean´³lit³Boolean„„µ±Double´³lit³Double„„µ± SignedInteger´³lit³ SignedInteger„„µ±String´³lit³String„„µ±
ByteString´³lit³
ByteString„„µ±Symbol´³lit³Symbol„„„„³PBind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³Caveat´³orµµ±Rewrite´³refµ„³Rewrite„„µ±Alts´³refµ„³Alts„„µ±Reject´³refµ„³Reject„„µ±unknown³any„„„³Reject´³rec´³lit³reject„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³Pattern´³orµµ±PDiscard´³refµ„³PDiscard„„µ±PAtom´³refµ„³PAtom„„µ± PEmbedded´³refµ„³ PEmbedded„„µ±PBind´³refµ„³PBind„„µ±PAnd´³refµ„³PAnd„„µ±PNot´³refµ„³PNot„„µ±Lit´³refµ„³Lit„„µ± PCompound´³refµ„³ PCompound„„„„³Rewrite´³rec´³lit³rewrite„´³tupleµ´³named³pattern´³refµ„³Pattern„„´³named³template´³refµ„³Template„„„„„³WireRef´³orµµ±mine´³tupleµ´³lit°„´³named³oid´³refµ„³Oid„„„„„µ±yours´³ tuplePrefixµ´³lit°„´³named³oid´³refµ„³Oid„„„´³named³ attenuation´³seqof´³refµ„³Caveat„„„„„„„³PDiscard´³rec´³lit³_„´³tupleµ„„„³Template´³orµµ±
TAttenuate´³refµ„³
@ -40,5 +40,5 @@ ByteString
RunService´³rec´³lit³ run-service„´³tupleµ´³named³ serviceName³any„„„„³ ServiceState´³rec´³lit³ service-state„´³tupleµ´³named³ serviceName³any„´³named³state´³refµ„³State„„„„„³ ServiceObject´³rec´³lit³service-object„´³tupleµ´³named³ serviceName³any„´³named³object³any„„„„³RequireService´³rec´³lit³require-service„´³tupleµ´³named³ serviceName³any„„„„³RestartService´³rec´³lit³restart-service„´³tupleµ´³named³ serviceName³any„„„„³ServiceDependency´³rec´³lit³
depends-on„´³tupleµ´³named³depender³any„´³named³dependee´³refµ„³ ServiceState„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³protocol„´³schema·³version°³ definitions·³Oid´³atom³ SignedInteger„³Sync´³rec´³lit³S„´³tupleµ´³named³peer´³embedded´³lit<69>„„„„„„³Turn´³seqof´³refµ„³ TurnEvent„„³Error´³rec´³lit³error„´³tupleµ´³named³message´³atom³String„„´³named³detail³any„„„„³Event´³orµµ±Assert´³refµ„³Assert„„µ±Retract´³refµ„³Retract„„µ±Message´³refµ„³Message„„µ±Sync´³refµ„³Sync„„„„³Assert´³rec´³lit³A„´³tupleµ´³named³ assertion´³refµ„³ Assertion„„´³named³handle´³refµ„³Handle„„„„„³Handle´³atom³ SignedInteger„³Packet´³orµµ±Turn´³refµ„³Turn„„µ±Error´³refµ„³Error„„µ± Extension´³refµ„³ Extension„„„„³Message´³rec´³lit³M„´³tupleµ´³named³body´³refµ„³ Assertion„„„„„³Retract´³rec´³lit³R„´³tupleµ´³named³handle´³refµ„³Handle„„„„„³ Assertion³any³ Extension´³rec´³named³label³any„´³named³fields´³seqof³any„„„³ TurnEvent´³tupleµ´³named³oid´³refµ„³Oid„„´³named³event´³refµ„³Event„„„„„³ embeddedType€„„µ³ dataspace„´³schema·³version°³ definitions·³Observe´³rec´³lit³Observe„´³tupleµ´³named³pattern´³refµ³dataspacePatterns„³Pattern„„´³named³observer´³embedded³any„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³
gatekeeper„´³schema·³version°³ definitions·³Bind´³rec´³lit³bind„´³tupleµ´³named³ description´³refµ„³ Description„„´³named³target´³embedded³any„„´³named³observer´³refµ„³ BindObserver„„„„„³Step´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Bound´³orµµ±bound´³rec´³lit³bound„´³tupleµ´³named³pathStep´³refµ„³PathStep„„„„„„µ±Rejected´³refµ„³Rejected„„„„³Route´³rec´³lit³route„´³ tuplePrefixµ´³named³
transports´³seqof³any„„„´³named³ pathSteps´³seqof´³refµ„³PathStep„„„„„³Resolve´³rec´³lit³resolve„´³tupleµ´³named³step´³refµ„³Step„„´³named³observer´³embedded´³refµ„³Resolved„„„„„„³PathStep´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Rejected´³rec´³lit³rejected„´³tupleµ´³named³detail³any„„„„³Resolved´³orµµ±accepted´³rec´³lit³accepted„´³tupleµ´³named³responderSession´³embedded³any„„„„„„µ±Rejected´³refµ„³Rejected„„„„³ Description´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³ ResolvePath´³rec´³lit³ resolve-path„´³tupleµ´³named³route´³refµ„³Route„„´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„³ BindObserver´³orµµ±present´³embedded´³refµ„³Bound„„„µ±absent´³lit€„„„„³ForceDisconnect´³rec´³lit³force-disconnect„´³tupleµ„„„³ResolvedPathStep´³rec´³lit³ path-step„´³tupleµ´³named³origin´³embedded´³refµ„³Resolve„„„´³named³pathStep´³refµ„³PathStep„„´³named³resolved´³refµ„³Resolved„„„„„³TransportControl´³refµ„³ForceDisconnect„³TransportConnection´³rec´³lit³connect-transport„´³tupleµ´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³transportAddress„´³schema·³version°³ definitions·³Tcp´³rec´³lit³tcp„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³Unix´³rec´³lit³unix„´³tupleµ´³named³path´³atom³String„„„„„³Stdio´³rec´³lit³stdio„´³tupleµ„„„³ WebSocket´³rec´³lit³ws„´³tupleµ´³named³url´³atom³String„„„„„„³ embeddedType€„„µ³dataspacePatterns„´³schema·³version°³ definitions·³DLit´³rec´³lit³lit„´³tupleµ´³named³value´³refµ„³AnyAtom„„„„„³DBind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„³AnyAtom´³orµµ±bool´³atom³Boolean„„µ±float´³atom³Float„„µ±double´³atom³Double„„µ±int´³atom³ SignedInteger„„µ±string´³atom³String„„µ±bytes´³atom³
ByteString„„µ±symbol´³atom³Symbol„„µ±embedded´³embedded³any„„„„³Pattern´³orµµ±DDiscard´³refµ„³DDiscard„„µ±DBind´³refµ„³DBind„„µ±DLit´³refµ„³DLit„„µ± DCompound´³refµ„³ DCompound„„„„³DDiscard´³rec´³lit³_„´³tupleµ„„„³ DCompound´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„´³named³fields´³seqof´³refµ„³Pattern„„„„„„„µ±arr´³rec´³lit³arr„´³tupleµ´³named³items´³seqof´³refµ„³Pattern„„„„„„„µ±dict´³rec´³lit³dict„´³tupleµ´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„„„
transports´³seqof³any„„„´³named³ pathSteps´³seqof´³refµ„³PathStep„„„„„³Resolve´³rec´³lit³resolve„´³tupleµ´³named³step´³refµ„³Step„„´³named³observer´³embedded´³refµ„³Resolved„„„„„„³PathStep´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³Rejected´³rec´³lit³rejected„´³tupleµ´³named³detail³any„„„„³Resolved´³orµµ±accepted´³rec´³lit³accepted„´³tupleµ´³named³responderSession´³embedded³any„„„„„„µ±Rejected´³refµ„³Rejected„„„„³ Description´³rec´³named³stepType´³atom³Symbol„„´³tupleµ´³named³detail³any„„„„³ ResolvePath´³rec´³lit³ resolve-path„´³tupleµ´³named³route´³refµ„³Route„„´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„³ BindObserver´³orµµ±present´³embedded´³refµ„³Bound„„„µ±absent´³lit€„„„„³ForceDisconnect´³rec´³lit³force-disconnect„´³tupleµ„„„³ResolvedPathStep´³rec´³lit³ path-step„´³tupleµ´³named³origin´³embedded´³refµ„³Resolve„„„´³named³pathStep´³refµ„³PathStep„„´³named³resolved´³refµ„³Resolved„„„„„³TransportControl´³refµ„³ForceDisconnect„³TransportConnection´³rec´³lit³connect-transport„´³tupleµ´³named³addr³any„´³named³control´³embedded´³refµ„³TransportControl„„„´³named³resolved´³refµ„³Resolved„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„µ³transportAddress„´³schema·³version°³ definitions·³Tcp´³rec´³lit³tcp„´³tupleµ´³named³host´³atom³String„„´³named³port´³atom³ SignedInteger„„„„„³Unix´³rec´³lit³unix„´³tupleµ´³named³path´³atom³String„„„„„³Stdio´³rec´³lit³stdio„´³tupleµ„„„³ WebSocket´³rec´³lit³ws„´³tupleµ´³named³url´³atom³String„„„„„„³ embeddedType€„„µ³dataspacePatterns„´³schema·³version°³ definitions·³AnyAtom´³orµµ±bool´³atom³Boolean„„µ±double´³atom³Double„„µ±int´³atom³ SignedInteger„„µ±string´³atom³String„„µ±bytes´³atom³
ByteString„„µ±symbol´³atom³Symbol„„µ±embedded´³embedded³any„„„„³Pattern´³orµµ±discard´³rec´³lit³_„´³tupleµ„„„„µ±bind´³rec´³lit³bind„´³tupleµ´³named³pattern´³refµ„³Pattern„„„„„„µ±lit´³rec´³lit³lit„´³tupleµ´³named³value´³refµ„³AnyAtom„„„„„„µ±group´³rec´³lit³group„´³tupleµ´³named³type´³refµ„³ GroupType„„´³named³entries´³dictof³any´³refµ„³Pattern„„„„„„„„„³ GroupType´³orµµ±rec´³rec´³lit³rec„´³tupleµ´³named³label³any„„„„„µ±arr´³rec´³lit³arr„´³tupleµ„„„„µ±dict´³rec´³lit³dict„´³tupleµ„„„„„„„³ embeddedType´³refµ³ EntityRef„³Cap„„„„„

View File

@ -1,4 +1,4 @@
version 1 .
embeddedType EntityRef.Cap .
Observe = <Observe @pattern dataspacePatterns.Pattern @observer #!any>.
Observe = <Observe @pattern dataspacePatterns.Pattern @observer #:any>.

View File

@ -1,23 +1,30 @@
version 1 .
embeddedType EntityRef.Cap .
# Dataspace patterns: a sublanguage of attenuation patterns.
Pattern = DDiscard / DBind / DLit / DCompound .
# Dataspace patterns: *almost* a sublanguage of attenuation patterns.
#
# One key difference is that Dataspace patterns are extensible, in that
# they ignore fields not mentioned in group patterns.
DDiscard = <_>.
DBind = <bind @pattern Pattern>.
DLit = <lit @value AnyAtom>.
DCompound = <rec @label any @fields [Pattern ...]>
/ <arr @items [Pattern ...]>
/ <dict @entries { any: Pattern ...:... }> .
Pattern =
/ @discard <_>
/ <bind @pattern Pattern>
/ <lit @value AnyAtom>
/ <group @type GroupType @entries { any: Pattern ...:... }>
.
GroupType =
/ <rec @label any>
/ <arr>
/ <dict>
.
AnyAtom =
/ @bool bool
/ @float float
/ @double double
/ @int int
/ @string string
/ @bytes bytes
/ @symbol symbol
/ @embedded #!any
/ @embedded #:any
.

View File

@ -6,18 +6,47 @@ embeddedType EntityRef.Cap .
# Assertion. Gatekeeper will attempt to resolve `step`, responding with a `Resolved` to
# `observer`.
Resolve = <resolve @step Step @observer #!Resolved> .
Resolved = <accepted @responderSession #!any> / Rejected .
Resolve = <resolve @step Step @observer #:Resolved> .
Resolved = <accepted @responderSession #:any> / Rejected .
Step = <<rec> @stepType symbol [@detail any]> .
# ---------------------------------------------------------------------------
# Protocol at dataspaces *associated* with gatekeeper entities
# Assertion. Gatekeeper will compute an appropriate PathStep from `description` pointing at
# `target`, and will respond with a `Bound` to `observer` (if supplied).
Bind = <bind @description Description @target #!any @observer BindObserver> .
# ## Handling `Resolve` requests
#
# When the gatekeeper entity receives a `Resolve` assertion (call it R1), it
#
# 1. asserts a `Resolve` (call it R2) into its associated dataspace that
# is the same as R1 except it has a different `observer`; and
#
# 2. observes a `Bind` with `description` matching the `step` of R1/R2
# according to `stepType` (e.g. treatment of SturdyStepType is not the
# same as treatment of NoiseStepType).
#
# Normally, an appropriate `Bind` is expected to exist. If the gatekeeper
# sees the `Bind` first, it takes the `target` from it and does whatever
# `stepType` mandates before replying to R1's observer.
#
# However, if a `Resolved` is asserted to R2's observer before a `Bind`
# appears, that resolution is relayed on to R1's observer directly, be it
# positive or negative, and the gatekeeper stops waiting for a `Bind`.
#
# This way, entities can keep an eye out for `Resolve` requests that will
# never complete, and answer `Rejected` to them even when no matching
# `Bind` exists. Entities could also use `Resolve` requests to synthesize a
# `Bind` in a "just-in-time" fashion.
#
# ## General treatment of `Bind` assertions
#
# When the gatekeeper sees a `Bind`, independently of any potential
# `Resolve` requests, it computes an appropriate PathStep from
# `description` pointing at `target`, and responds with a `Bound` to
# `observer` (if supplied).
#
Bind = <bind @description Description @target #:any @observer BindObserver> .
Description = <<rec> @stepType symbol [@detail any]> .
BindObserver = @present #!Bound / @absent #f .
BindObserver = @present #:Bound / @absent #f .
Bound = <bound @pathStep PathStep> / Rejected .
# ---------------------------------------------------------------------------
@ -27,10 +56,10 @@ Bound = <bound @pathStep PathStep> / Rejected .
# and `resolved`, respondent will follow `route.pathSteps` starting from one of the
# `route.transports`, asserting `ResolvePath` with the final `Resolved` as well as the selected
# transport `addr` and a `control` for it.
ResolvePath = <resolve-path @route Route @addr any @control #!TransportControl @resolved Resolved> .
ResolvePath = <resolve-path @route Route @addr any @control #:TransportControl @resolved Resolved> .
TransportConnection = <connect-transport @addr any @control #!TransportControl @resolved Resolved> .
ResolvedPathStep = <path-step @origin #!Resolve @pathStep PathStep @resolved Resolved> .
TransportConnection = <connect-transport @addr any @control #:TransportControl @resolved Resolved> .
ResolvedPathStep = <path-step @origin #:Resolve @pathStep PathStep @resolved Resolved> .
PathStep = <<rec> @stepType symbol [@detail any]> .
# A `Route` describes a network path that can be followed to reach some target entity.

View File

@ -2,7 +2,7 @@ version 1 .
# Assertion in driver DS
# Causes creation of server and route
HttpBinding = <http-bind @host HostPattern @port int @method MethodPattern @path PathPattern @handler #!HttpRequest> .
HttpBinding = <http-bind @host HostPattern @port int @method MethodPattern @path PathPattern @handler #:HttpRequest> .
# Assertion in driver DS
# Describes active server and route
@ -21,7 +21,7 @@ MethodPattern = @any #f / @specific @"Lowercase" symbol .
# Assertion in driver DS
HttpRequest = <http-request
@sequenceNumber int
@host string
@host RequestHost
@port int
@method @"Lowercase" symbol
@path [string ...]
@ -32,13 +32,24 @@ HttpRequest = <http-request
Headers = {@"Lowercase" symbol: string ...:...} .
QueryValue = @string string / <file @filename string @headers Headers @body bytes> .
RequestBody = @present bytes / @absent #f .
RequestHost = @present string / @absent #f .
# Assertion to handler entity
HttpContext = <request @req HttpRequest @res #!HttpResponse> .
HttpContext = <request @req HttpRequest @res #:HttpResponse> .
# HttpResponse protocol. Delivered to the `res` ref in `HttpContext`.
#
# (status | header)* . chunk* . done
#
# Done triggers completion of the response and retraction of the frame by the peer. If the
# HttpBinding responsible for the request is withdrawn mid-way through a response (i.e. when
# chunked transfer is used and at least one chunk has been sent) the request is abruptly
# closed; if it is withdrawn at any other moment in the lifetime of the request, a 500 Internal
# Server Error is send to the client.
#
@<TODO "trailers?">
# Messages
HttpResponse =
# Messages.
/ <status @code int @message string>
/ <header @name symbol @value string>
/ <chunk @chunk Chunk>

View File

@ -1,4 +1,5 @@
version 1 .
embeddedType EntityRef.Cap .
# https://noiseprotocol.org/
@ -42,13 +43,30 @@ DefaultProtocol = "Noise_NK_25519_ChaChaPoly_BLAKE2s" .
# sequence is exhausted or not supplied, an all-zeros key is used each time a PSK is needed.
NoisePreSharedKeys = @present { preSharedKeys: [bytes ...] } / @invalid { preSharedKeys: any } / @absent {} .
# Sessions proceed by sending Packets to the initiatorSession and responderSession according to
# the Noise protocol definition. Each Packet represents a complete logical unit of
# ---------------------------------------------------------------------------
# Handshaking and running a session
# 1. initiator asserts <resolve <noise ServiceSelector> #:A> at Gatekeeper
# 2. gatekeeper asserts <accepted #:B> at #:A
# 3. initiator asserts <initiator #:C> at #:B and then sends `Packet`s to #:B
# 4. responder sends `Packet`s to #:C
#
# Sessions begin with introduction of initiator (#:C) and responder (#:B) to each other, and
# then proceed by sending `Packet`s (from #:C) to #:B and (from #:B) to #:C according to
# the Noise protocol definition. Each `Packet` represents a complete logical unit of
# communication; for example, a complete Turn when layering the Syndicate protocol over Noise.
# Note well the restriction on Noise messages: no individual complete packet or packet fragment
# may exceed 65535 bytes (N.B. not 65536!). When `fragmented`, each portion of a Packet is a
# may exceed 65535 bytes (N.B. not 65536!). When `fragmented`, each portion of a `Packet` is a
# complete Noise "transport message"; when `complete`, the whole thing is likewise a complete
# "transport message".
#
# Retraction of the `Initiator` ends the session from the initiator-side; retraction of the
# `<accepted ...>` assertion ends the session from the responder-side.
SessionItem = Initiator / Packet .
# Assertion
Initiator = <initiator @initiatorSession #:Packet> .
# Message
Packet = @complete bytes / @fragmented [bytes ...] .
# When layering Syndicate protocol over noise,

View File

@ -16,4 +16,4 @@ TurnEvent = [@oid Oid @event Event].
Assert = <A @assertion Assertion @handle Handle>.
Retract = <R @handle Handle>.
Message = <M @body Assertion>.
Sync = <S @peer #!#t>.
Sync = <S @peer #:#t>.

View File

@ -2,7 +2,7 @@ version 1 .
embeddedType EntityRef.Cap .
# Assertion:
StreamConnection = <stream-connection @source #!Source @sink #!Sink @spec any>.
StreamConnection = <stream-connection @source #:Source @sink #:Sink @spec any>.
# Assertions:
StreamListenerReady = <stream-listener-ready @spec any>.
@ -13,7 +13,7 @@ StreamError = <error @message string>.
Source =
# Assertions:
/ <sink @controller #!Sink>
/ <sink @controller #:Sink>
/ StreamError
# Messages:
@ -22,7 +22,7 @@ Source =
Sink =
# Assertions:
/ <source @controller #!Source>
/ <source @controller #:Source>
/ StreamError
# Messages:

View File

@ -51,7 +51,7 @@ Lit = <lit @value any>.
Pattern = PDiscard / PAtom / PEmbedded / PBind / PAnd / PNot / Lit / PCompound .
PDiscard = <_>.
PAtom = =Boolean / =Float / =Double / =SignedInteger / =String / =ByteString / =Symbol .
PAtom = =Boolean / =Double / =SignedInteger / =String / =ByteString / =Symbol .
PEmbedded = =Embedded .
PBind = <bind @pattern Pattern>.
PAnd = <and @patterns [Pattern ...]>.

View File

@ -4,4 +4,4 @@ embeddedType EntityRef.Cap .
TcpRemote = <tcp-remote @host string @port int>.
TcpLocal = <tcp-local @host string @port int>.
TcpPeerInfo = <tcp-peer @handle #!any @local TcpLocal @remote TcpRemote>.
TcpPeerInfo = <tcp-peer @handle #:any @local TcpLocal @remote TcpRemote>.

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { SyndicateRollup } from '../../rollup.js';
const r = new SyndicateRollup('syndicate', { globalName: 'Syndicate' });

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export * from '@preserves/core';
@ -10,6 +10,7 @@ export * as DataspacePatterns from './gen/dataspacePatterns.js';
export * from './runtime/actor.js';
export * from './runtime/bag.js';
export * as Dataflow from './runtime/dataflow.js';
export { Field } from './runtime/dataflow.js';
export * from './runtime/dataspace.js';
export * from './runtime/mirror.js';
export * as Pattern from './runtime/pattern.js';

View File

@ -1,13 +1,13 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { IdentitySet, Value, embeddedId, is, fromJS, stringify, Dictionary, KeyedSet } from '@preserves/core';
import { Cell, Field, Graph } from './dataflow';
import { Caveat, runRewrites } from './rewrite';
import { ActorSpace } from './space';
import { ActionDescription, StructuredTask, TaskAction } from './task';
import { randomId } from './randomid';
import * as Q from '../gen/queuedTasks';
import { IdentitySet, Value, embeddedId, is, fromJS, stringify, KeyedSet, Tuple, Embeddable, IsEmbedded } from '@preserves/core';
import { Cell, Field, Graph } from './dataflow.js';
import { Caveat, runRewrites } from './rewrite.js';
import { ActorSpace } from './space.js';
import { ActionDescription, StructuredTask, TaskAction } from './task.js';
import { randomId } from './randomid.js';
import * as Q from '../gen/queuedTasks.js';
import { Mirror, Reflectable, _asRef } from './mirror';
import * as Refl from '../gen/mirror';
@ -26,7 +26,11 @@ export type ExitReason = null | { ok: true } | { ok: false, err: unknown };
export type LocalAction = () => void;
export type DetailedAction<T = AnyValue> = LocalAction & { detail: T };
export type Assertable = Assertion | { __as_preserve__: <T>() => Value<T> } | { __as_preserve__: () => Assertion };
export type Assertable =
| Assertion
| { __as_preserve__: <T extends Embeddable>() => Value<T> }
| { __as_preserve__: () => Assertion }
;
export interface Entity {
assert(assertion: Assertion, handle: Handle): void;
@ -43,13 +47,9 @@ export interface Entity {
export type Cap = Ref;
export interface Ref {
readonly relay: Facet;
readonly target: Partial<Entity>;
readonly attenuation?: Caveat[];
}
export class Ref implements Reflectable {
get [IsEmbedded](): true { return true; }
export class RefImpl implements Ref, Reflectable {
readonly relay: Facet;
readonly target: Partial<Entity>;
readonly attenuation?: Caveat[];
@ -76,6 +76,10 @@ export class RefImpl implements Ref, Reflectable {
if ('sync' in this.target) sig = sig + 'S';
return `${this.relay.idChain()}<${sig}>${entityRepr}`;
}
static __from_preserve__(v: AnyValue): undefined | Ref {
return typeof v === 'object' && IsEmbedded in v && 'relay' in v ? v : void 0;
}
}
//---------------------------------------------------------------------------
@ -180,8 +184,12 @@ export class Actor implements Reflectable {
return this._dataflowGraph;
}
atExit(a: LocalAction): void {
atExit(a: LocalAction): () => void {
this.exitHooks.push(a);
return () => {
const i = this.exitHooks.indexOf(a);
if (i !== -1) this.exitHooks.splice(i, 1);
};
}
_terminateWith(reason: Exclude<ExitReason, null>) {
@ -284,6 +292,10 @@ export class Facet implements Reflectable {
this._reflection?.mirror.setProp(this._reflection.childHandles, '' + child.id, void 0);
}
wrap<T extends Tuple<any>>(f: (... args: T) => void): (... args: T) => void {
return (... args) => this.turn(() => f(... args));
}
turn(a: LocalAction) {
Turn.for(this, a);
}
@ -323,12 +335,17 @@ export class Facet implements Reflectable {
_halfLink(other: Facet): void {
const h = nextHandle++;
const peer = { relay: other, target: new StopOnRetract() };
this.outbound.set(h, { handle: h, peer, crossSpace: null, established: true });
const e = {
handle: h,
peer: new Ref(other, new StopOnRetract()),
crossSpace: null,
established: true,
};
this.outbound.set(h, e);
this._reflection?.mirror.setProp(
this._reflection.assertionHandles,
'' + h,
Refl.FacetAssertion({ handle: h, target: peer }));
Refl.FacetAssertion({ handle: h, target: e.peer }));
}
_terminate(orderly: boolean): void {
@ -383,7 +400,7 @@ export const STOP_ON_RETRACT = Symbol('stop-on-retract'); // NB. NOT A GLOBAL SY
export class StopOnRetract implements Partial<Entity> {
retract(_handle: Handle): void {
Turn.active.stop();
Turn.active.stop(Turn.activeFacet);
}
actor = STOP_ON_RETRACT;
}
@ -455,7 +472,7 @@ export class Turn {
}
ref<T extends Partial<Entity>>(e: T): Ref {
return new RefImpl(this.activeFacet, e);
return new Ref(this.activeFacet, e);
}
facet(bootProc: LocalAction): Facet {
@ -465,11 +482,14 @@ export class Turn {
}
// Alias for syndicatec code generator to use
_stop(facet: Facet = this.activeFacet, continuation?: LocalAction) {
_stop(facet: Facet, continuation?: LocalAction) {
this.stop(facet, continuation);
}
stop(facet: Facet = this.activeFacet, continuation?: LocalAction) {
stop(facet: Facet, continuation?: LocalAction) {
if (facet.actor !== Turn.activeFacet.actor) {
throw new Error("Attempt to terminate a facet in a different actor");
}
if (continuation) facet.onStop(continuation);
facet._terminate(true);
}
@ -507,7 +527,7 @@ export class Turn {
});
},
() => {
const a = new KeyedSet<number, Ref>();
const a = new KeyedSet<Ref, number>();
initialAssertions.forEach(h => a.add(h));
return Q.ActionDescription.spawnActor({ detail, initialAssertions: a });
});
@ -536,10 +556,10 @@ export class Turn {
crash(err: Error): void {
this.enqueue(this.activeFacet.actor.root,
() => this.activeFacet.actor._terminateWith({ ok: false, err }),
() => Q.ActionDescription.stopActor(Q.OptionalAny.some(Dictionary.fromJS({
() => Q.ActionDescription.stopActor(Q.OptionalAny.some<Ref>({
message: err.message,
stack: err.stack ? err.stack : false,
}))));
})));
}
field<V>(initial: V, name?: string): Field<V> {

View File

@ -1,9 +1,9 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
// Bags and Deltas (which are Bags where item-counts can be negative).
import { Value, KeyedDictionary, KeyedSet } from '@preserves/core';
import { Value, KeyedDictionary, KeyedSet, Embeddable } from '@preserves/core';
export enum ChangeDescription {
PRESENT_TO_ABSENT = -1,
@ -12,10 +12,10 @@ export enum ChangeDescription {
PRESENT_TO_PRESENT = 2,
}
export class Bag<T, V extends Value<T> = Value<T>> {
_items: KeyedDictionary<V, number, T>;
export class Bag<T extends Embeddable, V extends Value<T> = Value<T>> {
_items: KeyedDictionary<T, V, number>;
constructor(s?: KeyedSet<V, T>) {
constructor(s?: KeyedSet<T, V>) {
this._items = new KeyedDictionary();
if (s) s.forEach((v) => this._items.set(v, 1));
}
@ -68,7 +68,7 @@ export class Bag<T, V extends Value<T> = Value<T>> {
this._items.forEach((c, v) => f(c, v));
}
snapshot(): KeyedDictionary<V, number, T> {
snapshot(): KeyedDictionary<T, V, number> {
return this._items.clone();
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
// Property-based "dataflow"

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Record, IdentityMap, KeyedDictionary, stringify } from '@preserves/core';
import { Index, IndexObserver } from './skeleton.js';
@ -18,7 +18,7 @@ export type DataspaceOptions = {
};
export class DataspaceObserver implements IndexObserver<Turn> {
readonly captureMap = new KeyedDictionary<Array<AnyValue>, Handle, Ref>();
readonly captureMap = new KeyedDictionary<Ref, Array<AnyValue>, Handle>();
constructor(
public readonly target: Ref,

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
// Utilities for Maps of Sets

View File

@ -1,7 +1,7 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { canonicalString, KeyedDictionary, Dictionary, is, Record, RecordConstructorInfo, Value, CompoundKey, _iterMap } from '@preserves/core';
import { canonicalString, KeyedDictionary, is, Record, RecordConstructorInfo, Value, _iterMap, DictionaryMap, Dictionary, EncodableDictionary } from '@preserves/core';
import { AnyValue, Ref } from './actor.js';
import * as P from '../gen/dataspacePatterns.js';
@ -13,20 +13,20 @@ export function classOfValue(v: any): Shape | null {
if (Record.isRecord(v)) {
return constructorInfoSignature(Record.constructorInfo(v));
} else if (Array.isArray(v)) {
return '' + v.length;
} else if (Map.isMap(v)) {
return '[]';
} else if (Dictionary.isDictionary(v)) {
return '{}';
} else {
return null;
}
}
export function classOfCtor(v: P.DCompound): Shape {
export function classOfCtor(v: P.GroupType): Shape {
switch (v._variant) {
case 'rec':
return canonicalString(v.label) + '/' + v.fields.length;
return canonicalString(v.label);
case 'arr':
return '' + v.items.length;
return '[]';
case 'dict':
return '{}';
}
@ -34,55 +34,59 @@ export function classOfCtor(v: P.DCompound): Shape {
// Called by generated code in addition to functions in this module
export function constructorInfoSignature(ci: RecordConstructorInfo<Value>): string {
return canonicalString(ci.label) + '/' + ci.arity;
return canonicalString(ci.label);
}
export function step(v: AnyValue, index: AnyValue): AnyValue | undefined {
if (Map.isMap(v)) {
return v.get(index);
const vMap = Dictionary.asMap<Ref>(v);
if (vMap) {
return vMap.get(index);
} else {
return (v as Array<AnyValue> /* includes Record! */)[index as number];
}
}
export type ConstantPositions = {
withValues: Array<Path>,
requiredToExist: Array<Path>,
}
export type PatternAnalysis = {
constPaths: Array<Path>,
constPositions: ConstantPositions,
constValues: Array<AnyValue>,
capturePaths: Array<Path>,
};
export function analysePattern(p: P.Pattern): PatternAnalysis {
const result: PatternAnalysis = {
constPaths: [],
constPositions: {
withValues: [],
requiredToExist: [],
},
constValues: [],
capturePaths: [],
};
const path: Path = [];
function walkKey(p: P.Pattern, key: AnyValue) {
path.push(key);
walk(p);
path.pop();
}
function walk(p: P.Pattern) {
switch (p._variant) {
case 'DCompound':
switch (p.value._variant) {
case 'rec': p.value.fields.forEach(walkKey); break;
case 'arr': p.value.items.forEach(walkKey); break;
case 'dict': p.value.entries.forEach(walkKey); break;
}
case 'group':
p.entries.forEach((p, k) => {
path.push(k);
walk(p);
path.pop();
});
break;
case 'DBind':
case 'bind':
result.capturePaths.push(path.slice());
walk(p.value.pattern);
walk(p.pattern);
break;
case 'DDiscard':
case 'discard':
result.constPositions.requiredToExist.push(path.slice());
break;
case 'DLit':
result.constPaths.push(path.slice());
result.constValues.push(P.fromAnyAtom(p.value.value));
case 'lit':
result.constPositions.withValues.push(path.slice());
result.constValues.push(P.fromAnyAtom(p.value));
break;
}
}
@ -96,32 +100,20 @@ export function match(p: P.Pattern, v: AnyValue): Array<AnyValue> | false {
function walk(p: P.Pattern, v: AnyValue): boolean {
switch (p._variant) {
case 'DBind': {
case 'bind': {
captures.push(v);
return walk(p.value.pattern, v);
return walk(p.pattern, v);
}
case 'DDiscard':
case 'discard':
return true;
case 'DLit':
return is(p.value.value, v);
case 'DCompound': {
const pcls = classOfCtor(p.value);
case 'lit':
return is(p.value, v);
case 'group': {
const pcls = classOfCtor(p.type);
const vcls = classOfValue(v);
if (pcls !== vcls) return false;
let items: Array<P.Pattern>;
switch (p.value._variant) {
case 'dict':
for (const [stepIndex, pp] of p.value.entries.entries()) {
const vv = step(v, stepIndex);
if (vv === void 0 || !walk(pp, vv)) return false;
}
return true;
case 'rec': items = p.value.fields; break;
case 'arr': items = p.value.items; break;
}
let index = 0;
for (const pp of items) {
const vv = step(v, index++);
for (const [stepIndex, pp] of p.entries.entries()) {
const vv = step(v, stepIndex);
if (vv === void 0 || !walk(pp, vv)) return false;
}
return true;
@ -135,19 +127,14 @@ export function match(p: P.Pattern, v: AnyValue): Array<AnyValue> | false {
export function isCompletelyConcrete(p: P.Pattern): boolean {
function walk(p: P.Pattern): boolean {
switch (p._variant) {
case 'DBind': return false;
case 'DDiscard': return false;
case 'DLit': return true;
case 'DCompound': switch (p.value._variant) {
case 'rec': return p.value.fields.every(isCompletelyConcrete);
case 'arr': return p.value.items.every(isCompletelyConcrete);
case 'dict': {
for (const pp of p.value.entries.values()) {
if (!walk(pp)) return false;
}
return true;
case 'bind': return false;
case 'discard': return false;
case 'lit': return true;
case 'group':
for (const pp of p.entries.values()) {
if (!walk(pp)) return false;
}
}
return true;
}
}
return walk(p);
@ -156,26 +143,19 @@ export function isCompletelyConcrete(p: P.Pattern): boolean {
export function withoutCaptures(p: P.Pattern): P.Pattern {
function walk(p: P.Pattern): P.Pattern {
switch (p._variant) {
case 'DBind': return walk(p.value.pattern);
case 'DDiscard': return p;
case 'DLit': return p;
case 'DCompound':
switch (p.value._variant) {
case 'rec':
return P.Pattern.DCompound(P.DCompound.rec({
label: p.value.label,
fields: p.value.fields.map(walk),
}));
case 'arr':
return P.Pattern.DCompound(P.DCompound.arr(p.value.items.map(walk)));
case 'dict': {
const newDict = new KeyedDictionary<Value<Ref>, P.Pattern<Ref>, Ref>();
for (const [k, v] of p.value.entries) {
newDict.set(k, walk(v));
}
return P.Pattern.DCompound(P.DCompound.dict(newDict));
}
case 'bind': return walk(p.pattern);
case 'discard': return p;
case 'lit': return p;
case 'group': {
const newEntries = new KeyedDictionary<Ref, Value<Ref>, P.Pattern<Ref>>();
for (const [kk, pp] of p.entries) {
newEntries.set(kk, walk(pp));
}
return P.Pattern.group({
type: p.type,
entries: newEntries,
});
}
}
}
return walk(p);
@ -185,57 +165,92 @@ export function withoutCaptures(p: P.Pattern): P.Pattern {
// Constructor helpers
export function bind(p?: P.Pattern): P.Pattern {
return P.Pattern.DBind(P.DBind(p ?? _));
return P.Pattern.bind(p ?? _);
}
export function discard(): P.Pattern {
return P.Pattern.DDiscard(P.DDiscard());
return P.Pattern.discard();
}
export const _ = discard();
function lit_seq_entries(vs: AnyValue[]): KeyedDictionary<Ref, AnyValue, P.Pattern<Ref>> {
const entries = new KeyedDictionary<Ref, AnyValue, P.Pattern<Ref>>();
vs.forEach((v, i) => entries.set(i, lit(v)));
return entries;
}
export function lit(v: AnyValue): P.Pattern {
if (Array.isArray(v)) {
if ('label' in v) {
return P.Pattern.DCompound(P.DCompound.rec({
label: v.label,
fields: v.map(lit),
}));
return P.Pattern.group({
type: P.GroupType.rec(v.label),
entries: lit_seq_entries(v),
});
} else {
return P.Pattern.DCompound(P.DCompound.arr(v.map(lit)));
return P.Pattern.group({
type: P.GroupType.arr(),
entries: lit_seq_entries(v),
});
}
} else if (Map.isMap(v)) {
return P.Pattern.DCompound(P.DCompound.dict(v.mapEntries(
e => [e[0], lit(e[1])])));
} else if (Set.isSet(v)) {
throw new Error("Cannot express literal set in pattern");
} else {
return P.Pattern.DLit(P.DLit(P.asAnyAtom(v)));
}
const vMap = Dictionary.asMap<Ref>(v);
if (vMap) {
const r = new KeyedDictionary<Ref, AnyValue, P.Pattern>();
vMap.forEach((val, key) => r.set(key, lit(val)));
return P.Pattern.group({
type: P.GroupType.dict(),
entries: r,
});
}
if (Set.isSet(v)) {
throw new Error("Cannot express literal set in pattern");
}
return P.Pattern.lit(P.asAnyAtom(v));
}
export function drop_lit(p: P.Pattern): AnyValue | null {
const e = new Error();
function walkEntries(target: AnyValue[], entries: EncodableDictionary<Ref, AnyValue, P.Pattern<Ref>>): void {
let maxKey = -1;
for (const key of entries.keys()) {
if (typeof key !== 'number') throw e;
maxKey = Math.max(maxKey, key);
}
for (let i = 0; i < maxKey + 1; i++) {
const p = entries.get(i);
if (p === void 0) throw e;
target.push(walk(p));
}
}
function walk(p: P.Pattern): AnyValue {
switch (p._variant) {
case 'DCompound':
switch (p.value._variant) {
case 'group':
switch (p.type._variant) {
case 'rec': {
const v = [] as unknown as Record<AnyValue, AnyValue[], Ref>;
v.label = p.value.label;
p.value.fields.forEach(tt => v.push(walk(tt)));
v.label = p.type.label;
walkEntries(v, p.entries);
return v;
}
case 'arr':
return p.value.items.map(walk);
case 'dict': {
const v = new Dictionary<Ref, AnyValue>();
p.value.entries.forEach((pp, key) => v.set(key, walk(pp)));
case 'arr': {
const v = [] as AnyValue[];
walkEntries(v, p.entries);
return v;
}
case 'dict': {
const v = new DictionaryMap<Ref, AnyValue>();
p.entries.forEach((pp, key) => v.set(key, walk(pp)));
return v.simplifiedValue();
}
}
case 'DLit':
return P.fromAnyAtom(p.value.value);
case 'lit':
return P.fromAnyAtom(p.value);
default:
throw e;
}
@ -249,13 +264,22 @@ export function drop_lit(p: P.Pattern): AnyValue | null {
}
export function rec(label: AnyValue, ... fields: P.Pattern[]): P.Pattern {
return P.Pattern.DCompound(P.DCompound.rec({ label, fields }));
return P.Pattern.group({
type: P.GroupType.rec(label),
entries: new KeyedDictionary<Ref, AnyValue, P.Pattern>(fields.map((p, i) => [i, p])),
});
}
export function arr(... patterns: P.Pattern[]): P.Pattern {
return P.Pattern.DCompound(P.DCompound.arr(patterns));
return P.Pattern.group({
type: P.GroupType.arr(),
entries: new KeyedDictionary<Ref, AnyValue, P.Pattern>(patterns.map((p, i) => [i, p])),
});
}
export function dict(... entries: [AnyValue, P.Pattern][]): P.Pattern {
return P.Pattern.DCompound(P.DCompound.dict(new Dictionary<Ref, P.Pattern>(entries)));
return P.Pattern.group({
type: P.GroupType.dict(),
entries: new KeyedDictionary<Ref, AnyValue, P.Pattern>(entries),
});
}

View File

@ -1,10 +1,10 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2021-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2021-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { AnyValue, Ref } from './actor.js';
import { Pattern, toPattern } from '../gen/dataspacePatterns.js';
import { Pattern, toPattern, GroupType, fromGroupType } from '../gen/dataspacePatterns.js';
import * as P from './pattern.js';
import { RecordConstructorInfo, is, Record } from '@preserves/core';
import { RecordConstructorInfo, is, Record, JsDictionary } from '@preserves/core';
import { Meta, Type, GenType, SchemaDefinition } from '@preserves/schema';
export type QuasiValueConstructorInfo =
@ -17,9 +17,7 @@ export type QuasiValue =
| { type: 'bind', inner: QuasiValue }
| { type: 'discard' }
| { type: 'lit', value: AnyValue }
| { type: 'rec', label: AnyValue, items: QuasiValue[] }
| { type: 'arr', items: QuasiValue[] }
| { type: 'dict', entries: [AnyValue, QuasiValue][] }
| { type: 'group', groupType: GroupType, entries: [AnyValue, QuasiValue][] }
| { type: 'unquote', unquoted: QuasiValue }
;
@ -58,7 +56,8 @@ export function rec(label: AnyValue, ... items: QuasiValue[]): QuasiValue {
if (literals.length === items.length) {
return lit(Record(label, literals));
} else {
return { type: 'rec', label, items };
const entries = items.map((v, i) => [i, v] as [number, QuasiValue]);
return { type: 'group', groupType: GroupType.rec(label), entries };
}
}
@ -67,12 +66,13 @@ export function arr(... items: QuasiValue[]): QuasiValue {
if (literals.length === items.length) {
return lit(literals);
} else {
return { type: 'arr', items };
const entries = items.map((v, i) => [i, v] as [number, QuasiValue]);
return { type: 'group', groupType: GroupType.arr(), entries };
}
}
export function dict(... entries: [AnyValue, QuasiValue][]): QuasiValue {
return { type: 'dict', entries };
return { type: 'group', groupType: GroupType.dict(), entries };
}
export function quote(quoted: QuasiValue): QuasiValue {
@ -80,12 +80,9 @@ export function quote(quoted: QuasiValue): QuasiValue {
case 'bind': return quote(bind.quasiValue(quoted.inner));
case 'discard': return quote(discard.quasiValue());
case 'lit': return rec(Symbol.for('lit'), lit(quoted.value));
case 'arr': return rec(Symbol.for('arr'), arr(
... quoted.items.map(quote)));
case 'rec': return rec(Symbol.for('rec'), lit(quoted.label), arr(
... quoted.items.map(quote)));
case 'dict': return rec(Symbol.for('dict'), dict(
... quoted.entries.map(([k, qq]) => [k, quote(qq)] as [AnyValue, QuasiValue])));
case 'group':
return rec(Symbol.for('group'), lit(fromGroupType(quoted.groupType)), dict(
... quoted.entries.map(([k, qq]) => [k, quote(qq)] as [AnyValue, QuasiValue])));
case 'unquote': return quoted.unquoted;
}
}
@ -94,13 +91,27 @@ export function unquote(unquoted: QuasiValue): QuasiValue {
return { type: 'unquote', unquoted };
}
function entriesSeq<V>(entries: [AnyValue, V][], defaultValue: V): V[] {
let maxKey = -1;
const result: V[] = [];
for (const [k, q] of entries) {
if (typeof k !== 'number') throw new Error("Invalid sequence quasivalue entries key");
result[k] = q;
maxKey = Math.max(maxKey, k);
}
for (let i = 0; i < maxKey + 1; i++) {
if (result[i] === void 0) result[i] = defaultValue;
}
return result;
}
export function ctor(info: QuasiValueConstructorInfo, ... items: QuasiValue[]): QuasiValue {
if ('constructorInfo' in info) {
return rec(info.constructorInfo.label, ... items);
} else if ('schema' in info) {
const definfo = info.schema();
const schema = Meta.asSchema(definfo.schema);
const def = schema.definitions.get(definfo.definitionName)!;
const def = JsDictionary.get(schema.definitions, definfo.definitionName)!;
const defNameStr = definfo.definitionName.description!;
const ctorArgs = items.slice();
@ -158,7 +169,7 @@ export function ctor(info: QuasiValueConstructorInfo, ... items: QuasiValue[]):
if (d.type === 'discard') {
return d;
}
if (d.type !== 'dict') {
if (d.type !== 'group' || d.groupType._variant !== 'dict') {
throw new Error(`Dictionary argument needed to ${defNameStr}`);
}
for (const [k, p] of d.entries) {
@ -217,8 +228,8 @@ export function ctor(info: QuasiValueConstructorInfo, ... items: QuasiValue[]):
}
function qArr(q: QuasiValue): QuasiValue[] {
if (q.type === 'arr') {
return q.items;
if (q.type === 'group' && q.groupType._variant === 'arr') {
return entriesSeq(q.entries, discard());
} else if (q.type === 'lit' && Array.isArray(q.value)) {
return q.value.map(lit);
} else {
@ -284,10 +295,12 @@ function walk(q: QuasiValue): Pattern {
case 'bind': return P.bind(walk(q.inner));
case 'discard': return P._;
case 'lit': return P.lit(q.value);
case 'arr': return P.arr(... q.items.map(walk));
case 'rec': return P.rec(q.label, ... q.items.map(walk));
case 'dict': return P.dict(... q.entries.map(
([k, qq]) => [k, walk(qq)] as [AnyValue, Pattern]));
case 'group': switch (q.groupType._variant) {
case 'arr': return P.arr(... entriesSeq(q.entries, discard()).map(walk));
case 'rec': return P.rec(q.groupType.label, ... entriesSeq(q.entries, discard()).map(walk));
case 'dict': return P.dict(... q.entries.map(
([k, qq]) => [k, walk(qq)] as [AnyValue, Pattern]));
}
case 'unquote': throw new Error('Unexpected unquote in QuasiValue');
}
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Bytes } from '@preserves/core';
import * as node_crypto from 'crypto';

View File

@ -1,9 +1,9 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Turn } from "./actor.js";
import { Bytes, Dictionary, DoubleFloat, embed, IdentityMap, is, isEmbedded, Record, SingleFloat, Tuple, stringify } from "@preserves/core";
import type { Assertion, Handle, Ref } from "./actor.js";
import { Turn, Ref } from "./actor.js";
import { Bytes, Dictionary, DictionaryMap, DoubleFloat, IdentityMap, KeyedDictionary, is, isEmbedded, Record, Tuple, stringify } from "@preserves/core";
import type { Assertion, Handle } from "./actor.js";
import type { SturdyValue } from "../transport/sturdy.js";
import {
@ -19,6 +19,8 @@ import {
PEmbedded,
Pattern,
Rewrite,
TAttenuate,
TCompound,
TRef,
Template,
_embedded,
@ -39,7 +41,6 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
case 'Boolean': return typeof v === 'boolean';
case 'ByteString': return Bytes.isBytes(v);
case 'Double': return DoubleFloat.isDouble(v);
case 'Float': return SingleFloat.isSingle(v);
case 'SignedInteger': return typeof v === 'number';
case 'String': return typeof v === 'string';
case 'Symbol': return typeof v === 'symbol';
@ -88,9 +89,10 @@ export function match(p: Pattern, v: Assertion): Bindings | null {
return true;
}
case 'dict':{
if (!Dictionary.isDictionary<Ref, Assertion>(v)) return false;
const vMap = Dictionary.asMap<Ref, Assertion>(v);
if (!vMap) return false;
for (const [key, pp] of p.value.entries.entries()) {
const vv = v.get(key);
const vv = vMap.get(key);
if (vv === void 0) return false;
if (!walk(pp, vv)) return false;
}
@ -114,8 +116,7 @@ export function instantiate(t: Template, b: Bindings): Assertion {
if (!isEmbedded(v)) {
throw new Error(`Attempt to attenuate non-capability: ${stringify(v)}`);
}
const r = v.embeddedValue;
return embed(attenuate(r, ... t.value.attenuation));
return attenuate(v, ... t.value.attenuation);
}
case 'TRef': {
const n = t.value.binding;
@ -136,9 +137,9 @@ export function instantiate(t: Template, b: Bindings): Assertion {
case 'arr':
return t.value.items.map(walk);
case 'dict': {
const v = new Dictionary<Ref, Assertion>();
const v = new DictionaryMap<Ref, Assertion>();
t.value.entries.forEach((tt, key) => v.set(key, walk(tt)));
return v;
return v.simplifiedValue();
}
}
}
@ -193,9 +194,14 @@ export function rfilter(... patterns: Pattern[]): Caveat {
return ps.length === 1 ? Caveat.Rewrite(ps[0]) : Caveat.Alts(Alts(ps));
}
export function rmap(... rewrites: [Pattern, Template][]): Caveat {
const rs = rewrites.map(([pattern, template]) => Rewrite({ pattern, template }));
return rs.length === 1 ? Caveat.Rewrite(rs[0]) : Caveat.Alts(Alts(rs));
}
export function attenuate(ref: Ref, ... a: Caveat[]): Ref {
if (a.length === 0) return ref;
return { ... ref, attenuation: [... (ref.attenuation ?? []), ... a] };
return new Ref(ref.relay, ref.target, [... (ref.attenuation ?? []), ... a]);
}
export function forwarder(ref: Ref): { proxy: Ref, revoker: Ref } {
@ -238,7 +244,7 @@ export function pArr(... items: Array<Pattern>): Pattern {
}
export function pDict(... entries: [SturdyValue, Pattern][]): Pattern {
return Pattern.PCompound(PCompound.dict(new Dictionary<_embedded, Pattern>(entries)));
return Pattern.PCompound(PCompound.dict(new KeyedDictionary<_embedded, SturdyValue, Pattern>(entries)));
}
export function pLit(value: SturdyValue): Pattern {
@ -281,10 +287,6 @@ export function pDouble(): Pattern {
return Pattern.PAtom(PAtom.Double());
}
export function pFloat(): Pattern {
return Pattern.PAtom(PAtom.Float());
}
export function pBoolean(): Pattern {
return Pattern.PAtom(PAtom.Boolean());
}
@ -292,3 +294,27 @@ export function pBoolean(): Pattern {
export function pDiscard(): Pattern {
return Pattern.PDiscard(PDiscard());
}
export function tRec(label: SturdyValue, ... fields: Array<Template>): Template {
return Template.TCompound(TCompound.rec({ label, fields }));
}
export function tArr(... items: Array<Template>): Template {
return Template.TCompound(TCompound.arr(items));
}
export function tDict(... entries: [SturdyValue, Template][]): Template {
return Template.TCompound(TCompound.dict(new KeyedDictionary<_embedded, SturdyValue, Template>(entries)));
}
export function tLit(value: SturdyValue): Template {
return Template.Lit(Lit(value));
}
export function tRef(binding: number): Template {
return Template.TRef(TRef(binding));
}
export function tAttenuate(template: Template, ... attenuation: Caveat[]): Template {
return Template.TAttenuate(TAttenuate({ template, attenuation }));
}

View File

@ -1,12 +1,12 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Set, Dictionary, KeyedDictionary, IdentitySet, stringify, Value } from '@preserves/core';
import { Set, KeyedDictionary, IdentitySet, stringify, Value, Embeddable } from '@preserves/core';
import { AnyValue, Assertion, Ref } from './actor.js';
import { Bag, ChangeDescription } from './bag.js';
import * as Stack from './stack.js';
import * as P from '../gen/dataspacePatterns.js';
import { Path, analysePattern, classOfCtor, classOfValue, step } from './pattern.js';
import { Path, analysePattern, classOfCtor, classOfValue, step, Shape, ConstantPositions } from './pattern.js';
enum EventType {
ADDED = +1,
@ -31,13 +31,15 @@ export class Index<T> {
readonly root: Node<T> = new Node(new Continuation(new Set()));
addObserver(pattern: P.Pattern, observer: IndexObserver<T>, parameter: T) {
let {constPaths, constValues, capturePaths} = analysePattern(pattern);
let {constPositions, constValues, capturePaths} = analysePattern(pattern);
const continuation = this.root.extend(pattern);
let constValMap = continuation.leafMap.get(constPaths);
let constValMap = continuation.leafMap.get(constPositions);
if (!constValMap) {
constValMap = new Dictionary();
constValMap = new KeyedDictionary();
continuation.cachedAssertions.forEach((a) => {
const key = projectPaths(a, constPaths);
if (projectPaths(a, constPositions.requiredToExist) === void 0) return;
const key = projectPaths(a, constPositions.withValues);
if (key === void 0) return;
let leaf = constValMap!.get(key);
if (!leaf) {
leaf = new Leaf();
@ -45,7 +47,7 @@ export class Index<T> {
}
leaf.cachedAssertions.add(a);
});
continuation.leafMap.set(constPaths, constValMap);
continuation.leafMap.set(constPositions, constValMap);
}
let leaf = constValMap.get(constValues);
if (!leaf) {
@ -55,8 +57,10 @@ export class Index<T> {
let observerGroup = leaf.observerGroups.get(capturePaths);
if (!observerGroup) {
const cachedCaptures = new Bag<Ref, Array<AnyValue>>();
leaf.cachedAssertions.forEach((a) =>
cachedCaptures._items.update(projectPaths(a, capturePaths), n => n! + 1, 0));
leaf.cachedAssertions.forEach((a) => {
const vs = projectPaths(a, capturePaths);
if (vs !== void 0) cachedCaptures._items.update(vs, n => n! + 1, 0);
});
observerGroup = new ObserverGroup(cachedCaptures);
leaf.observerGroups.set(capturePaths, observerGroup);
}
@ -65,9 +69,9 @@ export class Index<T> {
}
removeObserver(pattern: P.Pattern, observer: IndexObserver<T>, parameter: T) {
let {constPaths, constValues, capturePaths} = analysePattern(pattern);
let {constPositions, constValues, capturePaths} = analysePattern(pattern);
const continuation = this.root.extend(pattern);
let constValMap = continuation.leafMap.get(constPaths);
let constValMap = continuation.leafMap.get(constPositions);
if (!constValMap) return;
let leaf = constValMap.get(constValues);
if (!leaf) return;
@ -82,7 +86,7 @@ export class Index<T> {
constValMap.delete(constValues);
}
if (constValMap.size === 0) {
continuation.leafMap.delete(constPaths);
continuation.leafMap.delete(constPositions);
}
}
@ -142,13 +146,13 @@ export class Index<T> {
}
}
function dumpBag<T, V extends Value<T>>(b: Bag<T, V>, indent: string) {
function dumpBag<T extends Embeddable, V extends Value<T>>(b: Bag<T, V>, indent: string) {
for (const [v, count] of b.entries()) {
console.log(indent + stringify(v) + ' = ' + count);
}
}
function dumpSet<V>(s: Set<V>, indent: string) {
function dumpSet<V extends Embeddable>(s: Set<V>, indent: string) {
s.forEach(v => console.log(indent + stringify(v)));
}
@ -156,7 +160,7 @@ type Selector = [number, AnyValue];
class Node<T> {
readonly continuation: Continuation<T>;
readonly edges: KeyedDictionary<Selector, { [shape: string]: Node<T> }, Ref> = new KeyedDictionary();
readonly edges: KeyedDictionary<Ref, Selector, { [shape: Shape]: Node<T> }> = new KeyedDictionary();
constructor(continuation: Continuation<T>) {
this.continuation = continuation;
@ -168,19 +172,19 @@ class Node<T> {
function walkNode(node: Node<T>, popCount: number, stepIndex: AnyValue, p: P.Pattern): [number, Node<T>]
{
switch (p._variant) {
case 'DDiscard':
case 'DLit':
case 'discard':
case 'lit':
return [popCount, node];
case 'DBind':
return walkNode(node, popCount, stepIndex, p.value.pattern);
case 'DCompound': {
case 'bind':
return walkNode(node, popCount, stepIndex, p.pattern);
case 'group': {
const selector: Selector = [popCount, stepIndex];
let table = node.edges.get(selector);
if (!table) {
table = {};
node.edges.set(selector, table);
}
let cls = classOfCtor(p.value);
let cls = classOfCtor(p.type);
let nextNode = table[cls];
if (!nextNode) {
nextNode = new Node(new Continuation(
@ -189,16 +193,11 @@ class Node<T> {
table[cls] = nextNode;
}
popCount = 0;
function walkKey(pp: P.Pattern, stepIndex: AnyValue) {
p.entries.forEach((pp, stepIndex) => {
path.push(stepIndex);
[popCount, nextNode] = walkNode(nextNode, popCount, stepIndex, pp);
path.pop();
}
switch (p.value._variant) {
case 'rec': p.value.fields.forEach(walkKey); break;
case 'arr': p.value.items.forEach(walkKey); break;
case 'dict': p.value.entries.forEach(walkKey); break;
}
});
return [popCount + 1, nextNode];
}
}
@ -226,8 +225,10 @@ class Node<T> {
function walkContinuation(continuation: Continuation<T>) {
m_cont(continuation, outerValue);
continuation.leafMap.forEach((constValMap, constPaths) => {
let constValues = projectPaths(outerValue, constPaths);
continuation.leafMap.forEach((constValMap, constPositions) => {
if (projectPaths(outerValue, constPositions.requiredToExist) === void 0) return;
let constValues = projectPaths(outerValue, constPositions.withValues);
if (constValues === void 0) return;
let leaf = constValMap.get(constValues);
if (!leaf && operation === EventType.ADDED) {
leaf = new Leaf();
@ -236,12 +237,13 @@ class Node<T> {
if (leaf) {
m_leaf(leaf, outerValue);
leaf.observerGroups.forEach((observerGroup, capturePaths) => {
m_observerGroup(observerGroup, projectPaths(outerValue, capturePaths));
const vs = projectPaths(outerValue, capturePaths);
if (vs !== void 0) m_observerGroup(observerGroup, vs);
});
if (operation === EventType.REMOVED && leaf.isEmpty()) {
constValMap.delete(constValues);
if (constValMap.size === 0) {
continuation.leafMap.delete(constPaths);
continuation.leafMap.delete(constPositions);
}
}
}
@ -267,7 +269,7 @@ class Node<T> {
class Continuation<T> {
readonly cachedAssertions: Set<Ref>;
readonly leafMap: KeyedDictionary<Array<Path>, Dictionary<Ref, Leaf<T>>, Ref> = new KeyedDictionary();
readonly leafMap: KeyedDictionary<Ref, ConstantPositions, KeyedDictionary<Ref, Assertion, Leaf<T>>> = new KeyedDictionary();
constructor(cachedAssertions: Set<Ref>) {
this.cachedAssertions = cachedAssertions;
@ -286,7 +288,7 @@ class Continuation<T> {
class Leaf<T> {
readonly cachedAssertions: Set<Ref> = new Set();
readonly observerGroups: KeyedDictionary<Array<Path>, ObserverGroup<T>, Ref> = new KeyedDictionary();
readonly observerGroups: KeyedDictionary<Ref, Array<Path>, ObserverGroup<T>> = new KeyedDictionary();
isEmpty(): boolean {
return this.cachedAssertions.size === 0 && this.observerGroups.size === 0;
@ -320,15 +322,21 @@ class ObserverGroup<T> {
}
}
// Total by assumption that path is valid for v
function projectPath(v: AnyValue, path: Path): AnyValue {
function projectPath(v: AnyValue, path: Path): AnyValue | undefined {
for (let index of path) {
v = step(v, index)!;
const next = step(v, index);
if (next === void 0) return void 0;
v = next;
}
return v;
}
// Total by assumption that paths are valid for v
function projectPaths(v: AnyValue, paths: Array<Path>): AnyValue[] {
return paths.map((path) => projectPath(v, path));
function projectPaths(v: AnyValue, paths: Array<Path>): AnyValue[] | undefined {
const result = [];
for (const path of paths) {
const w = projectPath(v, path);
if (w === void 0) return void 0;
result.push(w);
}
return result;
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { IdentityMap, IdentitySet, embeddedId, forEachEmbedded } from '@preserves/core';
import type { Actor, Assertion, ExitReason, Handle, Ref } from './actor.js';

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export type NonEmptyStack<T> = { item: T, rest: Stack<T> };
export type Stack<T> = null | NonEmptyStack<T>;

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2021-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2021-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { State } from '../gen/service';
import { Actor, AnyValue, LocalAction, Turn } from './actor';

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import type { Facet } from './actor.js';

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2021-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2021-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export * as dataspace from './gen/dataspace.js';
export * as dataspacePatterns from './gen/dataspacePatterns.js';

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Bytes, underlying } from '@preserves/core';
import * as node_crypto from 'crypto';
@ -18,6 +18,7 @@ export const newKey: () => Promise<Bytes> =
const HMAC_BLAKE2s = makeHMAC(BLAKE2s);
export async function mac(secretKey: Bytes, data: Bytes): Promise<Bytes> {
return Bytes.from(HMAC_BLAKE2s(underlying(secretKey), underlying(data)));
export function mac(secretKey: Bytes, data: Bytes): Bytes {
return Bytes.from(HMAC_BLAKE2s(underlying(secretKey), underlying(data))
.subarray(0, KEY_LENGTH));
}

View File

@ -0,0 +1,307 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Actor, Ref, Handle, Assertion, Entity, Turn } from '../runtime/actor.js';
import { Value, Embedded, mapEmbeddeds, IdentityMap, KeyedDictionary, stringify } from '@preserves/core';
import * as IO from '../gen/protocol.js';
import { fromCaveat, WireRef } from '../gen/sturdy.js';
import { attenuate } from '../runtime/rewrite.js';
export class WireSymbol {
count = 0;
constructor (
public side: Membrane,
public oid: IO.Oid,
public ref: Ref,
) {}
drop(): void {
this.count--;
if (this.count === 0) {
this.side.byOid.delete(this.oid);
this.side.byRef.delete(this.ref);
}
}
};
export type WhichTable = "byOid" | "byRef";
export class Membrane {
readonly byOid = new IdentityMap<IO.Oid, WireSymbol>();
readonly byRef = new IdentityMap<Ref, WireSymbol>();
grab<Table extends WhichTable>(table: Table,
key: Parameters<Membrane[Table]['get']>[0],
transient: boolean,
f: () => WireSymbol): WireSymbol;
grab<Table extends WhichTable>(table: Table,
key: Parameters<Membrane[Table]['get']>[0],
transient: boolean,
f: null): WireSymbol | null;
grab<Table extends WhichTable>(table: Table,
key: Parameters<Membrane[Table]['get']>[0],
transient: boolean,
f: (() => WireSymbol) | null): WireSymbol | null {
let e = this[table].get(key as any);
if (e === void 0) {
if (f === null) return null;
e = f();
this.byRef.set(e.ref, e);
this.byOid.set(e.oid, e);
}
if (!transient) e.count++;
return e;
}
}
export const INERT_REF = new Ref(
Actor.boot(() => Turn.active.stop(Turn.activeFacet)).root,
{});
export interface ProxyInbound {
proxyPacket(packet: IO.Packet<Embedded<WireRef>>): void;
}
export interface ProxyOutbound {
send(remoteOid: IO.Oid, event: IO.Event<Embedded<WireRef>>): void;
proxyAssertion(targetRemoteOid: IO.Oid, assertion: Assertion, handle: Handle): Value<Embedded<WireRef>>;
proxyRetract(handle: Handle): void;
proxyMessage(assertion: Assertion): Value<Embedded<WireRef>>;
proxySync(targetRemoteOid: IO.Oid, peer: Ref): Embedded<WireRef>;
}
export abstract class LayerBoundary implements ProxyOutbound, ProxyInbound {
readonly inboundAssertions = new IdentityMap<Handle, {
localHandle: Handle,
pins: Array<WireSymbol>,
}>();
readonly outboundAssertions = new IdentityMap<Handle, Array<WireSymbol>>();
readonly exported = new Membrane();
readonly imported = new Membrane();
constructor(public trustPeer = true, public nextLocalOid: IO.Oid = 0) {}
abstract send(remoteOid: IO.Oid, event: IO.Event<Embedded<WireRef>>): void;
proxyAssertion(targetRemoteOid: IO.Oid, assertion: Assertion, handle: Handle): Value<Embedded<WireRef>> {
const pins: Array<WireSymbol> = [];
const rewritten = mapEmbeddeds(assertion, r => this.rewriteRefOut(r, false, pins));
this.grabImportedOid(targetRemoteOid, pins);
this.outboundAssertions.set(handle, pins);
return rewritten;
}
proxyRetract(handle: Handle): void {
(this.outboundAssertions.get(handle) ?? []).forEach(e => e.drop());
this.outboundAssertions.delete(handle);
}
proxyMessage(assertion: Assertion): Value<Embedded<WireRef>> {
const pins: Array<WireSymbol> = [];
return mapEmbeddeds(assertion, r => this.rewriteRefOut(r, true, pins));
}
proxySync(targetRemoteOid: IO.Oid, peer: Ref): Embedded<WireRef> {
const peerEntity = new SyncPeerEntity(peer);
this.grabImportedOid(targetRemoteOid, peerEntity.pins);
return this.rewriteRefOut(Turn.ref(peerEntity), false, peerEntity.pins);
}
grabImportedOid(oid: IO.Oid, pins: Array<WireSymbol>): void {
const e = this.imported.grab("byOid", oid, false, null);
if (e === null) {
throw new Error("Internal error: import table missing entry for oid " + oid);
}
pins.push(e);
}
grabExportedOid(oid: IO.Oid, pins: Array<WireSymbol>): Ref {
const e = this.exported.grab("byOid", oid, false, null);
if (e === null) return INERT_REF;
pins.push(e);
return e.ref;
}
rewriteRefOut(r: Ref, transient: boolean, pins: Array<WireSymbol>): Embedded<WireRef> {
if (r.target instanceof ProxyEntity && r.target.relay === this) {
if (r.attenuation === void 0 || r.attenuation.length === 0) {
// No extra conditions on this reference since it was sent to us.
this.grabImportedOid(r.target.oid, pins);
return new Embedded<WireRef>(WireRef.yours({ oid: r.target.oid, attenuation: [] }));
} else {
// This reference has been attenuated since it was sent to us.
// Do we trust the peer to enforce such attenuation on our behalf?
if (this.trustPeer) {
this.grabImportedOid(r.target.oid, pins);
return new Embedded<WireRef>(WireRef.yours({ oid: r.target.oid, attenuation: r.attenuation }));
} else {
// fall through: treat the attenuated ref as a local ref, and re-export it.
}
}
}
const e = this.exported.grab(
"byRef", r, transient, () => {
if (transient) throw new Error("Cannot send transient reference");
return new WireSymbol(this.exported, this.nextLocalOid++, r);
});
pins.push(e);
return new Embedded<WireRef>(WireRef.mine(e.oid));
}
rewriteRefIn(nw: Embedded<WireRef>, pins: Array<WireSymbol>): Ref {
const n = nw.value;
switch (n._variant) {
case 'yours': {
const e = this.exported.grab("byOid", n.oid, false, null);
if (e === null) {
return INERT_REF;
} else {
pins.push(e);
const r = e.ref;
if (n.attenuation.length === 0) {
return r;
} else {
type AttenuatedRef = Ref & { __attenuations?: KeyedDictionary<Ref, Assertion, any> };
const ar = r as AttenuatedRef;
if (ar.__attenuations === void 0) {
ar.__attenuations = new KeyedDictionary();
}
return ar.__attenuations.getOrSet(n.attenuation.map(fromCaveat), () =>
attenuate(r, ... n.attenuation));
}
}
}
case 'mine': {
const e = this.imported.grab("byOid", n.oid, false, () =>
new WireSymbol(this.imported, n.oid, Turn.ref(new ProxyEntity(this, n.oid))));
pins.push(e);
return e.ref;
}
}
}
rewriteIn(a: Value<Embedded<WireRef>>): [Assertion, Array<WireSymbol>]
{
const pins: Array<WireSymbol> = [];
const rewritten = mapEmbeddeds(a, r => this.rewriteRefIn(r, pins));
return [rewritten, pins];
}
handle(localOid: IO.Oid, m: IO.Event<Embedded<WireRef>>): void {
switch (m._variant) {
case 'Assert': {
const [a, pins] = this.rewriteIn(m.value.assertion);
const r = this.grabExportedOid(localOid, pins);
this.inboundAssertions.set(m.value.handle, {
localHandle: Turn.active.assert(r, a),
pins,
});
break;
}
case 'Retract': {
const remoteHandle = m.value.handle;
const h = this.inboundAssertions.get(remoteHandle);
if (h === void 0) throw new Error(`Peer retracted invalid handle ${remoteHandle}`);
this.inboundAssertions.delete(remoteHandle);
h.pins.forEach(e => e.drop());
Turn.active.retract(h.localHandle);
break;
}
case 'Message': {
const [a, pins] = this.rewriteIn(m.value.body);
if (pins.length > 0) throw new Error("Cannot receive transient reference");
const r = this.exported.byOid.get(localOid)?.ref;
if (r) Turn.active.message(r, a);
break;
}
case 'Sync': {
const pins: Array<WireSymbol> = [];
const r = this.grabExportedOid(localOid, pins);
const k = this.rewriteRefIn(m.value.peer, pins);
Turn.active.sync(r).then(() => {
Turn.active.message(k, true);
pins.forEach(e => e.drop());
});
break;
}
}
}
proxyPacket(packet: IO.Packet<Embedded<WireRef>>): void {
switch (packet._variant) {
case 'Turn':
packet.value.forEach(v => this.handle(v.oid, v.event));
break;
case 'Error':
throw new Error(`Remote peer terminated relay: ${stringify(packet.value)}`);
case 'Extension':
// Ignore unknown extensions.
break;
}
}
}
export class ProxyEntity implements Entity {
readonly relay: ProxyOutbound;
readonly oid: IO.Oid;
constructor(relay: ProxyOutbound, oid: IO.Oid) {
this.relay = relay;
this.oid = oid;
}
send(m: IO.Event<Embedded<WireRef>>): void {
this.relay.send(this.oid, m);
}
assert(assertion: Assertion, handle: Handle): void {
this.send(IO.Event.Assert(IO.Assert({
assertion: this.relay.proxyAssertion(this.oid, assertion, handle),
handle
})))
}
retract(handle: Handle): void {
this.relay.proxyRetract(handle);
this.send(IO.Event.Retract(IO.Retract(handle)));
}
message(body: Assertion): void {
this.send(IO.Event.Message(IO.Message(this.relay.proxyMessage(body))));
}
sync(peer: Ref): void {
this.send(IO.Event.Sync(IO.Sync(this.relay.proxySync(this.oid, peer))));
}
}
export class SyncPeerEntity implements Entity {
readonly peer: Ref;
readonly handleMap = new IdentityMap<Handle, Handle>();
pins: Array<WireSymbol> = [];
constructor(peer: Ref) {
this.peer = peer;
}
assert(assertion: Assertion, handle: Handle): void {
this.handleMap.set(handle, Turn.active.assert(this.peer, assertion));
}
retract(handle: Handle): void {
Turn.active.retract(this.handleMap.get(handle)!);
this.handleMap.delete(handle);
}
message(body: Assertion): void {
// We get to vanish from the indexes now
this.pins.forEach(e => e.drop());
Turn.active.message(this.peer, body);
}
sync(peer: Ref): void {
Turn.active._sync(this.peer, peer);
}
}

View File

@ -1,23 +1,23 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import * as S from '../gen/sturdy.js';
import { Decoder, DecoderState, Encoder, EncoderState, GenericEmbedded, neverEmbeddedType, EmbeddedType, Value, EmbeddedWriter } from '@preserves/core';
import { Decoder, DecoderState, Encoder, EncoderState, neverEmbeddedType, EmbeddedType, Value, Embedded, EmbeddedWriter } from '@preserves/core';
export const wireRefEmbeddedType: EmbeddedType<S.WireRef> & EmbeddedWriter<S.WireRef> = {
decode(s: DecoderState): S.WireRef {
return S.asWireRef(new Decoder<any>(s).next());
export const wireRefEmbeddedType: EmbeddedType<Embedded<S.WireRef>> & EmbeddedWriter<Embedded<S.WireRef>> = {
decode(s: DecoderState): Embedded<S.WireRef> {
return new Embedded<S.WireRef>(S.asWireRef(new Decoder<any>(s).next()));
},
encode(s: EncoderState, v: S.WireRef): void {
new Encoder<any>(s, neverEmbeddedType).push(S.fromWireRef(v));
encode(s: EncoderState, v: Embedded<S.WireRef>): void {
new Encoder<any>(s, neverEmbeddedType).push(S.fromWireRef(v.value));
},
fromValue(v: Value<GenericEmbedded>): S.WireRef {
return S.asWireRef(v as Value<S._embedded>);
fromValue(v: Value): Embedded<S.WireRef> {
return new Embedded<S.WireRef>(S.asWireRef(v as Value<S._embedded>));
},
toValue(v: S.WireRef): Value<GenericEmbedded> {
return S.fromWireRef(v) as Value<GenericEmbedded>;
toValue(v: Embedded<S.WireRef>): Value {
return S.fromWireRef(v.value) as Value;
}
};

View File

@ -1,136 +1,15 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Actor, Assertion, Entity, Facet, Handle, Ref, Turn } from '../runtime/actor.js';
import { BytesLike, Decoder, Dictionary, embed, encode, IdentityMap, mapEmbeddeds, stringify, underlying, Value } from '@preserves/core';
import { Assertion, Facet, Ref, Turn } from '../runtime/actor.js';
import { BytesLike, Decoder, encode, Embedded, stringify, underlying } from '@preserves/core';
import * as IO from '../gen/protocol.js';
import { wireRefEmbeddedType } from './protocol.js';
import { attenuate } from '../runtime/rewrite.js';
import { fromCaveat, WireRef } from '../gen/sturdy.js';
import { WireRef } from '../gen/sturdy.js';
import { LayerBoundary } from './membrane.js';
const FLUSH = Symbol.for('flush');
export class WireSymbol {
count = 0;
constructor (
public side: Membrane,
public oid: IO.Oid,
public ref: Ref,
) {}
drop(): void {
this.count--;
if (this.count === 0) {
this.side.byOid.delete(this.oid);
this.side.byRef.delete(this.ref);
}
}
};
export class SyncPeerEntity implements Entity {
readonly relay: Relay;
readonly peer: Ref;
readonly handleMap = new IdentityMap<Handle, Handle>();
pins: Array<WireSymbol> = [];
constructor(relay: Relay, peer: Ref) {
this.relay = relay;
this.peer = peer;
}
assert(assertion: Assertion, handle: Handle): void {
this.handleMap.set(handle, Turn.active.assert(this.peer, assertion));
}
retract(handle: Handle): void {
Turn.active.retract(this.handleMap.get(handle)!);
this.handleMap.delete(handle);
}
message(body: Assertion): void {
// We get to vanish from the indexes now
this.pins.forEach(e => e.drop());
Turn.active.message(this.peer, body);
}
sync(peer: Ref): void {
Turn.active._sync(this.peer, peer);
}
}
export class RelayEntity implements Entity {
readonly relay: Relay;
readonly oid: IO.Oid;
constructor(relay: Relay, oid: IO.Oid) {
this.relay = relay;
this.oid = oid;
}
send(m: IO.Event<WireRef>): void {
this.relay.send(this.oid, m);
}
assert(assertion: Assertion, handle: Handle): void {
this.send(IO.Event.Assert(IO.Assert({
assertion: this.relay.register(this.oid, assertion, handle),
handle
})))
}
retract(handle: Handle): void {
this.relay.deregister(handle);
this.send(IO.Event.Retract(IO.Retract(handle)));
}
message(body: Assertion): void {
this.send(IO.Event.Message(IO.Message(this.relay.register(null, body, null))));
}
sync(peer: Ref): void {
const peerEntity = new SyncPeerEntity(this.relay, peer);
this.relay.grabImportedOid(this.oid, peerEntity.pins);
const ior = this.relay.rewriteRefOut(Turn.ref(peerEntity), false, peerEntity.pins);
this.send(IO.Event.Sync(IO.Sync(ior)));
}
}
export type WhichTable = "byOid" | "byRef";
export class Membrane {
readonly byOid = new IdentityMap<IO.Oid, WireSymbol>();
readonly byRef = new IdentityMap<Ref, WireSymbol>();
grab<Table extends WhichTable>(table: Table,
key: Parameters<Membrane[Table]['get']>[0],
transient: boolean,
f: () => WireSymbol): WireSymbol;
grab<Table extends WhichTable>(table: Table,
key: Parameters<Membrane[Table]['get']>[0],
transient: boolean,
f: null): WireSymbol | null;
grab<Table extends WhichTable>(table: Table,
key: Parameters<Membrane[Table]['get']>[0],
transient: boolean,
f: (() => WireSymbol) | null): WireSymbol | null {
let e = this[table].get(key as any);
if (e === void 0) {
if (f === null) return null;
e = f();
this.byRef.set(e.ref, e);
this.byOid.set(e.oid, e);
}
if (!transient) e.count++;
return e;
}
}
export const INERT_REF: Ref = {
relay: Actor.boot(() => Turn.active.stop()).root,
target: {},
};
export type PacketWriter = (bs: Uint8Array) => void;
export interface RelayOptions {
@ -143,22 +22,13 @@ export interface RelayOptions {
nextLocalOid?: IO.Oid;
}
export class Relay {
export class Relay extends LayerBoundary {
readonly facet: Facet;
readonly selfRef: Ref;
readonly w: PacketWriter;
readonly inboundAssertions = new IdentityMap<Handle, {
localHandle: Handle,
pins: Array<WireSymbol>,
}>();
readonly outboundAssertions = new IdentityMap<Handle, Array<WireSymbol>>();
readonly exported = new Membrane();
readonly imported = new Membrane();
readonly peer: Ref | null;
nextLocalOid: IO.Oid = 0;
pendingTurn: IO.Turn<WireRef> = [];
pendingTurn: IO.Turn<Embedded<WireRef>> = [];
debug: boolean;
trustPeer: boolean;
readonly decoder = new Decoder(void 0, {
includeAnnotations: false,
@ -166,11 +36,12 @@ export class Relay {
});
constructor(options: RelayOptions) {
super(options.trustPeer, options.nextLocalOid);
this.facet = Turn.activeFacet;
this.selfRef = Turn.ref(this);
this.w = options.packetWriter;
this.debug = options.debug ?? false;
this.trustPeer = options.trustPeer ?? true;
this.facet.preventInertCheck();
options.setup(this);
@ -180,105 +51,8 @@ export class Relay {
}
this.peer = (options.initialOid !== void 0)
? this.rewriteRefIn(WireRef.mine(options.initialOid), [])
? this.rewriteRefIn(new Embedded<WireRef>(WireRef.mine(options.initialOid)), [])
: null;
if (options.nextLocalOid !== void 0) {
this.nextLocalOid = (options.nextLocalOid === 0) ? 1 : options.nextLocalOid;
}
}
register(targetRemoteOid: IO.Oid, assertion: Assertion, handle: Handle): Value<WireRef>;
register(targetRemoteOid: null, assertion: Assertion, handle: null): Value<WireRef>;
register(targetRemoteOid: IO.Oid | null, assertion: Assertion, handle: Handle | null): Value<WireRef> {
const transient = (handle === null);
const pins: Array<WireSymbol> = [];
const rewritten = mapEmbeddeds(assertion, r => embed(this.rewriteRefOut(r, transient, pins)));
if (handle !== null) {
if (targetRemoteOid !== null /* belt and suspenders */) {
this.grabImportedOid(targetRemoteOid, pins);
}
this.outboundAssertions.set(handle, pins);
}
return rewritten;
}
deregister(handle: Handle): void {
(this.outboundAssertions.get(handle) ?? []).forEach(e => e.drop());
this.outboundAssertions.delete(handle);
}
grabImportedOid(oid: IO.Oid, pins: Array<WireSymbol>) {
const e = this.imported.grab("byOid", oid, false, null);
if (e === null) {
throw new Error("Internal error: import table missing entry for oid " + oid);
}
pins.push(e);
}
grabExportedOid(oid: IO.Oid, pins: Array<WireSymbol>): Ref {
const e = this.exported.grab("byOid", oid, false, null);
if (e === null) return INERT_REF;
pins.push(e);
return e.ref;
}
rewriteRefOut(r: Ref, transient: boolean, pins: Array<WireSymbol>): WireRef {
if (r.target instanceof RelayEntity && r.target.relay === this) {
if (r.attenuation === void 0 || r.attenuation.length === 0) {
// No extra conditions on this reference since it was sent to us.
this.grabImportedOid(r.target.oid, pins);
return WireRef.yours({ oid: r.target.oid, attenuation: [] });
} else {
// This reference has been attenuated since it was sent to us.
// Do we trust the peer to enforce such attenuation on our behalf?
if (this.trustPeer) {
this.grabImportedOid(r.target.oid, pins);
return WireRef.yours({ oid: r.target.oid, attenuation: r.attenuation });
} else {
// fall through: treat the attenuated ref as a local ref, and re-export it.
}
}
}
const e = this.exported.grab(
"byRef", r, transient, () => {
if (transient) throw new Error("Cannot send transient reference");
return new WireSymbol(this.exported, this.nextLocalOid++, r);
});
pins.push(e);
return WireRef.mine(e.oid);
}
rewriteRefIn(n: WireRef, pins: Array<WireSymbol>): Ref {
switch (n._variant) {
case 'yours': {
const e = this.exported.grab("byOid", n.oid, false, null);
if (e === null) {
return INERT_REF;
} else {
pins.push(e);
const r = e.ref;
if (n.attenuation.length === 0) {
return r;
} else {
type AttenuatedRef = Ref & { __attenuations?: Dictionary<any, Ref> };
const ar = r as AttenuatedRef;
if (ar.__attenuations === void 0) {
ar.__attenuations = new Dictionary();
}
return ar.__attenuations.getOrSet(n.attenuation.map(fromCaveat), () =>
attenuate(r, ... n.attenuation));
}
}
}
case 'mine': {
const e = this.imported.grab("byOid", n.oid, false, () =>
new WireSymbol(this.imported, n.oid, Turn.ref(new RelayEntity(this, n.oid))));
pins.push(e);
return e.ref;
}
}
}
message(body: Assertion) {
@ -292,7 +66,7 @@ export class Relay {
}
}
send(remoteOid: IO.Oid, m: IO.Event<WireRef>): void {
send(remoteOid: IO.Oid, m: IO.Event<Embedded<WireRef>>): void {
if (this.pendingTurn.length === 0) {
Turn.active.message(this.selfRef, FLUSH);
}
@ -300,63 +74,16 @@ export class Relay {
}
accept(bs: BytesLike): void {
Turn.for(this.facet, () => {
this.facet.turn(() => {
this.decoder.write(bs);
while (true) {
const rawTurn = this.decoder.try_next();
if (rawTurn === void 0) break;
const wireTurn = IO.toTurn(rawTurn);
if (wireTurn === void 0) throw new Error("Bad IO.Turn");
if (this.debug) console.log('IN', stringify(rawTurn));
wireTurn.forEach(v => this.handle(v.oid, v.event));
const rawPacket = this.decoder.try_next();
if (rawPacket === void 0) break;
const wirePacket = IO.toPacket(rawPacket);
if (wirePacket === void 0) throw new Error("Bad IO.Packet");
if (this.debug) console.log('IN', stringify(rawPacket));
this.proxyPacket(wirePacket);
}
});
}
rewriteIn(a: Value<WireRef>): [Assertion, Array<WireSymbol>]
{
const pins: Array<WireSymbol> = [];
const rewritten = mapEmbeddeds(a, r => embed(this.rewriteRefIn(r, pins)));
return [rewritten, pins];
}
handle(localOid: IO.Oid, m: IO.Event<WireRef>) {
switch (m._variant) {
case 'Assert': {
const [a, pins] = this.rewriteIn(m.value.assertion);
const r = this.grabExportedOid(localOid, pins);
this.inboundAssertions.set(m.value.handle, {
localHandle: Turn.active.assert(r, a),
pins,
});
break;
}
case 'Retract': {
const remoteHandle = m.value.handle;
const h = this.inboundAssertions.get(remoteHandle);
if (h === void 0) throw new Error(`Peer retracted invalid handle ${remoteHandle}`);
this.inboundAssertions.delete(remoteHandle);
h.pins.forEach(e => e.drop());
Turn.active.retract(h.localHandle);
break;
}
case 'Message': {
const [a, pins] = this.rewriteIn(m.value.body);
if (pins.length > 0) throw new Error("Cannot receive transient reference");
const r = this.exported.byOid.get(localOid)?.ref;
if (r) Turn.active.message(r, a);
break;
}
case 'Sync': {
const pins: Array<WireSymbol> = [];
const r = this.grabExportedOid(localOid, pins);
const k = this.rewriteRefIn(m.value.peer, pins);
Turn.active.sync(r).then(() => {
Turn.active.message(k, true);
pins.forEach(e => e.drop());
});
break;
}
}
}
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
// Basically Macaroons [1] in a Dataspace context
//
@ -10,8 +10,9 @@
// California: Internet Society, 2014.
import { mac } from './cryptography.js';
import { Bytes, decode, encode, is, neverEmbeddedType, Value } from '@preserves/core';
import { Bytes, decode, encode, is, neverEmbeddedType, Value, fromJS } from '@preserves/core';
import * as S from '../gen/sturdy.js';
import * as G from '../gen/gatekeeper.js';
export * from '../gen/sturdy.js';
export type SturdyValue = Value<S._embedded>;
@ -37,16 +38,42 @@ export function sturdyDecode(bs: Bytes): SturdyValue {
});
}
export async function mint(oid: SturdyValue, secretKey: Bytes): Promise<S.SturdyRef> {
return S.SturdyRef(S.Parameters({
oid,
sig: await mac(secretKey, sturdyEncode(oid)),
caveats: S.CaveatsField.absent(),
}));
export function sturdyBind(
oid: SturdyValue,
secretKey: Bytes,
target: S._embedded,
observer?: S._embedded,
): G.Bind {
return G.Bind({
description: G.Description({
stepType: fromJS(S.SturdyStepType()) as symbol,
detail: fromJS(S.SturdyDescriptionDetail({ oid, key: secretKey })),
}),
target,
observer: (observer === void 0) ? G.BindObserver.absent() : G.BindObserver.present(observer),
});
}
async function chainMac(key: Bytes | Promise<Bytes>, caveats: S.Caveat[]): Promise<Bytes> {
return caveats.reduce(async (key, c) => mac(await key, sturdyEncode(S.fromCaveat(c))), key);
type RefAndBind = { ref: S.SturdyRef, bind: G.Bind };
export function mint(oid: SturdyValue, secretKey: Bytes): S.SturdyRef;
export function mint(oid: SturdyValue, secretKey: Bytes, target: S._embedded, observer?: S._embedded): RefAndBind;
export function mint(
oid: SturdyValue,
secretKey: Bytes,
target?: S._embedded,
observer?: S._embedded,
): S.SturdyRef | RefAndBind {
const ref = S.SturdyRef(S.Parameters({
oid,
sig: mac(secretKey, sturdyEncode(oid)),
caveats: S.CaveatsField.absent(),
}));
if (target === void 0) return ref;
return { ref, bind: sturdyBind(oid, secretKey, target, observer) };
}
function chainMac(key: Bytes, caveats: S.Caveat[]): Bytes {
return caveats.reduce((key, c) => mac(key, sturdyEncode(S.fromCaveat(c))), key);
}
export function caveatChain(r: S.SturdyRef): S.Caveat[] {
@ -57,16 +84,16 @@ export function caveatChain(r: S.SturdyRef): S.Caveat[] {
}
}
export async function attenuate(r: S.SturdyRef, ... a: S.Caveat[]): Promise<S.SturdyRef> {
export function attenuate(r: S.SturdyRef, ... a: S.Caveat[]): S.SturdyRef {
if (a.length === 0) return r;
return S.SturdyRef(S.Parameters({
oid: r.parameters.oid,
caveats: S.CaveatsField.present([... caveatChain(r), ... a]),
sig: await chainMac(r.parameters.sig, a),
sig: chainMac(r.parameters.sig, a),
}));
}
export async function validate(r: S.SturdyRef, secretKey: Bytes): Promise<boolean> {
const sig = await chainMac(await mac(secretKey, sturdyEncode(r.parameters.oid)), caveatChain(r));
export function validate(r: S.SturdyRef, secretKey: Bytes): boolean {
const sig = chainMac(mac(secretKey, sturdyEncode(r.parameters.oid)), caveatChain(r));
return is(sig, r.parameters.sig);
}

View File

@ -1,4 +1,4 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
export const randomBytes = void 0;

View File

@ -1,12 +1,12 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { KeyedSet } from '@preserves/core';
import { GenericEmbedded, KeyedSet } from '@preserves/core';
import { Bag, ChangeDescription } from '../src/runtime/bag';
describe('bag', () => {
it('should be initializable from a set', () => {
const b = new Bag(new KeyedSet<string>(['a', 'b', 'c']));
const b = new Bag(new KeyedSet<GenericEmbedded, string>(['a', 'b', 'c']));
expect(b.size).toBe(3);
expect(b.get('a')).toBe(1);
expect(b.get('z')).toBe(0);
@ -28,7 +28,7 @@ describe('bag', () => {
});
it('should count down', () => {
const b = new Bag(new KeyedSet<string>(['a']));
const b = new Bag(new KeyedSet<GenericEmbedded, string>(['a']));
expect(b.change('a', 1)).toBe(ChangeDescription.PRESENT_TO_PRESENT);
expect(b.change('a', -1)).toBe(ChangeDescription.PRESENT_TO_PRESENT);
expect(b.size).toBe(1);

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Canonicalizer, embeddedId, FlexSet } from '@preserves/core';
import { Cell, Field, Graph } from '../src/runtime/dataflow';

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { is, preserves } from '@preserves/core';

View File

@ -1,6 +1,6 @@
{
"name": "@syndicate-lang/create",
"version": "0.19.0",
"version": "0.25.0",
"description": "Create a new Syndicate/js package",
"author": "Tony Garnock-Jones <tonyg@leastfixedpoint.com>",
"homepage": "https://github.com/syndicate-lang/syndicate-js/tree/main/packages/create",

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import yargs from 'yargs/yargs';

View File

@ -1,22 +0,0 @@
((typescript-mode
. ((eval
. (progn
;; For TIDE:
(setq tide-tsserver-executable
(concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/typescript/lib/tsserver.js"))
;; For LSP:
(require 'lsp-javascript)
(let ((node-modules (concat
(let ((d (dir-locals-find-file ".")))
(if (stringp d) d (car d)))
"node_modules/")))
(lsp-dependency 'typescript-language-server
`(:system ,(concat node-modules
"typescript-language-server/lib/cli.mjs")))
(lsp-dependency 'typescript
`(:system ,(concat node-modules
"typescript/lib/tsserver.js")))))
))))

View File

@ -6,7 +6,7 @@
<link href="style.css" rel="stylesheet">
<script src="node_modules/@preserves/core/dist/preserves.js"></script>
<script src="node_modules/@syndicate-lang/core/dist/syndicate.js"></script>
<script src="node_modules/@syndicate-lang/html/dist/syndicate-html.js"></script>
<script src="node_modules/@syndicate-lang/html2/dist/syndicate-html2.js"></script>
<script src="node_modules/@syndicate-lang/ws-relay/dist/syndicate-ws-relay.js"></script>
<script src="index.js"></script>
</head>

View File

@ -3,7 +3,7 @@
"version": "0.0.0",
"license": "GPL-3.0+",
"devDependencies": {
"@preserves/schema-cli": "0.992.5",
"@preserves/schema-cli": "0.995.201",
"@syndicate-lang/ts-plugin": "*",
"@syndicate-lang/tsc": "*",
"rollup": "^2.60",
@ -12,9 +12,9 @@
"typescript-language-server": "^3.0"
},
"dependencies": {
"@preserves/core": "0.992.4",
"@preserves/core": "0.995.200",
"@syndicate-lang/core": "*",
"@syndicate-lang/html": "*",
"@syndicate-lang/html2": "*",
"@syndicate-lang/ws-relay": "*"
},
"scripts": {
@ -26,6 +26,6 @@
"rollup": "rollup -c",
"rollup:watch": "rollup -c -w",
"clean": "rm -rf lib/ src.ts/ src/gen/ index.js index.js.map",
"serve": "python -m http.server"
"serve": "syndicate-server -c syndicate-server.config.pr"
}
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import sourcemaps from 'rollup-plugin-sourcemaps';
@ -9,7 +9,7 @@ export default {
external: [
'@preserves/core',
'@syndicate-lang/core',
'@syndicate-lang/html',
'@syndicate-lang/html2',
'@syndicate-lang/ws-relay',
],
output: {
@ -20,7 +20,7 @@ export default {
globals: {
'@preserves/core': 'Preserves',
'@syndicate-lang/core': 'Syndicate',
'@syndicate-lang/html': 'SyndicateHtml',
'@syndicate-lang/html2': 'SyndicateHtml2',
'@syndicate-lang/ws-relay': 'SyndicateWsRelay',
},
},

View File

@ -1,15 +1,15 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Dataspace, Ref, Sturdy, Reader, Schemas, Embedded, randomId, fromJS } from "@syndicate-lang/core";
import html from "@syndicate-lang/html";
import { boot as bootHtml, Widget } from "@syndicate-lang/html2";
import wsRelay from "@syndicate-lang/ws-relay";
import { ExampleDefinition } from './gen/example';
import G = Schemas.gatekeeper;
export function main() {
Dataspace.boot(ds => {
html.boot(ds);
bootHtml(ds);
wsRelay.boot(ds, true /* remove this `true` to turn off client/server debug logging */);
bootApp(ds);
});
@ -19,7 +19,7 @@ function bootApp(ds: Ref) {
spawn named 'app' {
at ds {
/*
* This example expects a syndicate-server instance running on port 9001 on the
* This example expects a syndicate-server instance running on port 8000 on the
* server hosting index.html, exposing a dataspace entity via a capability called
* `"syndicate"` with empty "secret". See syndicate-server.config.pr.
*/
@ -28,7 +28,7 @@ function bootApp(ds: Ref) {
const route = G.Route<Ref>({
"transports": [fromJS(Schemas.transportAddress.WebSocket(
`ws://${document.location.hostname}:9001/`))],
`ws://${document.location.hostname}:8000/`))],
"pathSteps": [G.asPathStep(fromJS(Sturdy.asSturdyRef(
new Reader<Ref>(
'<ref {oid: "syndicate" sig: #[acowDB2/oI+6aSEC3YIxGg==]}>').next())))],
@ -42,13 +42,9 @@ function bootApp(ds: Ref) {
at remoteDs {
assert ExampleDefinition(this_instance);
during ExampleDefinition($who: string) => {
const ui = new html.Anchor();
at ds {
assert ui.html(
'#main',
html.template`<p>We see <span class="example-definition">${who}</span></p>`,
who);
}
new Widget(t =>
t`<p>We see <span class="example-definition">${who}</span></p>`)
.setParent('#main');
}
}
}

View File

@ -1,12 +1,18 @@
; Start the server with
;
; syndicate-server -c ./syndicate-server.config.pr
;---------------------------------------------------------------------------
# Start the server with
#
# syndicate-server -c ./syndicate-server.config.pr
# ---------------------------------------------------------------------------
; Expose the gatekeeper on port 9001:
<require-service <relay-listener <tcp "0.0.0.0" 9001> $gatekeeper>>
# Expose the gatekeeper and HTTP on port 8000:
<require-service <relay-listener <tcp "0.0.0.0" 8000> $gatekeeper $config>>
<require-service <http-router $config>>
; Create a dataspace entity, and register it with the gatekeeper with name `"syndicate"` and an
; empty secret key:
<require-service <http-static-files "." 0>>
? <service-object <http-static-files "." 0> ?handler> [
$config += <http-bind #f 8000 get [...] $handler>
]
# Create a dataspace entity, and register it with the gatekeeper with name `"syndicate"` and an
# empty secret key:
let ?ds = dataspace
<bind <ref {oid: "syndicate" key: #x""}> $ds #f>

View File

@ -1,6 +1,6 @@
#!/usr/bin/env -S node -r esm
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
try {
require('../lib/index.js').main(process.argv.slice(2));

View File

@ -1,6 +1,6 @@
{
"name": "@syndicate-lang/fs",
"version": "0.24.0",
"version": "0.33.0",
"description": "Reflect contents of a portion of the file system as assertions",
"homepage": "https://github.com/syndicate-lang/syndicate-js/tree/main/packages/fs",
"license": "GPL-3.0+",
@ -27,16 +27,16 @@
"syndicate-fs": "./bin/syndicate-fs.js"
},
"peerDependencies": {
"@preserves/core": "0.992.4"
"@preserves/core": "0.995.200"
},
"dependencies": {
"@syndicate-lang/core": "^0.23.0",
"@syndicate-lang/service": "^0.24.0",
"@syndicate-lang/core": "^0.32.0",
"@syndicate-lang/service": "^0.33.0",
"chokidar": "^3.5.3"
},
"devDependencies": {
"@preserves/schema-cli": "0.992.5",
"@syndicate-lang/ts-plugin": "^0.24.0",
"@syndicate-lang/tsc": "^0.24.0"
"@preserves/schema-cli": "0.995.201",
"@syndicate-lang/ts-plugin": "^0.34.0",
"@syndicate-lang/tsc": "^0.34.0"
}
}

View File

@ -2,7 +2,7 @@ version 1 .
Config = @core CoreConfig & @awaitWriteFinish AwaitWriteFinishConfig .
CoreConfig = {
dataspace: #!any,
dataspace: #:any,
label: any,
path: string,
} .

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2023-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { Bytes, Observe, Ref, Turn, stringify } from "@syndicate-lang/core";
import { QuasiValue as Q } from "@syndicate-lang/core";

View File

@ -1,6 +1,6 @@
{
"name": "@syndicate-lang/html",
"version": "0.24.0",
"version": "0.33.0",
"description": "DOM/HTML UI for Syndicate/JS",
"homepage": "https://github.com/syndicate-lang/syndicate-js/tree/main/packages/html",
"license": "GPL-3.0+",
@ -25,10 +25,10 @@
"veryclean": "yarn run clean && rm -rf node_modules"
},
"dependencies": {
"@syndicate-lang/core": "^0.23.0"
"@syndicate-lang/core": "^0.32.0"
},
"devDependencies": {
"@syndicate-lang/ts-plugin": "^0.24.0",
"@syndicate-lang/tsc": "^0.24.0"
"@syndicate-lang/ts-plugin": "^0.34.0",
"@syndicate-lang/tsc": "^0.34.0"
}
}

View File

@ -1,5 +1,5 @@
/// SPDX-License-Identifier: GPL-3.0-or-later
/// SPDX-FileCopyrightText: Copyright © 2016-2023 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
/// SPDX-FileCopyrightText: Copyright © 2016-2024 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
import { SyndicateRollup } from '../../rollup.js';
const r = new SyndicateRollup('syndicate-html', { globalName: 'SyndicateHtml' });

Some files were not shown because too many files have changed in this diff Show More