greatly simplify and improve type inferencing - suggestions broken
This commit is contained in:
parent
c3f7cea310
commit
c5c5def598
12 changed files with 1022 additions and 694 deletions
|
|
@ -18,9 +18,9 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.27.0",
|
"@eslint/js": "^9.27.0",
|
||||||
"@types/react": "^19.1.4",
|
"@types/react": "^19.1.5",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"@vitejs/plugin-react-swc": "^3.9.0",
|
"@vitejs/plugin-react-swc": "^3.10.0",
|
||||||
"eslint": "^9.27.0",
|
"eslint": "^9.27.0",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
|
|
|
||||||
128
pnpm-lock.yaml
generated
128
pnpm-lock.yaml
generated
|
|
@ -16,7 +16,7 @@ importers:
|
||||||
version: 5.2.5
|
version: 5.2.5
|
||||||
dope2:
|
dope2:
|
||||||
specifier: git+https://deemz.org/git/joeri/dope2.git
|
specifier: git+https://deemz.org/git/joeri/dope2.git
|
||||||
version: git+https://deemz.org/git/joeri/dope2.git#8cfbd6116ffe778efb02c37133a1ff633ae171df
|
version: git+https://deemz.org/git/joeri/dope2.git#0d3ccee7d5ce703e71fd3c05e1795c7968646a34
|
||||||
react:
|
react:
|
||||||
specifier: ^19.1.0
|
specifier: ^19.1.0
|
||||||
version: 19.1.0
|
version: 19.1.0
|
||||||
|
|
@ -28,14 +28,14 @@ importers:
|
||||||
specifier: ^9.27.0
|
specifier: ^9.27.0
|
||||||
version: 9.27.0
|
version: 9.27.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^19.1.4
|
specifier: ^19.1.5
|
||||||
version: 19.1.4
|
version: 19.1.5
|
||||||
'@types/react-dom':
|
'@types/react-dom':
|
||||||
specifier: ^19.1.5
|
specifier: ^19.1.5
|
||||||
version: 19.1.5(@types/react@19.1.4)
|
version: 19.1.5(@types/react@19.1.5)
|
||||||
'@vitejs/plugin-react-swc':
|
'@vitejs/plugin-react-swc':
|
||||||
specifier: ^3.9.0
|
specifier: ^3.10.0
|
||||||
version: 3.9.0(vite@6.3.5)
|
version: 3.10.0(vite@6.3.5)
|
||||||
eslint:
|
eslint:
|
||||||
specifier: ^9.27.0
|
specifier: ^9.27.0
|
||||||
version: 9.27.0
|
version: 9.27.0
|
||||||
|
|
@ -286,6 +286,9 @@ packages:
|
||||||
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
'@rolldown/pluginutils@1.0.0-beta.9':
|
||||||
|
resolution: {integrity: sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==}
|
||||||
|
|
||||||
'@rollup/rollup-android-arm-eabi@4.41.0':
|
'@rollup/rollup-android-arm-eabi@4.41.0':
|
||||||
resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==}
|
resolution: {integrity: sha512-KxN+zCjOYHGwCl4UCtSfZ6jrq/qi88JDUtiEFk8LELEHq2Egfc/FgW+jItZiOLRuQfb/3xJSgFuNPC9jzggX+A==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
|
|
@ -386,68 +389,68 @@ packages:
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@swc/core-darwin-arm64@1.11.24':
|
'@swc/core-darwin-arm64@1.11.29':
|
||||||
resolution: {integrity: sha512-dhtVj0PC1APOF4fl5qT2neGjRLgHAAYfiVP8poJelhzhB/318bO+QCFWAiimcDoyMgpCXOhTp757gnoJJrheWA==}
|
resolution: {integrity: sha512-whsCX7URzbuS5aET58c75Dloby3Gtj/ITk2vc4WW6pSDQKSPDuONsIcZ7B2ng8oz0K6ttbi4p3H/PNPQLJ4maQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@swc/core-darwin-x64@1.11.24':
|
'@swc/core-darwin-x64@1.11.29':
|
||||||
resolution: {integrity: sha512-H/3cPs8uxcj2Fe3SoLlofN5JG6Ny5bl8DuZ6Yc2wr7gQFBmyBkbZEz+sPVgsID7IXuz7vTP95kMm1VL74SO5AQ==}
|
resolution: {integrity: sha512-S3eTo/KYFk+76cWJRgX30hylN5XkSmjYtCBnM4jPLYn7L6zWYEPajsFLmruQEiTEDUg0gBEWLMNyUeghtswouw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
'@swc/core-linux-arm-gnueabihf@1.11.24':
|
'@swc/core-linux-arm-gnueabihf@1.11.29':
|
||||||
resolution: {integrity: sha512-PHJgWEpCsLo/NGj+A2lXZ2mgGjsr96ULNW3+T3Bj2KTc8XtMUkE8tmY2Da20ItZOvPNC/69KroU7edyo1Flfbw==}
|
resolution: {integrity: sha512-o9gdshbzkUMG6azldHdmKklcfrcMx+a23d/2qHQHPDLUPAN+Trd+sDQUYArK5Fcm7TlpG4sczz95ghN0DMkM7g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@swc/core-linux-arm64-gnu@1.11.24':
|
'@swc/core-linux-arm64-gnu@1.11.29':
|
||||||
resolution: {integrity: sha512-C2FJb08+n5SD4CYWCTZx1uR88BN41ZieoHvI8A55hfVf2woT8+6ZiBzt74qW2g+ntZ535Jts5VwXAKdu41HpBg==}
|
resolution: {integrity: sha512-sLoaciOgUKQF1KX9T6hPGzvhOQaJn+3DHy4LOHeXhQqvBgr+7QcZ+hl4uixPKTzxk6hy6Hb0QOvQEdBAAR1gXw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@swc/core-linux-arm64-musl@1.11.24':
|
'@swc/core-linux-arm64-musl@1.11.29':
|
||||||
resolution: {integrity: sha512-ypXLIdszRo0re7PNNaXN0+2lD454G8l9LPK/rbfRXnhLWDBPURxzKlLlU/YGd2zP98wPcVooMmegRSNOKfvErw==}
|
resolution: {integrity: sha512-PwjB10BC0N+Ce7RU/L23eYch6lXFHz7r3NFavIcwDNa/AAqywfxyxh13OeRy+P0cg7NDpWEETWspXeI4Ek8otw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@swc/core-linux-x64-gnu@1.11.24':
|
'@swc/core-linux-x64-gnu@1.11.29':
|
||||||
resolution: {integrity: sha512-IM7d+STVZD48zxcgo69L0yYptfhaaE9cMZ+9OoMxirNafhKKXwoZuufol1+alEFKc+Wbwp+aUPe/DeWC/Lh3dg==}
|
resolution: {integrity: sha512-i62vBVoPaVe9A3mc6gJG07n0/e7FVeAvdD9uzZTtGLiuIfVfIBta8EMquzvf+POLycSk79Z6lRhGPZPJPYiQaA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@swc/core-linux-x64-musl@1.11.24':
|
'@swc/core-linux-x64-musl@1.11.29':
|
||||||
resolution: {integrity: sha512-DZByJaMVzSfjQKKQn3cqSeqwy6lpMaQDQQ4HPlch9FWtDx/dLcpdIhxssqZXcR2rhaQVIaRQsCqwV6orSDGAGw==}
|
resolution: {integrity: sha512-YER0XU1xqFdK0hKkfSVX1YIyCvMDI7K07GIpefPvcfyNGs38AXKhb2byySDjbVxkdl4dycaxxhRyhQ2gKSlsFQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
|
||||||
'@swc/core-win32-arm64-msvc@1.11.24':
|
'@swc/core-win32-arm64-msvc@1.11.29':
|
||||||
resolution: {integrity: sha512-Q64Ytn23y9aVDKN5iryFi8mRgyHw3/kyjTjT4qFCa8AEb5sGUuSj//AUZ6c0J7hQKMHlg9do5Etvoe61V98/JQ==}
|
resolution: {integrity: sha512-po+WHw+k9g6FAg5IJ+sMwtA/fIUL3zPQ4m/uJgONBATCVnDDkyW6dBA49uHNVtSEvjvhuD8DVWdFP847YTcITw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@swc/core-win32-ia32-msvc@1.11.24':
|
'@swc/core-win32-ia32-msvc@1.11.29':
|
||||||
resolution: {integrity: sha512-9pKLIisE/Hh2vJhGIPvSoTK4uBSPxNVyXHmOrtdDot4E1FUUI74Vi8tFdlwNbaj8/vusVnb8xPXsxF1uB0VgiQ==}
|
resolution: {integrity: sha512-h+NjOrbqdRBYr5ItmStmQt6x3tnhqgwbj9YxdGPepbTDamFv7vFnhZR0YfB3jz3UKJ8H3uGJ65Zw1VsC+xpFkg==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@swc/core-win32-x64-msvc@1.11.24':
|
'@swc/core-win32-x64-msvc@1.11.29':
|
||||||
resolution: {integrity: sha512-sybnXtOsdB+XvzVFlBVGgRHLqp3yRpHK7CrmpuDKszhj/QhmsaZzY/GHSeALlMtLup13M0gqbcQvsTNlAHTg3w==}
|
resolution: {integrity: sha512-Q8cs2BDV9wqDvqobkXOYdC+pLUSEpX/KvI0Dgfun1F+LzuLotRFuDhrvkU9ETJA6OnD2+Fn/ieHgloiKA/Mn/g==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
'@swc/core@1.11.24':
|
'@swc/core@1.11.29':
|
||||||
resolution: {integrity: sha512-MaQEIpfcEMzx3VWWopbofKJvaraqmL6HbLlw2bFZ7qYqYw3rkhM0cQVEgyzbHtTWwCwPMFZSC2DUbhlZgrMfLg==}
|
resolution: {integrity: sha512-g4mThMIpWbNhV8G2rWp5a5/Igv8/2UFRJx2yImrLGMgrDDYZIopqZ/z0jZxDgqNA1QDx93rpwNF7jGsxVWcMlA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@swc/helpers': '>=0.5.17'
|
'@swc/helpers': '>=0.5.17'
|
||||||
|
|
@ -472,8 +475,8 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^19.0.0
|
'@types/react': ^19.0.0
|
||||||
|
|
||||||
'@types/react@19.1.4':
|
'@types/react@19.1.5':
|
||||||
resolution: {integrity: sha512-EB1yiiYdvySuIITtD5lhW4yPyJ31RkJkkDw794LaQYrxCSaQV/47y5o1FMC4zF9ZyjUjzJMZwbovEnT5yHTW6g==}
|
resolution: {integrity: sha512-piErsCVVbpMMT2r7wbawdZsq4xMvIAhQuac2gedQHysu1TZYEigE6pnFfgZT+/jQnrRuF5r+SHzuehFjfRjr4g==}
|
||||||
|
|
||||||
'@typescript-eslint/eslint-plugin@8.32.1':
|
'@typescript-eslint/eslint-plugin@8.32.1':
|
||||||
resolution: {integrity: sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==}
|
resolution: {integrity: sha512-6u6Plg9nP/J1GRpe/vcjjabo6Uc5YQPAMxsgQyGC/I0RuukiG1wIe3+Vtg3IrSCVJDmqK3j8adrtzXSENRtFgg==}
|
||||||
|
|
@ -522,8 +525,8 @@ packages:
|
||||||
resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==}
|
resolution: {integrity: sha512-ar0tjQfObzhSaW3C3QNmTc5ofj0hDoNQ5XWrCy6zDyabdr0TWhCkClp+rywGNj/odAFBVzzJrK4tEq5M4Hmu4w==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@vitejs/plugin-react-swc@3.9.0':
|
'@vitejs/plugin-react-swc@3.10.0':
|
||||||
resolution: {integrity: sha512-jYFUSXhwMCYsh/aQTgSGLIN3Foz5wMbH9ahb0Zva//UzwZYbMiZd7oT3AU9jHT9DLswYDswsRwPU9jVF3yA48Q==}
|
resolution: {integrity: sha512-ZmkdHw3wo/o/Rk05YsXZs/DJAfY2CdQ5DUAjoWji+PEr+hYADdGMCGgEAILbiKj+CjspBTuTACBcWDrmC8AUfw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^4 || ^5 || ^6
|
vite: ^4 || ^5 || ^6
|
||||||
|
|
||||||
|
|
@ -597,8 +600,8 @@ packages:
|
||||||
deep-is@0.1.4:
|
deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
|
|
||||||
dope2@git+https://deemz.org/git/joeri/dope2.git#8cfbd6116ffe778efb02c37133a1ff633ae171df:
|
dope2@git+https://deemz.org/git/joeri/dope2.git#0d3ccee7d5ce703e71fd3c05e1795c7968646a34:
|
||||||
resolution: {commit: 8cfbd6116ffe778efb02c37133a1ff633ae171df, repo: https://deemz.org/git/joeri/dope2.git, type: git}
|
resolution: {commit: 0d3ccee7d5ce703e71fd3c05e1795c7968646a34, repo: https://deemz.org/git/joeri/dope2.git, type: git}
|
||||||
version: 0.0.1
|
version: 0.0.1
|
||||||
|
|
||||||
esbuild@0.25.4:
|
esbuild@0.25.4:
|
||||||
|
|
@ -1160,6 +1163,8 @@ snapshots:
|
||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.19.1
|
fastq: 1.19.1
|
||||||
|
|
||||||
|
'@rolldown/pluginutils@1.0.0-beta.9': {}
|
||||||
|
|
||||||
'@rollup/rollup-android-arm-eabi@4.41.0':
|
'@rollup/rollup-android-arm-eabi@4.41.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|
@ -1220,51 +1225,51 @@ snapshots:
|
||||||
'@rollup/rollup-win32-x64-msvc@4.41.0':
|
'@rollup/rollup-win32-x64-msvc@4.41.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-darwin-arm64@1.11.24':
|
'@swc/core-darwin-arm64@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-darwin-x64@1.11.24':
|
'@swc/core-darwin-x64@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-linux-arm-gnueabihf@1.11.24':
|
'@swc/core-linux-arm-gnueabihf@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-linux-arm64-gnu@1.11.24':
|
'@swc/core-linux-arm64-gnu@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-linux-arm64-musl@1.11.24':
|
'@swc/core-linux-arm64-musl@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-linux-x64-gnu@1.11.24':
|
'@swc/core-linux-x64-gnu@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-linux-x64-musl@1.11.24':
|
'@swc/core-linux-x64-musl@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-win32-arm64-msvc@1.11.24':
|
'@swc/core-win32-arm64-msvc@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-win32-ia32-msvc@1.11.24':
|
'@swc/core-win32-ia32-msvc@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core-win32-x64-msvc@1.11.24':
|
'@swc/core-win32-x64-msvc@1.11.29':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@swc/core@1.11.24':
|
'@swc/core@1.11.29':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/counter': 0.1.3
|
'@swc/counter': 0.1.3
|
||||||
'@swc/types': 0.1.21
|
'@swc/types': 0.1.21
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@swc/core-darwin-arm64': 1.11.24
|
'@swc/core-darwin-arm64': 1.11.29
|
||||||
'@swc/core-darwin-x64': 1.11.24
|
'@swc/core-darwin-x64': 1.11.29
|
||||||
'@swc/core-linux-arm-gnueabihf': 1.11.24
|
'@swc/core-linux-arm-gnueabihf': 1.11.29
|
||||||
'@swc/core-linux-arm64-gnu': 1.11.24
|
'@swc/core-linux-arm64-gnu': 1.11.29
|
||||||
'@swc/core-linux-arm64-musl': 1.11.24
|
'@swc/core-linux-arm64-musl': 1.11.29
|
||||||
'@swc/core-linux-x64-gnu': 1.11.24
|
'@swc/core-linux-x64-gnu': 1.11.29
|
||||||
'@swc/core-linux-x64-musl': 1.11.24
|
'@swc/core-linux-x64-musl': 1.11.29
|
||||||
'@swc/core-win32-arm64-msvc': 1.11.24
|
'@swc/core-win32-arm64-msvc': 1.11.29
|
||||||
'@swc/core-win32-ia32-msvc': 1.11.24
|
'@swc/core-win32-ia32-msvc': 1.11.29
|
||||||
'@swc/core-win32-x64-msvc': 1.11.24
|
'@swc/core-win32-x64-msvc': 1.11.29
|
||||||
|
|
||||||
'@swc/counter@0.1.3': {}
|
'@swc/counter@0.1.3': {}
|
||||||
|
|
||||||
|
|
@ -1276,11 +1281,11 @@ snapshots:
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/react-dom@19.1.5(@types/react@19.1.4)':
|
'@types/react-dom@19.1.5(@types/react@19.1.5)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 19.1.4
|
'@types/react': 19.1.5
|
||||||
|
|
||||||
'@types/react@19.1.4':
|
'@types/react@19.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.1.3
|
csstype: 3.1.3
|
||||||
|
|
||||||
|
|
@ -1361,9 +1366,10 @@ snapshots:
|
||||||
'@typescript-eslint/types': 8.32.1
|
'@typescript-eslint/types': 8.32.1
|
||||||
eslint-visitor-keys: 4.2.0
|
eslint-visitor-keys: 4.2.0
|
||||||
|
|
||||||
'@vitejs/plugin-react-swc@3.9.0(vite@6.3.5)':
|
'@vitejs/plugin-react-swc@3.10.0(vite@6.3.5)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@swc/core': 1.11.24
|
'@rolldown/pluginutils': 1.0.0-beta.9
|
||||||
|
'@swc/core': 1.11.29
|
||||||
vite: 6.3.5
|
vite: 6.3.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@swc/helpers'
|
- '@swc/helpers'
|
||||||
|
|
@ -1431,7 +1437,7 @@ snapshots:
|
||||||
|
|
||||||
deep-is@0.1.4: {}
|
deep-is@0.1.4: {}
|
||||||
|
|
||||||
dope2@git+https://deemz.org/git/joeri/dope2.git#8cfbd6116ffe778efb02c37133a1ff633ae171df:
|
dope2@git+https://deemz.org/git/joeri/dope2.git#0d3ccee7d5ce703e71fd3c05e1795c7968646a34:
|
||||||
dependencies:
|
dependencies:
|
||||||
functional-red-black-tree: 1.0.1
|
functional-red-black-tree: 1.0.1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { ExprBlock, type ExprBlockState } from './ExprBlock';
|
||||||
import { GlobalContext } from './GlobalContext';
|
import { GlobalContext } from './GlobalContext';
|
||||||
import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, tripleFunctionCallEditorState } from "./configurations";
|
import { biggerExample, emptySet, factorial, higherOrder, higherOrder2Params, inc, initialEditorState, lambda2Params, nonEmptyEditorState, pushBool, tripleFunctionCallEditorState } from "./configurations";
|
||||||
import { actionShortcuts } from './actions';
|
import { actionShortcuts } from './actions';
|
||||||
import { scoreResolved, type ResolvedType } from './eval';
|
// import { scoreResolved, type ResolvedType } from './eval';
|
||||||
|
|
||||||
|
|
||||||
const examples: [string, ExprBlockState][] = [
|
const examples: [string, ExprBlockState][] = [
|
||||||
|
|
@ -62,6 +62,8 @@ export function App() {
|
||||||
setAppState(_ => defaultState);
|
setAppState(_ => defaultState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// factoryReset();
|
||||||
|
|
||||||
const pushHistory = (callback: (p: ExprBlockState) => ExprBlockState) => {
|
const pushHistory = (callback: (p: ExprBlockState) => ExprBlockState) => {
|
||||||
setAppState(({history}) => {
|
setAppState(({history}) => {
|
||||||
const newState = callback(history.at(-1)!);
|
const newState = callback(history.at(-1)!);
|
||||||
|
|
@ -166,9 +168,7 @@ export function App() {
|
||||||
state={appState.history.at(-1)!}
|
state={appState.history.at(-1)!}
|
||||||
setState={pushHistory}
|
setState={pushHistory}
|
||||||
onCancel={() => {}}
|
onCancel={() => {}}
|
||||||
score={(resolved: ResolvedType) => {
|
score={() => 0}
|
||||||
return scoreResolved(resolved, () => 0);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</GlobalContext>
|
</GlobalContext>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
import { EnvContext } from "./EnvContext";
|
import { EnvContext } from "./EnvContext";
|
||||||
import { addFocusRightMost, evalCallBlock2, evalExprBlock, recomputeTypeVarsForEnv, scoreResolved, type Environment, type ResolvedType } from "./eval";
|
// import { addFocusRightMost, evalCallBlock2, evalExprBlock, recomputeTypeVarsForEnv, scoreResolved, type Environment, type ResolvedType } from "./eval";
|
||||||
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
import { ExprBlock, type ExprBlockState, type SetStateFn, type State2Props } from "./ExprBlock";
|
||||||
import { GlobalContext } from "./GlobalContext";
|
import { GlobalContext } from "./GlobalContext";
|
||||||
import { Value } from "./Value";
|
import { Value } from "./Value";
|
||||||
|
|
@ -9,6 +9,8 @@ import { Value } from "./Value";
|
||||||
import { getActions } from "./actions";
|
import { getActions } from "./actions";
|
||||||
import "./CallBlock.css";
|
import "./CallBlock.css";
|
||||||
import { CallContext } from "./CallContext";
|
import { CallContext } from "./CallContext";
|
||||||
|
import { inferType, inferTypeCall, type Environment } from "./infer_type";
|
||||||
|
import { Type } from "./Type";
|
||||||
|
|
||||||
export interface CallBlockState {
|
export interface CallBlockState {
|
||||||
kind: "call";
|
kind: "call";
|
||||||
|
|
@ -21,20 +23,19 @@ export interface CallBlockProps<
|
||||||
InputState=ExprBlockState,
|
InputState=ExprBlockState,
|
||||||
> extends State2Props<CallBlockState,ExprBlockState> {}
|
> extends State2Props<CallBlockState,ExprBlockState> {}
|
||||||
|
|
||||||
function nestedFnProperties({state, setState, score}: CallBlockProps, env) {
|
function nestedFnProperties({state, setState, score}: CallBlockProps, env: Environment) {
|
||||||
const setFn = (callback: SetStateFn) => {
|
const setFn = (callback: SetStateFn) => {
|
||||||
setState(state => ({...state, fn: callback(state.fn)}));
|
setState(state => ({...state, fn: callback(state.fn)}));
|
||||||
}
|
};
|
||||||
const onFnCancel = () => {
|
const onFnCancel = () => {
|
||||||
setState(state => state.input); // we become our input
|
setState(state => state.input); // we become our input
|
||||||
}
|
};
|
||||||
const scoreFn = (fnSuggestion: ResolvedType) => {
|
const scoreFn = (fnSuggestion: ExprBlockState) => {
|
||||||
return computePriority(
|
return score({
|
||||||
fnSuggestion,
|
kind: "call",
|
||||||
evalExprBlock(state.input, env)[0],
|
fn: fnSuggestion,
|
||||||
score,
|
input: state.input,
|
||||||
env,
|
});
|
||||||
);
|
|
||||||
};
|
};
|
||||||
return {state: state.fn, setState: setFn, onCancel: onFnCancel, score: scoreFn};
|
return {state: state.fn, setState: setFn, onCancel: onFnCancel, score: scoreFn};
|
||||||
}
|
}
|
||||||
|
|
@ -42,36 +43,37 @@ function nestedFnProperties({state, setState, score}: CallBlockProps, env) {
|
||||||
function nestedInputProperties({state, setState, score}: CallBlockProps, env: Environment) {
|
function nestedInputProperties({state, setState, score}: CallBlockProps, env: Environment) {
|
||||||
const setInput = (callback: SetStateFn) => {
|
const setInput = (callback: SetStateFn) => {
|
||||||
setState(state => ({...state, input: callback(state.input)}));
|
setState(state => ({...state, input: callback(state.input)}));
|
||||||
}
|
};
|
||||||
const onInputCancel = () => {
|
const onInputCancel = () => {
|
||||||
setState(state => addFocusRightMost(state.fn)); // we become our function
|
setState(state => /*addFocusRightMost*/(state.fn)); // we become our function
|
||||||
}
|
};
|
||||||
const scoreInput = (inputSuggestion: ResolvedType) => {
|
const scoreInput = (inputSuggestion: ExprBlockState) => {
|
||||||
return computePriority(
|
return score({
|
||||||
evalExprBlock(state.fn, env)[0], // fn *may* be set
|
kind: "call",
|
||||||
inputSuggestion, // suggestions will be for input
|
fn: state.fn,
|
||||||
score, // priority function we get from parent block
|
input: inputSuggestion,
|
||||||
env,
|
});
|
||||||
);
|
};
|
||||||
}
|
|
||||||
return {state: state.input, setState: setInput, onCancel: onInputCancel, score: scoreInput};
|
return {state: state.input, setState: setInput, onCancel: onInputCancel, score: scoreInput};
|
||||||
}
|
}
|
||||||
|
|
||||||
function computePriority(fn: ResolvedType, input: ResolvedType, outPriority: (s: ResolvedType) => number, env) {
|
// function computePriority(fn: ResolvedType, input: ResolvedType, outPriority: (s: ResolvedType) => number, env) {
|
||||||
// dirty, but works:
|
// // dirty, but works:
|
||||||
const [fnR, env2] = recomputeTypeVarsForEnv('<fn>', fn, env);
|
// const [fnR, env2] = recomputeTypeVarsForEnv('<fn>', fn, env);
|
||||||
const [inR, env3] = recomputeTypeVarsForEnv('<in>', input, env2);
|
// const [inR, env3] = recomputeTypeVarsForEnv('<in>', input, env2);
|
||||||
const [resolved] = evalCallBlock2(fnR, inR, env3);
|
// const [resolved] = evalCallBlock2(fnR, inR, env3);
|
||||||
const score = scoreResolved(resolved, outPriority);
|
// const score = scoreResolved(resolved, outPriority);
|
||||||
return score;
|
// return score;
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function CallBlock(props: CallBlockProps) {
|
export function CallBlock(props: CallBlockProps) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const addParam = getActions(globalContext, props.setState).c;
|
const addParam = getActions(globalContext, props.setState).c;
|
||||||
const [resolved] = evalExprBlock(props.state, env);
|
// const [resolved] = evalExprBlock(props.state, env);
|
||||||
return <span className={"functionBlock" + ((resolved.kind === "error") ? " unifyError" : "")}>
|
// return <span className={"functionBlock" + ((resolved.kind === "error") ? " unifyError" : "")}>
|
||||||
|
const typeInfo = inferTypeCall(props.state, env);
|
||||||
|
return <span className={"functionBlock"}>
|
||||||
<CallContext value={{addParam}}>
|
<CallContext value={{addParam}}>
|
||||||
<FunctionHeader {...props} addParam={addParam} />
|
<FunctionHeader {...props} addParam={addParam} />
|
||||||
<div className="functionParams">
|
<div className="functionParams">
|
||||||
|
|
@ -80,12 +82,14 @@ export function CallBlock(props: CallBlockProps) {
|
||||||
<InputParams
|
<InputParams
|
||||||
{...props}
|
{...props}
|
||||||
depth={0}
|
depth={0}
|
||||||
errorDepth={(resolved.kind === "error") ? (resolved.depth) : -1}
|
// errorDepth={(resolved.kind === "error") ? (resolved.depth) : -1}
|
||||||
|
errorDepth={-1}
|
||||||
addParam={addParam}
|
addParam={addParam}
|
||||||
/>
|
/>
|
||||||
{ (resolved.kind === "error") && resolved.e.toString()
|
{/* { (resolved.kind === "error") && resolved.e.toString()
|
||||||
|| (resolved.kind === "value") && <Value dynamic={resolved} />
|
|| (resolved.kind === "value") && <Value dynamic={resolved} />
|
||||||
|| "unknown" }
|
|| "unknown" } */}
|
||||||
|
:: <Type type={typeInfo.type} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CallContext>
|
</CallContext>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { createContext } from "react";
|
import { createContext } from "react";
|
||||||
import { getDefaultTypeParser, module2Env, ModuleStd } from "dope2";
|
import { getDefaultTypeParser, module2Env, ModuleStd } from "dope2";
|
||||||
import type { Dynamic, Environment } from "./eval";
|
// import type { Dynamic, Environment } from "./eval";
|
||||||
|
import type { Environment } from "./infer_type";
|
||||||
|
|
||||||
export const functionWith3Params = i => j => k => i+j+k;
|
export const functionWith3Params = i => j => k => i+j+k;
|
||||||
export const functionWith4Params = i => j => k => l => i+j+k+l;
|
export const functionWith4Params = i => j => k => l => i+j+k+l;
|
||||||
|
|
@ -14,10 +15,10 @@ export const extendedEnv: Environment = {
|
||||||
["leqZero", {i: n => leq => otherwise => (n<=0)?leq({}):otherwise({}), t: mkType("Int -> (Unit -> a) -> (Unit -> a) -> a")}],
|
["leqZero", {i: n => leq => otherwise => (n<=0)?leq({}):otherwise({}), t: mkType("Int -> (Unit -> a) -> (Unit -> a) -> a")}],
|
||||||
["functionWith3Params", { i: functionWith3Params, t: mkType("Int->Int->Int->Int") }],
|
["functionWith3Params", { i: functionWith3Params, t: mkType("Int->Int->Int->Int") }],
|
||||||
["functionWith4Params", { i: functionWith4Params, t: mkType("Int->Int->Int->Int->Int")}]
|
["functionWith4Params", { i: functionWith4Params, t: mkType("Int->Int->Int->Int->Int")}]
|
||||||
]).map(([name, {i,t}]) => [name, { kind: "value", i, t, unification: new Map() }] as [string, Dynamic])
|
]).map(([name, {i,t}]) => [name, { kind: "value", i, t, unification: new Map() }] as [string, any])
|
||||||
).name2dyn,
|
).name2dyn,
|
||||||
nextFreeTypeVar: 0,
|
// nextFreeTypeVar: 0,
|
||||||
typeVars: new Set(),
|
typevars: new Set(),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const EnvContext = createContext(extendedEnv);
|
export const EnvContext = createContext(extendedEnv);
|
||||||
|
|
@ -9,11 +9,12 @@ import { InputBlock, type InputBlockProps, type InputBlockState } from "./InputB
|
||||||
import { LambdaBlock, type LambdaBlockProps, type LambdaBlockState } from "./LambdaBlock";
|
import { LambdaBlock, type LambdaBlockProps, type LambdaBlockState } from "./LambdaBlock";
|
||||||
import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInBlock";
|
import { LetInBlock, type LetInBlockProps, type LetInBlockState } from "./LetInBlock";
|
||||||
import { Type } from "./Type";
|
import { Type } from "./Type";
|
||||||
import { evalExprBlock, type ResolvedType } from "./eval";
|
// import { evalExprBlock, type ResolvedType } from "./eval";
|
||||||
|
|
||||||
import "./ExprBlock.css";
|
import "./ExprBlock.css";
|
||||||
import { Input } from "./Input";
|
import { Input } from "./Input";
|
||||||
import { getActions } from "./actions";
|
import { getActions } from "./actions";
|
||||||
|
import { inferType } from "./infer_type";
|
||||||
|
|
||||||
export type ExprBlockState =
|
export type ExprBlockState =
|
||||||
InputBlockState
|
InputBlockState
|
||||||
|
|
@ -26,7 +27,7 @@ export type SetStateFn<InType = ExprBlockState, OutType = InType> = (state: InTy
|
||||||
export interface State2Props<InType, OutType = InType> {
|
export interface State2Props<InType, OutType = InType> {
|
||||||
state: InType;
|
state: InType;
|
||||||
setState: (callback: SetStateFn<InType, OutType>) => void;
|
setState: (callback: SetStateFn<InType, OutType>) => void;
|
||||||
score: (suggestion: ResolvedType) => number;
|
score: (suggestion: ExprBlockState) => number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ExprBlockProps extends State2Props<ExprBlockState> {
|
interface ExprBlockProps extends State2Props<ExprBlockState> {
|
||||||
|
|
@ -44,19 +45,22 @@ export function ExprBlock(props: ExprBlockProps) {
|
||||||
lambda: () => <LambdaBlock {...props as LambdaBlockProps} />,
|
lambda: () => <LambdaBlock {...props as LambdaBlockProps} />,
|
||||||
};
|
};
|
||||||
|
|
||||||
const [resolved] = evalExprBlock(props.state, env);
|
// const [resolved] = evalExprBlock(props.state, env);
|
||||||
|
// const typeInfo = inferType(props.state, env);
|
||||||
const actions = getActions(globalContext, props.setState);
|
const actions = getActions(globalContext, props.setState);
|
||||||
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
const extraHandlers = Object.fromEntries(Object.entries(actions).map(([shortcut, action]) =>
|
||||||
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
[shortcut, (e) => { e.preventDefault(); action(); }]))
|
||||||
|
|
||||||
return <span className={"editor" + ((resolved.kind!=="value") ? " "+resolved.kind : "")}>
|
// return <span className={"editor" + ((resolved.kind!=="value") ? " "+resolved.kind : "")}>
|
||||||
|
|
||||||
|
return <span className={"editor"}>
|
||||||
{renderBlock[props.state.kind]()}
|
{renderBlock[props.state.kind]()}
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
<div className={"typeSignature" + (resolved.__debug ? ' gotDebug' : '')}>
|
{/* <div className={"typeSignature" + (resolved.__debug ? ' gotDebug' : '')}> */}
|
||||||
:: <Type type={getType(resolved)} />
|
{/* :: <Type type={typeInfo.type} /> */}
|
||||||
{/* @ts-ignore */}
|
{/* @ts-ignore */}
|
||||||
{resolved.__debug && <div className="typeDebug">{resolved.__debug}</div>}
|
{/* {resolved.__debug && <div className="typeDebug">{resolved.__debug}</div>} */}
|
||||||
</div>
|
{/* </div> */}
|
||||||
<Input
|
<Input
|
||||||
placeholder="<c>"
|
placeholder="<c>"
|
||||||
text=""
|
text=""
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,16 @@ import { memo, useContext, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { getType, prettyT, trie } from "dope2";
|
import { getType, prettyT, trie } from "dope2";
|
||||||
|
|
||||||
import { EnvContext } from "./EnvContext";
|
import { EnvContext } from "./EnvContext";
|
||||||
import type { Environment, ResolvedType } from "./eval";
|
// import type { Environment, ResolvedType } from "./eval";
|
||||||
import "./InputBlock.css";
|
import "./InputBlock.css";
|
||||||
import { Type } from "./Type";
|
import { Type } from "./Type";
|
||||||
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
import type { ExprBlockState, State2Props } from "./ExprBlock";
|
||||||
import { attemptParseLiteral } from "./eval";
|
// import { attemptParseLiteral } from "./eval";
|
||||||
import { Input } from "./Input";
|
import { Input } from "./Input";
|
||||||
import { CallContext } from "./CallContext";
|
import { CallContext } from "./CallContext";
|
||||||
import { getActions } from "./actions";
|
import { getActions } from "./actions";
|
||||||
import { GlobalContext } from "./GlobalContext";
|
import { GlobalContext } from "./GlobalContext";
|
||||||
|
import { inferTypeInput } from "./infer_type";
|
||||||
|
|
||||||
interface Literal {
|
interface Literal {
|
||||||
kind: "literal";
|
kind: "literal";
|
||||||
|
|
@ -32,35 +33,35 @@ export interface InputBlockState {
|
||||||
focus: boolean
|
focus: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SuggestionType = ["literal"|"name", string, ResolvedType];
|
// export type SuggestionType = ["literal"|"name", string, ResolvedType];
|
||||||
export type PrioritizedSuggestionType = [number, ...SuggestionType];
|
// export type PrioritizedSuggestionType = [number, ...SuggestionType];
|
||||||
|
|
||||||
export interface InputBlockProps extends State2Props<InputBlockState,ExprBlockState> {
|
export interface InputBlockProps extends State2Props<InputBlockState,ExprBlockState> {
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const computeSuggestions = (
|
// const computeSuggestions = (
|
||||||
text: string,
|
// text: string,
|
||||||
env: Environment,
|
// env: Environment,
|
||||||
score: InputBlockProps['score'],
|
// score: InputBlockProps['score'],
|
||||||
): PrioritizedSuggestionType[] => {
|
// ): PrioritizedSuggestionType[] => {
|
||||||
const literals = attemptParseLiteral(text, env);
|
// const literals = attemptParseLiteral(text, env);
|
||||||
const ls: SuggestionType[] = [
|
// const ls: SuggestionType[] = [
|
||||||
// literals
|
// // literals
|
||||||
... literals.map((resolved) => ["literal", text, resolved]),
|
// ... literals.map((resolved) => ["literal", text, resolved]),
|
||||||
|
|
||||||
// names
|
// // names
|
||||||
... trie.suggest(env.names)(text)(Infinity)
|
// ... trie.suggest(env.names)(text)(Infinity)
|
||||||
.map(([name, resolved]) => ["name", name, resolved]),
|
// .map(([name, resolved]) => ["name", name, resolved]),
|
||||||
]
|
// ]
|
||||||
// return []; // <-- uncomment to disable suggestions (useful for debugging)
|
// // return []; // <-- uncomment to disable suggestions (useful for debugging)
|
||||||
return ls
|
// return ls
|
||||||
.map((suggestion: SuggestionType) =>
|
// .map((suggestion: SuggestionType) =>
|
||||||
[score(suggestion[2]), ...suggestion] as PrioritizedSuggestionType)
|
// [score(suggestion[2]), ...suggestion] as PrioritizedSuggestionType)
|
||||||
.sort(([priorityA], [priorityB]) => priorityB - priorityA)
|
// .sort(([priorityA], [priorityB]) => priorityB - priorityA)
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function InputBlock({ state, setState, score, onCancel }: InputBlockProps) {
|
export function InputBlock({ state, setState, /*score,*/ onCancel }: InputBlockProps) {
|
||||||
const {text, focus} = state;
|
const {text, focus} = state;
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
|
|
@ -69,7 +70,8 @@ export function InputBlock({ state, setState, score, onCancel }: InputBlockProps
|
||||||
const [i, setI] = useState(0); // selected suggestion idx
|
const [i, setI] = useState(0); // selected suggestion idx
|
||||||
|
|
||||||
const singleSuggestion = trie.growPrefix(env.names)(text);
|
const singleSuggestion = trie.growPrefix(env.names)(text);
|
||||||
const suggestions = useMemo(() => computeSuggestions(text, env, score), [text, score, env]);
|
// const suggestions = useMemo(() => computeSuggestions(text, env, score), [text, score, env]);
|
||||||
|
const suggestions = useMemo(() => [], []);
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -94,21 +96,21 @@ export function InputBlock({ state, setState, score, onCancel }: InputBlockProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSelectSuggestion = () => {
|
const onSelectSuggestion = () => {
|
||||||
const [_priority, kind, name, dynamic] = suggestions[i];
|
// const [_priority, kind, name, dynamic] = suggestions[i];
|
||||||
if (kind === "literal") {
|
// if (kind === "literal") {
|
||||||
setState(state => ({
|
// setState(state => ({
|
||||||
...state,
|
// ...state,
|
||||||
text: name,
|
// text: name,
|
||||||
value: {kind, type: prettyT(getType(dynamic))},
|
// value: {kind, type: prettyT(getType(dynamic))},
|
||||||
}));
|
// }));
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
setState(state => ({
|
// setState(state => ({
|
||||||
...state,
|
// ...state,
|
||||||
text: name,
|
// text: name,
|
||||||
value: {kind},
|
// value: {kind},
|
||||||
}))
|
// }))
|
||||||
}
|
// }
|
||||||
};
|
};
|
||||||
|
|
||||||
const extraHandlers = {
|
const extraHandlers = {
|
||||||
|
|
@ -134,7 +136,9 @@ export function InputBlock({ state, setState, score, onCancel }: InputBlockProps
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Input
|
const typeInfo = inferTypeInput(state, env);
|
||||||
|
|
||||||
|
return <><Input
|
||||||
placeholder="<name or literal>"
|
placeholder="<name or literal>"
|
||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
onEnter={onSelectSuggestion}
|
onEnter={onSelectSuggestion}
|
||||||
|
|
@ -150,6 +154,8 @@ export function InputBlock({ state, setState, score, onCancel }: InputBlockProps
|
||||||
i={i} setI={setI} />
|
i={i} setI={setI} />
|
||||||
</span>
|
</span>
|
||||||
</Input>
|
</Input>
|
||||||
|
::<Type type={typeInfo.type} />
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
function Suggestions({ suggestions, onSelect, i, setI }) {
|
function Suggestions({ suggestions, onSelect, i, setI }) {
|
||||||
|
|
@ -170,10 +176,10 @@ interface SuggestionProps {
|
||||||
j: number;
|
j: number;
|
||||||
onSelect: any;
|
onSelect: any;
|
||||||
highlighted: boolean;
|
highlighted: boolean;
|
||||||
suggestion: PrioritizedSuggestionType;
|
// suggestion: PrioritizedSuggestionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Suggestion({ setI, j, onSelect, highlighted, suggestion: [priority, kind, text, resolved] }: SuggestionProps) {
|
function Suggestion({ setI, j, onSelect, highlighted, /*suggestion: [priority, kind, text, resolved]*/ }: SuggestionProps) {
|
||||||
const onMouseEnter = j => () => {
|
const onMouseEnter = j => () => {
|
||||||
setI(j);
|
setI(j);
|
||||||
};
|
};
|
||||||
|
|
@ -186,7 +192,7 @@ function Suggestion({ setI, j, onSelect, highlighted, suggestion: [priority, kin
|
||||||
className={(highlighted ? " selected" : "")}
|
className={(highlighted ? " selected" : "")}
|
||||||
onMouseEnter={onMouseEnter(j)}
|
onMouseEnter={onMouseEnter(j)}
|
||||||
onMouseDown={onMouseDown(j)}>
|
onMouseDown={onMouseDown(j)}>
|
||||||
({priority}) ({kind}) {text} :: <Type type={resolved.t} />
|
{/* ({priority}) ({kind}) {text} :: <Type type={resolved.t} /> */}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
|
||||||
import { eqType, getSymbol, reduceUnification } from "dope2";
|
// import { eqType, getSymbol, reduceUnification } from "dope2";
|
||||||
|
|
||||||
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
import { ExprBlock, type ExprBlockState, type State2Props } from "./ExprBlock";
|
||||||
import { EnvContext } from "./EnvContext";
|
import { EnvContext } from "./EnvContext";
|
||||||
import { evalExprBlock, evalLambdaBlock, makeInnerEnv, makeTypeVar } from "./eval";
|
// import { evalExprBlock, evalLambdaBlock, makeInnerEnv, makeTypeVar } from "./eval";
|
||||||
|
|
||||||
import "./LambdaBlock.css";
|
import "./LambdaBlock.css";
|
||||||
import { Type } from "./Type";
|
import { Type } from "./Type";
|
||||||
import { Input } from "./Input";
|
import { Input } from "./Input";
|
||||||
|
import { inferTypeLambda } from "./infer_type";
|
||||||
|
|
||||||
export interface LambdaBlockState {
|
export interface LambdaBlockState {
|
||||||
kind: "lambda";
|
kind: "lambda";
|
||||||
|
|
@ -36,9 +37,13 @@ export function LambdaBlock({state, setState, score}: LambdaBlockProps) {
|
||||||
expr: callback(state.expr),
|
expr: callback(state.expr),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const [lambdaResolved, _, innerEnv] = evalLambdaBlock(state.paramName, state.expr, env);
|
const {paramType, innerEnv} = inferTypeLambda(state, env);
|
||||||
|
|
||||||
const inferredParamType = lambdaResolved.t.params[0](lambdaResolved.t);
|
// const [lambdaResolved, _, innerEnv] = evalLambdaBlock(state.paramName, state.expr, env);
|
||||||
|
|
||||||
|
// const inferredParamType = lambdaResolved.t.params[0](lambdaResolved.t);
|
||||||
|
|
||||||
|
// const innerEnv = env; // todo: change this
|
||||||
|
|
||||||
return <span className="lambdaBlock">
|
return <span className="lambdaBlock">
|
||||||
<span className="keyword">λ</span>
|
<span className="keyword">λ</span>
|
||||||
|
|
@ -55,7 +60,7 @@ export function LambdaBlock({state, setState, score}: LambdaBlockProps) {
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<div className="typeSignature">
|
<div className="typeSignature">
|
||||||
:: <Type type={inferredParamType} />
|
:: <Type type={paramType} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span className="keyword">:</span>
|
<span className="keyword">:</span>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@ import { useContext } from "react";
|
||||||
|
|
||||||
import { ExprBlock, type ExprBlockState } from "./ExprBlock";
|
import { ExprBlock, type ExprBlockState } from "./ExprBlock";
|
||||||
import { EnvContext } from "./EnvContext";
|
import { EnvContext } from "./EnvContext";
|
||||||
import { evalExprBlock, makeInnerEnv, scoreResolved, type ResolvedType } from "./eval";
|
// import { evalExprBlock, makeInnerEnv, scoreResolved, type ResolvedType } from "./eval";
|
||||||
import { type State2Props } from "./ExprBlock";
|
import { type State2Props } from "./ExprBlock";
|
||||||
import { GlobalContext } from "./GlobalContext";
|
import { GlobalContext } from "./GlobalContext";
|
||||||
|
|
||||||
import "./LetInBlock.css";
|
import "./LetInBlock.css";
|
||||||
import { Input } from "./Input";
|
import { Input } from "./Input";
|
||||||
|
import { inferTypeLet } from "./infer_type";
|
||||||
|
import { Type } from "./Type";
|
||||||
|
|
||||||
export interface LetInBlockState {
|
export interface LetInBlockState {
|
||||||
kind: "let";
|
kind: "let";
|
||||||
|
|
@ -31,49 +33,54 @@ export function LetInBlock(props: LetInBlockProps) {
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
function DeclColumns({state: {name, value, inner, focus}, setState, score}) {
|
function DeclColumns({state, setState, score}) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
|
|
||||||
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
||||||
const setValue = callback => setState(state => ({...state, value: callback(state.value)}));
|
const setValue = callback => setState(state => ({...state, value: callback(state.value)}));
|
||||||
|
|
||||||
const valueSuggestionPriority = (suggestion: ResolvedType) => {
|
// const valueSuggestionPriority = (suggestion: ResolvedType) => {
|
||||||
const innerEnv = makeInnerEnv(env, name, suggestion);
|
// const innerEnv = makeInnerEnv(env, name, suggestion);
|
||||||
const [resolved] = evalExprBlock(inner, innerEnv);
|
// const [resolved] = evalExprBlock(inner, innerEnv);
|
||||||
return scoreResolved(resolved, score);
|
// return scoreResolved(resolved, score);
|
||||||
};
|
// };
|
||||||
|
|
||||||
const [valueResolved] = evalExprBlock(value, env);
|
// const [valueResolved] = evalExprBlock(value, env);
|
||||||
const innerEnv = makeInnerEnv(env, name, valueResolved);
|
// const innerEnv = makeInnerEnv(env, name, valueResolved);
|
||||||
|
|
||||||
|
const {paramType, innerEnv} = inferTypeLet(state, env);
|
||||||
|
|
||||||
|
// const innerEnv = env; // todo: change this
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<span className="keyword column">let </span>
|
<span className="keyword column">let </span>
|
||||||
<span className="column rightAlign">
|
<span className="column rightAlign">
|
||||||
<Input
|
<Input
|
||||||
placeholder="<name>"
|
placeholder="<name>"
|
||||||
text={name}
|
text={state.name}
|
||||||
suggestion=""
|
suggestion=""
|
||||||
onEnter={() => {}}
|
onEnter={() => {}}
|
||||||
onCancel={() => {}}
|
onCancel={() => {}}
|
||||||
onTextChange={name => setState(state => ({...state, name}))}
|
onTextChange={name => setState(state => ({...state, name}))}
|
||||||
extraHandlers={{}}
|
extraHandlers={{}}
|
||||||
/>
|
/>
|
||||||
|
:: <Type type={paramType} />
|
||||||
</span>
|
</span>
|
||||||
<span className="keyword column"> = </span>
|
<span className="keyword column"> = </span>
|
||||||
<span className="column">
|
<span className="column">
|
||||||
<ExprBlock
|
<ExprBlock
|
||||||
state={value}
|
state={state.value}
|
||||||
setState={setValue}
|
setState={setValue}
|
||||||
score={valueSuggestionPriority}
|
score={() => 0}
|
||||||
onCancel={() => setState(state => state.inner)} // keep inner
|
onCancel={() => setState(state => state.inner)} // keep inner
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
{inner.kind === "let" &&
|
{state.inner.kind === "let" &&
|
||||||
globalContext?.syntacticSugar &&
|
globalContext?.syntacticSugar &&
|
||||||
<EnvContext value={innerEnv}>
|
<EnvContext value={innerEnv}>
|
||||||
<DeclColumns
|
<DeclColumns
|
||||||
state={inner}
|
state={state.inner}
|
||||||
setState={setInner}
|
setState={setInner}
|
||||||
score={score}
|
score={score}
|
||||||
/>
|
/>
|
||||||
|
|
@ -86,8 +93,9 @@ function InnerMost({state, setState, score}) {
|
||||||
const env = useContext(EnvContext);
|
const env = useContext(EnvContext);
|
||||||
const globalContext = useContext(GlobalContext);
|
const globalContext = useContext(GlobalContext);
|
||||||
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
const setInner = callback => setState(state => ({...state, inner: callback(state.inner)}));
|
||||||
const [valueResolved] = evalExprBlock(state.value, env);
|
// const [valueResolved] = evalExprBlock(state.value, env);
|
||||||
const innerEnv = makeInnerEnv(env, state.name, valueResolved);
|
// const innerEnv = makeInnerEnv(env, state.name, valueResolved);
|
||||||
|
const innerEnv = env; // todo: change this
|
||||||
const onCancel = () => setState(state => state.value);
|
const onCancel = () => setState(state => state.value);
|
||||||
if (state.inner.kind === "let" && globalContext?.syntacticSugar) {
|
if (state.inner.kind === "let" && globalContext?.syntacticSugar) {
|
||||||
return <EnvContext value={innerEnv}>
|
return <EnvContext value={innerEnv}>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { initialEditorState } from "./configurations";
|
import { initialEditorState } from "./configurations";
|
||||||
import { removeFocus } from "./eval";
|
// import { removeFocus } from "./eval";
|
||||||
|
|
||||||
|
const removeFocus = state => state;
|
||||||
|
|
||||||
export const actionShortcuts: [string, string[], string][] = [
|
export const actionShortcuts: [string, string[], string][] = [
|
||||||
["call" , ['c'], "expr ⌴" ],
|
["call" , ['c'], "expr ⌴" ],
|
||||||
|
|
|
||||||
1088
src/eval.ts
1088
src/eval.ts
File diff suppressed because it is too large
Load diff
216
src/infer_type.ts
Normal file
216
src/infer_type.ts
Normal file
|
|
@ -0,0 +1,216 @@
|
||||||
|
import { Double, eqType, fnType, IncompatibleTypesError, Int, mergeSubstitutionsN, occurring, prettySS, recomputeTypeVars, substitute, trie, TYPE_VARS, UNBOUND_SYMBOLS, unify } from "dope2";
|
||||||
|
|
||||||
|
import type { CallBlockState } from "./CallBlock";
|
||||||
|
import type { ExprBlockState } from "./ExprBlock";
|
||||||
|
import type { InputBlockState } from "./InputBlock";
|
||||||
|
import type { LambdaBlockState } from "./LambdaBlock";
|
||||||
|
import type { LetInBlockState } from "./LetInBlock";
|
||||||
|
|
||||||
|
export interface Environment {
|
||||||
|
names: any;
|
||||||
|
typevars: Set<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Type {
|
||||||
|
symbol: string;
|
||||||
|
params: ((t: Type) => Type)[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Substitutions = Map<string, Type>;
|
||||||
|
|
||||||
|
export interface TypeInfo {
|
||||||
|
type: Type;
|
||||||
|
subs: Substitutions;
|
||||||
|
newEnv: Environment;
|
||||||
|
err?: IncompatibleTypesError;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LambdaTypeInfo extends TypeInfo {
|
||||||
|
paramType: Type;
|
||||||
|
innerEnv: Environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inferType(s: ExprBlockState, env: Environment): TypeInfo {
|
||||||
|
if (s.kind === "input") {
|
||||||
|
return inferTypeInput(s, env);
|
||||||
|
}
|
||||||
|
else if (s.kind === "call") {
|
||||||
|
return inferTypeCall(s, env);
|
||||||
|
}
|
||||||
|
else if (s.kind === "let") {
|
||||||
|
return inferTypeLet(s, env);
|
||||||
|
}
|
||||||
|
else { // (s.kind === "lambda")
|
||||||
|
return inferTypeLambda(s, env);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inferTypeInput(s: InputBlockState, env: Environment): TypeInfo {
|
||||||
|
if (s.value.kind === "literal") {
|
||||||
|
const type = {
|
||||||
|
Int: Int,
|
||||||
|
Double: Double,
|
||||||
|
}[s.value.type] as Type;
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
subs: new Map(),
|
||||||
|
newEnv: env,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (s.value.kind === "name") {
|
||||||
|
const found = trie.get(env.names)(s.text);
|
||||||
|
if (found) {
|
||||||
|
let type = found.t;
|
||||||
|
let newEnv = env;
|
||||||
|
if (found.kind !== "unknown") {
|
||||||
|
[type, newEnv] = rewriteType(found.t, env);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
subs: new Map(),
|
||||||
|
newEnv,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// kind === "text", or name not found
|
||||||
|
const [type, newEnv] = typeUnknown(env);
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
subs: new Map(),
|
||||||
|
newEnv,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
export function inferTypeCall(s: CallBlockState, env: Environment): TypeInfo {
|
||||||
|
const fnTypeInfo = inferType(s.fn, env);
|
||||||
|
const inputTypeInfo = inferType(s.input, fnTypeInfo.newEnv);
|
||||||
|
const [returnType, envWithReturn] = typeUnknown(inputTypeInfo.newEnv);
|
||||||
|
const fakeFnType = fnType(_ => inputTypeInfo.type)(_ => returnType);
|
||||||
|
try {
|
||||||
|
const subs = unify(
|
||||||
|
fnTypeInfo.type,
|
||||||
|
fakeFnType);
|
||||||
|
console.log("subs:", prettySS(subs));
|
||||||
|
let type, newEnv;
|
||||||
|
if (subs.has(returnType!.symbol)) {
|
||||||
|
type = subs.get(returnType!.symbol);
|
||||||
|
subs.delete(returnType!.symbol);
|
||||||
|
newEnv = inputTypeInfo.newEnv
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
type = returnType;
|
||||||
|
newEnv = envWithReturn;
|
||||||
|
}
|
||||||
|
const mergedSubs = mergeSubstitutionsN([
|
||||||
|
fnTypeInfo.subs,
|
||||||
|
inputTypeInfo.subs,
|
||||||
|
subs,
|
||||||
|
]);
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
subs: mergedSubs,
|
||||||
|
newEnv,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof IncompatibleTypesError) {
|
||||||
|
const [type, newEnv] = typeUnknown(env);
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
subs: new Map(),
|
||||||
|
newEnv,
|
||||||
|
err: e,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function inferTypeLet(s: LetInBlockState, env: Environment): LambdaTypeInfo {
|
||||||
|
const valTypeInfo = inferType(s.value, env);
|
||||||
|
const innerEnv = {
|
||||||
|
names: trie.insert(env.names)(s.name)({kind: "value", t: valTypeInfo.type}),
|
||||||
|
typevars: env.typevars,
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
...inferType(s.inner, innerEnv),
|
||||||
|
paramType: valTypeInfo.type,
|
||||||
|
innerEnv,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function inferTypeLambda(s: LambdaBlockState, env: Environment): LambdaTypeInfo {
|
||||||
|
let [paramType] = typeUnknown(env);
|
||||||
|
const paramTypeVar = paramType.symbol;
|
||||||
|
|
||||||
|
let iterations = 1;
|
||||||
|
while (true) {
|
||||||
|
const innerEnv = {
|
||||||
|
names: trie.insert(env.names)(s.paramName)({kind: "unknown", t: paramType}),
|
||||||
|
typevars: env.typevars.union(occurring(paramType) as Set<string>),
|
||||||
|
};
|
||||||
|
const typeInfo = inferType(s.expr, innerEnv);
|
||||||
|
const subsWithoutPType = new Map(typeInfo.subs);
|
||||||
|
subsWithoutPType.delete(paramTypeVar);
|
||||||
|
const inferredPType = substitute(paramType, typeInfo.subs, []);
|
||||||
|
const inferredPType2 = rewriteInferredType(inferredPType, env);
|
||||||
|
if (eqType(inferredPType2)(paramType)) {
|
||||||
|
return {
|
||||||
|
type: fnType(_ => paramType)(_ => typeInfo.type),
|
||||||
|
subs: subsWithoutPType,
|
||||||
|
newEnv: env, // no change
|
||||||
|
paramType,
|
||||||
|
innerEnv,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if ((iterations++) == 4) {
|
||||||
|
throw new Error("too many iterations!");
|
||||||
|
}
|
||||||
|
// console.log("-----------------", iterations);
|
||||||
|
// console.log("paramType:", prettyT(paramType));
|
||||||
|
// console.log("inferredPType:", prettyT(inferredPType));
|
||||||
|
// console.log("inferredPType2:", prettyT(inferredPType2));
|
||||||
|
// console.log("env:", [...env.typevars].map(getHumanReadableName));
|
||||||
|
// console.log("innerEnv:", [...innerEnv.typevars].map(getHumanReadableName));
|
||||||
|
// console.log("-----------------");
|
||||||
|
paramType = inferredPType2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
const highestTypeVar2 = (typevars: Iterable<string>) => {
|
||||||
|
let highest = -1;
|
||||||
|
for (const typeVar of typevars) {
|
||||||
|
highest = Math.max(highest, UNBOUND_SYMBOLS.indexOf(typeVar));
|
||||||
|
}
|
||||||
|
return highest;
|
||||||
|
}
|
||||||
|
function rewriteType(type: Type, env: Environment): [Type, Environment] {
|
||||||
|
const [recomputed] = recomputeTypeVars([type], highestTypeVar2(env.typevars)+1);
|
||||||
|
return [type, {
|
||||||
|
names: env.names,
|
||||||
|
typevars: env.typevars.union(occurring(recomputed)),
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
function typeUnknown(env: Environment): [Type, Environment] {
|
||||||
|
const type = TYPE_VARS[highestTypeVar2(env.typevars)+1];
|
||||||
|
const newEnv = {
|
||||||
|
names: env.names,
|
||||||
|
typevars: new Set([...env.typevars, type.symbol]),
|
||||||
|
};
|
||||||
|
return [type, newEnv];
|
||||||
|
}
|
||||||
|
function rewriteInferredType(type: Type, env: Environment) {
|
||||||
|
const substitutions = new Map();
|
||||||
|
let i = 0;
|
||||||
|
for (const o of occurring(type)) {
|
||||||
|
while (env.typevars.has(UNBOUND_SYMBOLS[i])) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (!env.typevars.has(o)) {
|
||||||
|
substitutions.set(o, TYPE_VARS[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return substitute(type, substitutions, []);
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue