diff --git a/.github/workflows/github-release.yml b/.github/workflows/github-release.yml index 9f57be65..e78a05be 100644 --- a/.github/workflows/github-release.yml +++ b/.github/workflows/github-release.yml @@ -85,7 +85,7 @@ jobs: - uses: actions/upload-artifact@v4 with: - name: build-artifacts + name: build-artifacts-${{ matrix.os }} path: artifacts/* if-no-files-found: error retention-days: 1 @@ -96,9 +96,14 @@ jobs: steps: - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 with: - name: build-artifacts + name: build-artifacts-windows-latest + path: build-artifacts + - uses: actions/download-artifact@v3 + with: + name: build-artifacts-ubuntu-latest path: build-artifacts - name: Print artifacts diff --git a/.github/workflows/performance-and-size.yml b/.github/workflows/performance-and-size.yml index a3c964c7..2a99cbd2 100644 --- a/.github/workflows/performance-and-size.yml +++ b/.github/workflows/performance-and-size.yml @@ -8,7 +8,7 @@ env: CARGO_TERM_COLOR: always jobs: - hyperfine: + run-benchmarks: runs-on: ubuntu-latest steps: @@ -34,32 +34,49 @@ jobs: - name: Download files run: | - curl -O https://gist.githubusercontent.com/kaleidawave/5dcb9ec03deef1161ebf0c9d6e4b88d8/raw/03156048e214af0ceee4005ba8b86f96690dcbb2/demo.ts > demo.ts - curl https://esm.sh/v128/react-dom@18.2.0/es2022/react-dom.mjs > react.js - - name: Run parser, minfier, stringer performance + - name: Run checker performance shell: bash run: | - curl https://esm.sh/v128/react-dom@18.2.0/es2022/react-dom.mjs > react.js + # Generate a file which contains everything that Ezno currently implements + cargo run -p ezno-parser --example code_blocks_to_script ./checker/specification/specification.md demo.ts - echo "### Hyperfine">> $GITHUB_STEP_SUMMARY - echo "\`\`\`shell">> $GITHUB_STEP_SUMMARY - hyperfine './target/release/ezno ast-explorer --file react.js uglifier' >> $GITHUB_STEP_SUMMARY + echo "
+ Input + + \`\`\`ts + " >> $GITHUB_STEP_SUMMARY + cat demo.ts >> $GITHUB_STEP_SUMMARY + echo "\`\`\` +
+ " >> $GITHUB_STEP_SUMMARY + + # Printing diagnostics, so turn colors off for GH Summary + NO_COLOR=1 + + echo "
+ Diagnostics + + \`\`\`" >> $GITHUB_STEP_SUMMARY + ./target/release/ezno check demo.ts --timings &>> $GITHUB_STEP_SUMMARY + echo "\`\`\` +
+ " >> $GITHUB_STEP_SUMMARY + + echo "### Checking + \`\`\`shell" >> $GITHUB_STEP_SUMMARY + hyperfine './target/release/ezno check demo.ts' >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - - name: Run checker performance + - name: Run parser, minfier/stringer performance shell: bash - if: false run: | - echo "### Output">> $GITHUB_STEP_SUMMARY - echo "\`\`\`shell">> $GITHUB_STEP_SUMMARY - ./target/release/ezno check demo.ts >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - - echo "### Hyperfine">> $GITHUB_STEP_SUMMARY - echo "\`\`\`shell">> $GITHUB_STEP_SUMMARY - hyperfine './target/release/ezno check demo.ts' >> $GITHUB_STEP_SUMMARY + curl https://esm.sh/v128/react-dom@18.2.0/es2022/react-dom.mjs > react.js + + echo "### Parsing and writing out minified form of `react-dom` + \`\`\`shell">> $GITHUB_STEP_SUMMARY + hyperfine './target/release/ezno ast-explorer --file react.js uglifier' >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - name: Print (linux) binary size diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index d1d7c945..080238a0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -95,7 +95,7 @@ jobs: - uses: brndnmtthws/rust-action-cargo-binstall@v1 if: ${{ github.event.inputs.ezno-version != 'none' }} with: - packages: wasm-bindgen-cli@0.2.87 + packages: wasm-bindgen-cli@0.2.89 - name: Set NPM package version & build id: set-npm-version @@ -140,11 +140,15 @@ jobs: run: | git add . git commit -m "Release: ${{ steps.release.outputs.new-versions-description }}" + + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config user.name "github-actions[bot]" # Create tags echo '${{ steps.release.outputs.new-versions }}' | jq -r '.[]' | while read -r update; do git tag "release/$update" done + git push --tags origin main - name: Discord diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 902ea5d6..4f9844dd 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -71,7 +71,7 @@ jobs: - uses: brndnmtthws/rust-action-cargo-binstall@v1 if: steps.changes.outputs.src == 'true' with: - packages: wasm-bindgen-cli@0.2.87 + packages: wasm-bindgen-cli@0.2.89 - uses: denoland/setup-deno@v1 if: steps.changes.outputs.src == 'true' with: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94a16890..db09f18b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,10 @@ If you want to check all the checker tests ```shell cargo test -p ezno-checker-specification +# Also +cargo test -p ezno-checker-specification -F staging +# and +cargo test -p ezno-checker-specification -F all ``` If you want to test the lexing and parsing in Ezno's parser @@ -46,7 +50,7 @@ cargo run -p ezno-parser --example lex path/to/file.ts ### Useful commands - Check source is valid with `cargo check --workspace` -- Check that code is formatted in accordance with the specification with `cargo fmt --all --check` +- Check that code is formatted in accordance with the configuration with `cargo fmt --all --check` - Run all tests `cargo test --workspace --verbose` - Use `cargo clippy -- --allow warnings` to find blocking lints diff --git a/Cargo.lock b/Cargo.lock index 139cc7b0..2e877d84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" -dependencies = [ - "memchr", -] - [[package]] name = "argh" version = "0.1.12" @@ -50,9 +41,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" -version = "0.13.1" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bimap" @@ -73,6 +64,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "bumpalo" version = "3.14.0" @@ -85,12 +82,6 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -109,17 +100,15 @@ dependencies = [ [[package]] name = "console" -version = "0.14.1" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3993e6445baa160675931ec041a5e03ca84b9c6e32a056150d3aa2bdda0a1f45" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode", "lazy_static", "libc", - "regex", - "terminal_size", "unicode-width", - "winapi 0.3.9", + "windows-sys 0.45.0", ] [[package]] @@ -128,10 +117,29 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82a9b73a36529d9c47029b9fb3a6f0ea3cc916a261195352ba19e770fc1748b2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" +dependencies = [ + "cfg-if", +] + [[package]] name = "derive-debug-extras" version = "0.2.2" @@ -241,11 +249,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "erased-serde" -version = "0.3.31" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" +checksum = "4adbf0983fe06bd3a5c19c8477a637c2389feb0994eca7a59e3b961054aa7c0a" dependencies = [ "serde", ] @@ -342,47 +356,21 @@ version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", - "windows-sys", -] - -[[package]] -name = "fsevent" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -dependencies = [ - "bitflags", - "fsevent-sys", + "windows-sys 0.52.0", ] [[package]] name = "fsevent-sys" -version = "2.0.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" dependencies = [ "libc", ] -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "get-field-by-type" version = "0.0.3" @@ -403,27 +391,27 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "indexmap" -version = "1.9.3" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ - "autocfg", + "equivalent", "hashbrown", ] [[package]] name = "inotify" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" dependencies = [ - "bitflags", + "bitflags 1.3.2", "inotify-sys", "libc", ] @@ -437,15 +425,6 @@ dependencies = [ "libc", ] -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - [[package]] name = "iterator-endiate" version = "0.2.1" @@ -468,26 +447,30 @@ dependencies = [ ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "kqueue" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "kqueue-sys", + "libc", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "kqueue-sys" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "lazy_static" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "levenshtein" @@ -527,53 +510,16 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - [[package]] name = "mio" -version = "0.6.23" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio", - "slab", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", + "wasi", + "windows-sys 0.48.0", ] [[package]] @@ -585,33 +531,23 @@ dependencies = [ "winconsole", ] -[[package]] -name = "net2" -version = "0.2.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", -] - [[package]] name = "notify" -version = "4.0.17" +version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags", + "bitflags 2.4.1", + "crossbeam-channel", "filetime", - "fsevent", "fsevent-sys", "inotify", + "kqueue", "libc", + "log", "mio", - "mio-extras", "walkdir", - "winapi 0.3.9", + "windows-sys 0.48.0", ] [[package]] @@ -631,9 +567,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "ordered-float" -version = "3.9.2" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1e1c390732d15f1d48471625cd92d154e66db2c56645e29a9cd26f4699f72dc" +checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" dependencies = [ "num-traits", ] @@ -701,38 +637,9 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] -[[package]] -name = "regex" -version = "1.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" - [[package]] name = "rgb" version = "0.8.37" @@ -789,9 +696,9 @@ dependencies = [ [[package]] name = "serde-wasm-bindgen" -version = "0.5.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +checksum = "b9b713f70513ae1f8d92665bbbbda5c295c2cf1da5542881ae5eefe20c9af132" dependencies = [ "js-sys", "serde", @@ -820,15 +727,6 @@ dependencies = [ "serde", ] -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "source-map" version = "0.14.7" @@ -895,16 +793,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi 0.3.9", -] - [[package]] name = "tokenizer-lib" version = "1.5.1" @@ -936,21 +824,27 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", @@ -963,9 +857,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -973,9 +867,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", @@ -986,15 +880,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "winapi" -version = "0.2.8" +version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "winapi" @@ -1006,12 +894,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -1024,7 +906,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1041,7 +923,25 @@ checksum = "664fdcefd3903fbe6c463659a3fe4e7a541e717bbf6084cb1cfa98fcb6d88361" dependencies = [ "lazy_static", "rgb", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", ] [[package]] @@ -1050,7 +950,37 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets", + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", ] [[package]] @@ -1059,45 +989,117 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" @@ -1106,19 +1108,21 @@ checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "yansi" diff --git a/Cargo.toml b/Cargo.toml index f268feb0..38987f0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,10 +54,10 @@ path = "src/main.rs" [dependencies] # ezno-web-framework = { path = "./plugins/web" } -console = "0.14.1" +console = "0.15.7" codespan-reporting = "0.11.1" argh = "0.1.6" -base64 = "0.13.0" +base64 = "0.21.5" enum-variants-strings = "0.2.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.107" @@ -75,11 +75,11 @@ features = ["extras"] package = "ezno-parser" [target.'cfg(target_family = "wasm")'.dependencies] -wasm-bindgen = "=0.2.87" -serde-wasm-bindgen = "0.5.0" +wasm-bindgen = "=0.2.89" +serde-wasm-bindgen = "0.6.3" console_error_panic_hook = "0.1.7" js-sys = "0.3" [target.'cfg(not(target_family = "wasm"))'.dependencies] multiline-term-input = "0.1.0" -notify = "4.0.17" +notify = "6.1.0" diff --git a/checker/Cargo.toml b/checker/Cargo.toml index 23810828..da4c87c5 100644 --- a/checker/Cargo.toml +++ b/checker/Cargo.toml @@ -8,6 +8,7 @@ homepage = "https://kaleidawave.github.io/posts/introducing-ezno" authors = ["Ben "] edition = "2021" categories = ["compilers"] +keywords = ["javascript", "typechecker", "checker", "typescript", "types"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -33,16 +34,16 @@ iterator-endiate = "0.2" bimap = "0.6.2" path-absolutize = { version = "3.0.14", features = ["use_unix_paths_on_wasm"] } -indexmap = "1.7.0" +indexmap = "2.1.0" either = "1.6.1" levenshtein = "1.0.5" once_cell = "1.10.0" -ordered-float = "3.0.0" +ordered-float = "4.2.0" map_vec = "0.3.0" serde = { version = "1.0", features = ["derive"] } # For trait object safe thingy -erased-serde = "0.3" +erased-serde = "0.4.1" [dependencies.parser] path = "../parser" diff --git a/checker/definitions/internal-full.d.ts b/checker/definitions/internal-full.d.ts index 623d6eb3..c78668cc 100644 --- a/checker/definitions/internal-full.d.ts +++ b/checker/definitions/internal-full.d.ts @@ -1,23 +1,3 @@ -// ↓↓ Ezno Functions ↓↓ -declare function debug_context(): void performs const debug_context; -declare function print_type(t: any): void performs const print_type; -declare function debug_type(t: any): void performs const debug_type; -declare function debug_type_rust(t: any): void performs const debug_type_rust; -declare function debug_effects_rust(t: () => {}): void performs const debug_effects_rust; -declare function debug_effects(t: () => {}): void performs const debug_effects; -declare function is_dependent(t: any): void performs const is_dependent; - -declare function context_id(): void performs const context_id; -declare function context_id_chain(): void performs const context_id_chain; - -// A function, as it should be! -declare function satisfies(t: T): T performs const satisfies; - -declare function compile_type_to_object(): any performs const compile_type_to_object; -// ↑↑ Ezno Functions ↑↑ - -declare var undefined: undefined; - interface nominal Array { [index: number]: T | undefined; @@ -38,17 +18,18 @@ interface nominal Array { } } - map(cb: (t: T) => U): Array performs { + // TODO this argument + map(cb: (t: T, i?: number, self: Array) => U): Array performs { const { length } = this, u: Array = []; let i: number = 0; while (i < length) { - const value = this[i++]; - u.push(cb(value)) + const value = this[i]; + u.push(cb(value, i++, this)) } return u; } - filter(cb: (t: T) => boolean): Array performs { + filter(cb: (t: T, i?: number, self: Array) => boolean): Array performs { const { length } = this, filtered: Array = []; let i: number = 0; while (i < length) { @@ -60,7 +41,7 @@ interface nominal Array { return filtered; } - find(cb: (t: T) => boolean): T | undefined performs { + find(cb: (t: T, i?: number, self: Array) => boolean): T | undefined performs { const { length } = this; let i: number = 0; while (i < length) { @@ -71,7 +52,7 @@ interface nominal Array { } } - every(cb: (t: T) => boolean): boolean performs { + every(cb: (t: T, i?: number, self: Array) => boolean): boolean performs { const { length } = this; let i: number = 0; while (i < length) { @@ -84,7 +65,7 @@ interface nominal Array { return true } - some(cb: (t: T) => boolean): boolean performs { + some(cb: (t: T, i?: number, self: Array) => boolean): boolean performs { const { length } = this; let i: number = 0; while (i < length) { @@ -108,9 +89,19 @@ interface nominal Array { return false } - // last() performs { - // return this[this.length - 1] - // } + join(joiner: string = ","): string performs { + const { length } = this; + let i = 1; + if (length === 0) { + return "" + } + // TODO conversion + let s: string = "" + this[0]; + while (i < length) { + s += this[i++]; + } + return s + } } interface Math { @@ -140,6 +131,12 @@ interface nominal string { toLowerCase(): string performs const lowercase; get length(): number performs const string_length; + + // TODO + slice(start: number, end?: number): string performs const slice; + + // TODO + split(splitter: string): Array performs const split; } interface Console { diff --git a/checker/definitions/internal.d.ts b/checker/definitions/internal.d.ts index a4804291..b35f9196 100644 --- a/checker/definitions/internal.d.ts +++ b/checker/definitions/internal.d.ts @@ -18,7 +18,7 @@ declare function satisfies(t: T): T performs const satisfies; declare function compile_type_to_object(): any performs const compile_type_to_object; // ↑↑ Ezno Functions ↑↑ -declare var undefined: undefined; +// declare var undefined: undefined; interface nominal Array { [index: number]: T | undefined; @@ -98,7 +98,7 @@ interface Symbols { iterator: 199 } -declare var Symbol: Symbols; +declare const Symbol: Symbols; interface Object { @DoNotIncludeThis @@ -114,10 +114,10 @@ interface Object { // } } -declare var JSON: JSON; -declare var Math: Math; -declare var console: Console; -declare var Object: Object; +declare const JSON: JSON; +declare const Math: Math; +declare const console: Console; +declare const Object: Object; declare function JSXH(tag: string, attributes: any, children?: any) performs { return { tag, attributes, children } diff --git a/checker/docs/inference.md b/checker/docs/inference.md index 81301ce4..d3a7f782 100644 --- a/checker/docs/inference.md +++ b/checker/docs/inference.md @@ -35,11 +35,6 @@ print_properties({ x: 1, get y() { Reflect.set(this, "z", 3); return 2 } }) This may be solved in the future by a different way of checking parameters, but for now it is recognised as a use case that should be avoided. -### #TODO -- Mutable and immutable bases in `Context` -- Modify RootPoly so only open poly and Typed generic and parameter can have a aliases, rest is handled by Context -- Think about how function constraints work (they may not exist under `Type`) - ### Inferable properties There are two types of inference, type based *coalescence*: diff --git a/checker/examples/check.rs b/checker/examples/check.rs index 1d61d2d4..fc18dd83 100644 --- a/checker/examples/check.rs +++ b/checker/examples/check.rs @@ -13,7 +13,7 @@ fn main() { let now = Instant::now(); let (diagnostics, post_check_data) = check_project::<_, synthesis::EznoParser>( - path.to_path_buf(), + vec![path.to_path_buf()], std::iter::once(ezno_checker::INTERNAL_DEFINITION_FILE_PATH.into()).collect(), |path: &std::path::Path| { if path == PathBuf::from(ezno_checker::INTERNAL_DEFINITION_FILE_PATH) { @@ -23,11 +23,12 @@ fn main() { } }, None, + (), ); let args: Vec<_> = env::args().collect(); - if let Ok(mut post_check_data) = post_check_data { + if let Ok(post_check_data) = post_check_data { if args.iter().any(|arg| arg == "--types") { eprintln!("Types:"); for (type_id, item) in post_check_data.types.into_vec_temp() { @@ -36,8 +37,7 @@ fn main() { } if args.iter().any(|arg| arg == "--events") { eprintln!("Events on entry:"); - let entry_module = - post_check_data.modules.remove(&post_check_data.entry_source).unwrap(); + let (_, entry_module) = post_check_data.modules.into_iter().next().unwrap(); for item in entry_module.facts.get_events() { eprintln!("\t{item:?}"); } @@ -51,10 +51,23 @@ fn main() { } else { eprintln!("Diagnostics:"); for diagnostic in diagnostics { - eprintln!("\t{}", diagnostic.reason()); - if let Diagnostic::PositionWithAdditionalLabels { labels, .. } = diagnostic { - for (label, _) in labels.iter() { - eprintln!("\t\t({})", label); + let prefix: char = match diagnostic.kind() { + ezno_checker::DiagnosticKind::Error => 'E', + ezno_checker::DiagnosticKind::Warning => 'W', + ezno_checker::DiagnosticKind::Info => 'I', + }; + match diagnostic { + Diagnostic::Global { reason, kind: _ } => { + eprintln!("\t{prefix}: {reason}"); + } + Diagnostic::Position { reason, position, kind: _ } => { + eprintln!("\t{prefix}: {reason} {position:?}"); + } + Diagnostic::PositionWithAdditionalLabels { reason, position, labels, kind: _ } => { + eprintln!("\t{prefix}: {reason} {position:?}"); + for (reason, position) in labels { + eprintln!("\t\t{reason} {position:?}"); + } } } } diff --git a/checker/specification/build.rs b/checker/specification/build.rs index 092ff4bf..c1fc3a7f 100644 --- a/checker/specification/build.rs +++ b/checker/specification/build.rs @@ -94,7 +94,7 @@ fn markdown_lines_append_test_to_rust( let mut errors = Vec::new(); for (_, line) in lines.by_ref() { if line.starts_with("#") { - panic!("block with no diagnostics or break between") + panic!("block with no diagnostics or break between in {test_title}") } else if line.starts_with('-') { let error = line.strip_prefix("- ").unwrap().replace('\\', "").replace('"', "\\\""); diff --git a/checker/specification/specification.md b/checker/specification/specification.md index 4d9c6fb6..0978a0f1 100644 --- a/checker/specification/specification.md +++ b/checker/specification/specification.md @@ -19,10 +19,10 @@ const z: object = 4 ```ts let x: number = 3 -x = "not a number" +x = "hello world" ``` -- Type "not a number" is not assignable to type number +- Type "hello world" is not assignable to type number #### Variable references @@ -37,11 +37,11 @@ const b: string = a ```ts let a = 2 -a = "not a number" -let b: number = a +a = "hello world" +let b: boolean = a ``` -- Type "not a number" is not assignable to type number +- Type "hello world" is not assignable to type boolean #### Variable references does not exist @@ -65,7 +65,7 @@ const a = 3; - Cannot redeclare variable a -#### Un-intialised variables are undefined +#### Unintialised variables are undefined > Might be a usage warning at some point @@ -76,28 +76,209 @@ b satisfies string; - Expected string, found undefined -### Generic types +### Properties -#### Generic interface +#### Property exists ```ts -interface Wrapper { - internal: T +let my_obj = { a: 3 } +const a = my_obj.a +const b = my_obj.b +``` + +- No property 'b' on { a: 3 } + +#### Property updates registered + +```ts +let my_obj = { a: 3 } +my_obj.a = 4 +let b: 3 = my_obj.a +``` + +- Type 4 is not assignable to type 3 + +#### Property references + +```ts +const my_obj = { a: 2 } +const three: 3 = my_obj.a +``` + +- Type 2 is not assignable to type 3 + +#### Object property constraints + +```ts +const my_obj: { a: number } = { a: 2 } +my_obj.a = "hello world" +``` + +- Type "hello world" does not meet property constraint number + +#### Objects checks + +```ts +const my_obj: { b: 3 } = { a: 2 } +``` + +- Type { a: 2 } is not assignable to type { b: 3 } + +#### Getters + +```ts +let global = 0; +const object = { + get getValue() { + return global++ + }, } -const my_wrapped: Wrapper = { internal: "hi" } +object.getValue satisfies string +object.getValue satisfies boolean ``` -- Type { internal: "hi" } is not assignable to type Wrapper\ +> Also test that side effects work here -#### Array property checking +- Expected string, found 0 +- Expected boolean, found 1 + +#### Object spread ```ts -const numbers1: Array = [1, 2, "3"] -const numbers2: Array = ["hi", "3"] +const obj1 = { a: 2, b: 3 }; +const obj2 = { b: 4, ...obj1, a: 6 }; + +obj2.b satisfies 100; +obj2.a satisfies boolean; ``` -- Type [1, 2, "3"] is not assignable to type Array\ +- Expected 100, found 3 +- Expected boolean, found 6 + +#### Set property with key + +```ts +const obj = { a: 2 } + +function setProperty(key: string, value) { + obj[key] = value; +} + +setProperty("b", 6) +obj satisfies string; +``` + +- Expected string, found { a: 2, b: 6 } + +#### Delete properties + +```ts +const x = { a: 2, b: 3 } +delete x.b; +const b = x.b; +``` + +- No property 'b' on { a: 2 } + +### Constant evaluation + +#### Arithmetic + +```ts +const x: 4 = 2 + 3 +const y: 6 = 2 * 3 +const z: 8 = (2 * 3) - 2 +``` + +- Type 5 is not assignable to type 4 +- Type 4 is not assignable to type 8 + +#### Bitwise arithmetic + +```ts +const x: 2 = 2 & 3 +const y: 6 = 2 ^ 7 +const z: 14 = 8 | 4 +``` + +- Type 5 is not assignable to type 6 +- Type 12 is not assignable to type 14 + +#### Logical operators + +```ts +const x: 2 = 3 && 2 +const y: 6 = 3 && false +const z: false = true || 4 +``` + +- Type false is not assignable to type 6 +- Type true is not assignable to type false + +#### Equality + +```ts +(4 === 2) satisfies true; +(4 !== 2) satisfies string; +``` + +- Expected true, found false +- Expected string, found true + +#### Inequality + +```ts +(Math.PI > 3) satisfies true; +(4 < 2) satisfies true; +(4 > 2) satisfies number; +(2 >= 2) satisfies string; +``` + +- Expected true, found false +- Expected number, found true +- Expected string, found true + +#### String operations (constant functions can use `this`) + +```ts +"hi".toUpperCase() satisfies number +``` + +- Expected number, found "HI" + +#### Math operations + +```ts +Math.cos(0) satisfies 0 +Math.sqrt(16) satisfies 1 +Math.floor(723.22) satisfies 2; +``` + +- Expected 0, found 1 +- Expected 1, found 4 +- Expected 2, found 723 + +#### Updating assignments + +```ts +let a = 5, b = 6; +a++; +a satisfies 4; +b *= 4; +b satisfies 23; +``` + +- Expected 4, found 6 +- Expected 23, found 24 + +#### Index into string + +```ts +("something"[2]) satisfies number; +``` + +- Expected number, found "m" ### Function checking @@ -132,32 +313,18 @@ func satisfies () => string - Expected () => string, found () => 2 -#### Generic type argument restriction +#### Set property on dependent observed ```ts -function map(a: T, b: (t: T) => U) { - return b(a) +function add_property(obj: { prop: number }) { + obj.prop = 2; + (obj.prop satisfies 4); } - -map(2, Math.sin) -map("string", Math.sin) ``` -- Argument of type "string" is not assignable to parameter of type number - -> Because `Math.sin` set T to number - -#### Parameters are always considered generic +> Not number -```ts -function id(a) { - return a -} - -const d: 3 = id(2) -``` - -- Type 2 is not assignable to type 3 +- Expected 4, found 2 #### Type checking basic function types @@ -237,25 +404,93 @@ const x: (a: string) => number = a => a.to; - No property 'to' on string +#### Expected argument from parameter declaration + +```ts +function map(a: (a: number) => number) {} + +// No annotation on `a`. But error comes from body +// (rather than parameter assignment) +map(a => a.t) +``` + +- No property 't' on number + +#### Assignment to parameter + +```ts +function alterParameter(a: number, b: { prop: string }) { + a = 2; + a = "hi"; + + b.prop = 3; + + // Observed + b.prop = "hello"; + b.prop satisfies "hello"; +} +``` + +> Assigning straight to `a` might be disallowed by an option in the future. Right now it is allowed by JavaScript and so is allowed + +- Type \"hi\" is not assignable to type number +- Type 3 does not meet property constraint string + +#### Type of rest parameter + +```ts +function myRestFunction(...r: string[]) { + r satisfies boolean; +} +``` + +- Expected boolean, found Array\ + +#### Destructuring parameter + +```ts +function myFunction({ a }: { a: number }) { + a satisfies boolean; + return a +} + +myFunction({ a: 6 }) satisfies string; +``` + +- Expected boolean, found number +- Expected string, found 6 + ### Function calling #### Argument type against parameter ```ts function func(a: number) {} -func("not a number") +func("hello world") ``` -- Argument of type "not a number" is not assignable to parameter of type number +- Argument of type "hello world" is not assignable to parameter of type number + +#### Parameters are always considered generic + +```ts +function id(a) { + return a +} + +const d: 3 = id(2) +``` + +- Type 2 is not assignable to type 3 #### Generic type argument parameter ```ts function func(a: T) {} -func("not a number") +func("hello world") ``` -- Argument of type "not a number" is not assignable to parameter of type number +- Argument of type "hello world" is not assignable to parameter of type number #### Get value of property on parameter @@ -322,6 +557,20 @@ call(Math.sqrt) satisfies 2 - Expected 2, found 3 +#### Constant call and operation with a parameter + +> An example of the generic constructor type (namely call and operation) + +```ts +function floorPlusB(a: number, b: number) { + return Math.floor(a) + b +} + +floorPlusB(100.22, 5) satisfies 8 +``` + +- Expected 8, found 105 + #### This in object literal ```ts @@ -350,68 +599,83 @@ function getToUpperCase(s: string) { - Expected "HEY", found "HI" -### Closures +#### This as generic argument -#### Reading variable +```ts +function callToUpperCase(s: string) { + return s.toUpperCase() +} + +(callToUpperCase("hi") satisfies "HEY") +``` + +- Expected "HEY", found "HI" + +#### Calling new on a function ```ts -function kestrel(a) { - return function (_b) { - return a - } +function MyClass(value) { + this.value = value } -kestrel(3)(2) satisfies 4 +new MyClass("hi").value satisfies "hello" ``` -- Expected 4, found 3 +- Expected "hello", found "hi" -#### Nesting +#### Arguments in to rest parameter ```ts -function kestrel2(a) { - return _b => _c => a +function myRestFunction(...r: string[]) { + return r[0] + r[1] } -kestrel2(3)(2)(6) satisfies 4 +myRestFunction("hello ", "world") satisfies number; ``` -- Expected 4, found 3 +- Expected number, found "hello world" -#### Carry across objects +#### Default parameter ```ts -function magicNumber(a: number) { - return { - plusOne() { return a + 1 }, - doubled() { return 2 * a } - } +function withDefault(x: number = 1) { + return x } -const myNumber = magicNumber(4); -myNumber.plusOne() satisfies 5 -myNumber.doubled() satisfies 6 +withDefault() satisfies 2; +withDefault(3) satisfies 3; ``` -- Expected 6, found 8 +- Expected 2, found 1 -#### Stateful +#### Default parameter side effect ```ts -function myClosure(a) { - return { - getValue() { return a }, - setValue(b) { a = b } - } +let b: number = 0 +function doThing(a = (b += 2)) { + return a } -const value = myClosure(4); -value.getValue() satisfies 4; -value.setValue(10); -value.getValue() satisfies 6 +doThing("hello"); +b satisfies 0; +doThing(); +b satisfies 1; ``` -- Expected 6, found 10 +- Expected 1, found 2 + +#### Tagged template literal + +```ts +function myTag(static_parts: Array, name: string) { + return static_parts[0] + name +} + +const name = "Ben"; +myTag`${name}Hello ` satisfies "Hi Ben" +``` + +- Expected "Hi Ben", found "Hello Ben" ### Effects @@ -423,7 +687,8 @@ value.getValue() satisfies 6 let a: number = 0 function func() { a = 4; - // Important that subsequent reads use the new value, not the same free variable + // Important that subsequent reads use the + // new value, not the same free variable a satisfies 4; } @@ -462,20 +727,6 @@ obj.a satisfies 3 - Expected 3, found 4 -#### Constant call and operation with a parameter - -> An example of the generic constructor type (namely call and operation) - -```ts -function sinPlusB(a: number, b: number) { - return Math.floor(a) + b -} - -sinPlusB(100.22, 5) satisfies 8 -``` - -- Expected 8, found 105 - #### Effects carry through dependent calls ```ts @@ -544,268 +795,157 @@ setAtoString(myObject); > Error could be better. Full one contains labels with more information -- Assignment mismatch - -#### Mutating an object by a function - -> This is where the object loses its constant-ness - -```ts -function doThingWithCallback(callback: (obj: { x: number }) => any) { - const obj: { x: number } = { x: 8 }; - callback(obj); - (obj.x satisfies 8); - return obj; -} - -const object = doThingWithCallback((obj: { x: number }) => obj.x = 2); -(object.x satisfies string); -``` - -- Expected 8, found number -- Expected string, found 2 - -#### Assigning to parameter observed via effect - -```ts -function add_property(obj: { prop: number }) { - obj.prop += 2; -} - -const obj = { prop: 4 }; -add_property(obj); -(obj.prop satisfies 8); -``` - -- Expected 8, found 6 - -### Constant evaluation - -#### Arithmetic - -```ts -const x: 4 = 2 + 3 -const y: 6 = 2 * 3 -const z: 8 = (2 * 3) - 2 -``` - -- Type 5 is not assignable to type 4 -- Type 4 is not assignable to type 8 - -#### Bitwise arithmetic - -```ts -const x: 2 = 2 & 3 -const y: 6 = 2 ^ 7 -const z: 14 = 8 | 4 -``` - -- Type 5 is not assignable to type 6 -- Type 12 is not assignable to type 14 - -#### Logical operators - -```ts -const x: 2 = 3 && 2 -const y: 6 = 3 && false -const z: false = true || 4 -``` - -- Type false is not assignable to type 6 -- Type true is not assignable to type false - -#### Equality - -```ts -(4 === 2) satisfies true; -(4 !== 2) satisfies string; -``` - -- Expected true, found false -- Expected string, found true - -#### Inequality - -```ts -(Math.PI > 3) satisfies true; -(4 < 2) satisfies true; -(4 > 2) satisfies number; -(2 >= 2) satisfies string; -``` - -- Expected true, found false -- Expected number, found true -- Expected string, found true - -#### String operations (constant functions can use `this`) - -```ts -"hi".toUpperCase() satisfies number -``` - -- Expected number, found "HI" - -#### Math operations - -```ts -Math.cos(0) satisfies 0; -Math.sqrt(16) satisfies 1; -Math.floor(723.22) satisfies 2 -``` - -- Expected 0, found 1 -- Expected 1, found 4 -- Expected 2, found 723 - -#### Updating assignments +- Assignment mismatch + +#### Property assignment from conditional ```ts -let a = 5, b = 6; -a++; -a satisfies 4; -b *= 4; -b satisfies 23; +function getObject(condition: boolean) { + const mainObject = { a: 2 }; + const object = condition ? mainObject : { b: 3 }; + object.c = 4; + mainObject.c satisfies string; + return mainObject +} ``` -- Expected 4, found 6 -- Expected 23, found 24 +- Expected string, found 4 -### Objects +#### Mutating an object by a function -#### Property exists +> This is where the object loses its constant-ness ```ts -let my_obj = { a: 3 } -const a = my_obj.a -const b = my_obj.b +function doThingWithCallback(callback: (obj: { x: number }) => any) { + const obj: { x: number } = { x: 8 }; + callback(obj); + (obj.x satisfies 8); + return obj; +} + +const object = doThingWithCallback((obj: { x: number }) => obj.x = 2); +(object.x satisfies string); ``` -- No property 'b' on { a: 3 } +- Expected 8, found number +- Expected string, found 2 -#### Property updates registered +#### Assigning to parameter observed via effect ```ts -let my_obj = { a: 3 } -my_obj.a = 4 -let b: 3 = my_obj.a +function add_property(obj: { prop: number }) { + obj.prop += 2; +} + +const obj = { prop: 4 }; +add_property(obj); +(obj.prop satisfies 8); ``` -- Type 4 is not assignable to type 3 +- Expected 8, found 6 -#### Property references +#### Functions create objects ```ts -const my_obj = { a: 2 } -const three: 3 = my_obj.a +function newObject() { + return { prop: 2 } +} + +const a = newObject(), b = newObject(); +const c = a; +(a === c) satisfies false; +(a === b) satisfies string; ``` -- Type 2 is not assignable to type 3 +- Expected false, found true +- Expected string, found false -#### Object property constraints +### Closures + +#### Reading variable ```ts -const my_obj: { a: number } = { a: 2 } -my_obj.a = "not a number" +function kestrel(a) { + return function (_b) { + return a + } +} + +kestrel(3)(2) satisfies 4 ``` -- Type "not a number" does not meet property constraint number +- Expected 4, found 3 -#### Objects checks +#### Nesting ```ts -const my_obj: { b: 3 } = { a: 2 } +function kestrel2(a) { + return _b => _c => a +} + +kestrel2(3)(2)(6) satisfies 4 ``` -- Type { a: 2 } is not assignable to type { b: 3 } +- Expected 4, found 3 -#### Getters +#### Carry across objects ```ts -let global = 0; -const object = { - get getValue() { - return global++ - }, +function magicNumber(a: number) { + return { + plusOne() { return a + 1 }, + doubled() { return 2 * a } + } } -object.getValue satisfies string -object.getValue satisfies boolean +const myNumber = magicNumber(4); +myNumber.plusOne() satisfies 5 +myNumber.doubled() satisfies 6 ``` -> Also test that side effects work here - -- Expected string, found 0 -- Expected boolean, found 1 +- Expected 6, found 8 -#### Object spread +#### Stateful ```ts -const obj1 = { a: 2, b: 3 }; -const obj2 = { b: 4, ...obj1, a: 6 }; +function myClosure(a) { + return { + getValue() { return a }, + setValue(b) { a = b } + } +} -obj2.b satisfies 100; -obj2.a satisfies boolean; +const value = myClosure(4); +value.getValue() satisfies 4; +value.setValue(10); +value.getValue() satisfies 6 ``` -- Expected 100, found 3 -- Expected boolean, found 6 +- Expected 6, found 10 -#### Array pushing and pop-ing +### Collection types -> TODO maybe separate +#### Array push ```ts const x = [1] x.push("hi") x[1] satisfies 3 x.length satisfies 4; -x.pop() satisfies "hi"; -x.length satisfies 1; ``` - Expected 3, found "hi" - Expected 4, found 2 -#### Functions create objects - -```ts -function newObject() { - return { prop: 2 } -} - -const a = newObject(), b = newObject(); -const c = a; -(a === c) satisfies false; -(a === b) satisfies string; -``` - -- Expected false, found true -- Expected string, found false - -#### Set property with key - -```ts -const obj = { a: 2 } - -function setProperty(key: string, value) { - obj[key] = value; -} - -setProperty("b", 6) -obj satisfies string; -``` - -- Expected string, found { a: 2, b: 6 } - -#### Delete properties +#### Array pop ```ts -const x = { a: 2, b: 3 } -delete x.b; -const b = x.b; +const myArray = [6, "hi"] +myArray.pop() satisfies 3; +myArray.length satisfies 1; ``` -- No property 'b' on { a: 2 } +- Expected 3, found "hi" ### Control flow @@ -857,7 +997,7 @@ a satisfies string - Expected string, found "hi" | 0 -#### If else +#### If and else (across function) ```ts function print_number(value: number) { @@ -996,6 +1136,20 @@ while (a < i) { > Important that type is widened to 'number' (think it is an open poly in this case) +#### Limit to iterations + +```ts +let a: number = 0; +while (a++ < 1_000_000) {} + +a satisfies string; +``` + +> The important part is that it doesn't run the loop. Eventually this might be run in a way that is not calling the assign to variable +> function that evaluates `a = a + 1` a million times. There also should be per project, per module, per loop configuration + +- Expected string, found number + #### While loop unrolling as an effect ```ts @@ -1030,6 +1184,29 @@ while (i++ < 10) { - Expected 2, found 8 +#### Break with label + +```ts +let a: number = 0; +let result; + +top: while (a++ < 10) { + let b: number = 0; + while (b++ < 10) { + if (a === 3 && b === 2) { + result = a * b; + break top + } + } +} + +a satisfies string; +result satisfies boolean; +``` + +- Expected string, found 3 +- Expected boolean, found 6 + #### Continue in a while loop > With the continue the update to `a` only happens on even runs (5 times) @@ -1071,7 +1248,7 @@ const x: X = { a: 2, b: false } ```ts type MyNumber = number; "hi" satisfies MyNumber; -4 satisfies MyNumber +4 satisfies MyNumber; ``` - Expected MyNumber, found "hi" @@ -1079,12 +1256,62 @@ type MyNumber = number; #### Declare variable ```ts -declare var global_number: number +declare const global_number: number const my_number: string = global_number ``` - Type number is not assignable to type string +#### Function (and interface) hoisting + +> Using functions and interface **before** their position of declaration in the source + +```ts +getFive() satisfies 4; + +function getFive() { + return 5 +} + +let x: X = { a: 3 } + +interface X { + a: 2 +} +``` + +- Expected 4, found 5 +- Type { a: 3 } is not assignable to type X + +#### RegExp + +> RegExp = Regular expression +> In the future, their definition could be considered and evaluated at runtime + +```ts +/hi/ satisfies string; +``` + +- Expected string, found /hi/ + +#### Null and undefined + +```ts +undefined satisfies null; +null satisfies undefined; +``` + +- Expected null, found undefined +- Expected undefined, found null + +#### void operator + +```ts +(void 2) satisfies string; +``` + +- Expected string, found undefined + #### (untagged) Template literal ```ts @@ -1420,19 +1647,47 @@ getA({ p: 2 }) > I think reasons contains more information -#### Function subtyping +#### Function parameter subtyping ```ts // Perfectly fine -const x: (a: number) => string = (a: 4) => "hi" +const x: (a: number) => string = (p: string | number) => "hi" // Bad -const y: (a: 4) => string = (a: number) => "hi" +const y: (a: number | string) => string = (p: number) => "hi" ``` -- Type (a: number) => "hi" is not assignable to type (a: 4) => string +- Type (p: number) => "hi" is not assignable to type (a: number | string) => string > I think reasons contains more information +#### Function return type subtyping + +```ts +const x: (a: number) => number = p => 4 +const y: (a: number) => number = p => "a number" +``` + +- Type (p: number) => "a number" is not assignable to type (a: number) => number + +#### `void` return type + +> This works similarly to undefined except that it accepts any function return type + +```ts +function runWithCallback(cb: () => void): void { + cb() satisfies string; + + return 5; +} + +runWithCallback(() => 3) +``` + +> Here argument is fine. In the body the return type is `any` (inferred constraint, but doesn't matter) + +- Expected string, found any +- Cannot return 5 because the function is expected to return void + #### Indexing into (fixed) type ```ts @@ -1487,13 +1742,28 @@ function getSecondCharacter(s: string) { - Expected boolean, found (s: string) => string | undefined - Expected "b", found "t" -#### Index into string +### Generic types + +#### Generic interface ```ts -("something"[2] satisfies number); +interface Wrapper { + internal: T +} + +const my_wrapped: Wrapper = { internal: "hi" } ``` -- Expected number, found "m" +- Type { internal: "hi" } is not assignable to type Wrapper\ + +#### Array property checking + +```ts +const numbers1: Array = [1, 2, "3"] +const numbers2: Array = ["hi", "3"] +``` + +- Type [1, 2, "3"] is not assignable to type Array\ ### Prototypes @@ -1516,7 +1786,7 @@ const p = { b: 2 } Object.setPrototypeOf(x, p); const p_of_x = Object.getPrototypeOf(x); // ('a' in p_of_x.a) satisfies false; -p === p_of_x satisfies string; +(p === p_of_x) satisfies string; ``` - Expected string, found true @@ -1584,6 +1854,21 @@ export type MyNumber = string; - Expected MyNumber, found 2 +#### Import type and variable + +```ts +import { MyNumber } from "./types"; +2 satisfies MyNumber; +MyNumber satisfies boolean; + +// in types.ts +export type MyNumber = string; +export const MyNumber = 6; +``` + +- Expected MyNumber, found 2 +- Expected boolean, found 6 + #### Export let ```ts diff --git a/checker/specification/test.rs b/checker/specification/test.rs index 72ea11cf..623ab3bf 100644 --- a/checker/specification/test.rs +++ b/checker/specification/test.rs @@ -53,7 +53,7 @@ fn check_errors( // let result = panic::catch_unwind(|| { let result = checker::check_project::<_, EznoParser>( - PathBuf::from("main.ts"), + vec![PathBuf::from("main.ts")], std::iter::once(checker::INTERNAL_DEFINITION_FILE_PATH.into()).collect(), |path| { if path == std::path::Path::new(checker::INTERNAL_DEFINITION_FILE_PATH) { @@ -68,6 +68,7 @@ fn check_errors( } }, type_check_options, + (), ); // }); diff --git a/checker/specification/to_implement.md b/checker/specification/to_implement.md index a0ec8387..8b1c0a98 100644 --- a/checker/specification/to_implement.md +++ b/checker/specification/to_implement.md @@ -27,33 +27,34 @@ function add_property(obj: { prop: number }) { - Expected 4, found 2 -#### Calling on or type +#### Generic type argument restriction ```ts -type Func1 = () => 3; -type Func2 = () => 2; -function callFunc(func: (() => T) | (() => U)): 3 | 2 { - return func() +function map(a: T, b: (t: T) => U) { + return b(a) } -print_type(callFunc) +map(2, Math.sin) +map("string", Math.sin) ``` -- Expected "a" | "b" | "c" found "d" +- Argument of type "string" is not assignable to parameter of type number -#### This as generic argument +> Because `Math.sin` set T to number -> Was working, now broken for some reason :( +#### Calling on or type ```ts -function callToUpperCase(s: string) { - return s.toUpperCase() +type Func1 = () => 3; +type Func2 = () => 2; +function callFunc(func: (() => T) | (() => U)): 3 | 2 { + return func() } -(callToUpperCase("hi") satisfies "HEY") +print_type(callFunc) ``` -- Expected "HEY", found "HI" +- Expected "a" | "b" | "c" found "d" #### Symmetric or @@ -142,62 +143,81 @@ if (a === "hi") { - Expected "hello", found "hi" -### Looping +### This -#### For loops +#### Bind function ```ts -function func(array: Array) { - for (const item of array) { - item satisfies number - } +function ChangeThis(this: { value: any }) { + return this.value } + +const x = ChangeThis.bind({ value: 2 }) +x() satisfies 3 ``` -- Expected number found string +- Expected 3, found 2 + +### Iteration -#### Constant loops +#### For-in fixed object ```ts -function join(array: Array) { - let buf = "" - for (let item of array) { - buf += item - } - return buf +let properties: string = ""; +for (const property in { a: 1, b: 2, c: 3 }) { + properties += property; } - -join(["a", "b", "c"]) satisfies "cba" +properties satisfies boolean; ``` -- Expected "cba" found "abc" +- Expected boolean, found "abc" -### This +#### For-in non fixed object -#### Calling new on a function +> TypeScript anonymous object annotations do not guarantee ordering and the subtyping rules allow for the RHS to have more +> properties than defined ```ts -function MyClass(value) { - this.value = value +declare const myObject: { a: 1, b: 2, c: 3 }; + +let properties: string = ""; +for (const property in myObject) { + properties += property; } +properties satisfies boolean; +``` + +- Expected boolean, found string + +> TODO for in and generators + +#### For loops -new MyClass("hi").value satisfies "hello" +```ts +function func(array: Array) { + for (const item of array) { + item satisfies number + } +} ``` -- Expected "hello", found "hi" +- Expected number found string -#### Bind function +#### Constant for loop ```ts -function ChangeThis(this: { value: any }) { - return this.value +function join(array: Array) { + let buf = "" + for (let item of array) { + buf += item + } + return buf } -const x = ChangeThis.bind({ value: 2 }) -x() satisfies 3 +join(["a", "b", "c"]) satisfies "cba" ``` -- Expected 3, found 2 +- Expected "cba" found "abc" ### Inference @@ -238,7 +258,7 @@ x = 0 call() satisfies 2 ``` -- Cannot call ... +- Cannot call TODO - Expected 2 found 1 #### Property restriction @@ -254,7 +274,7 @@ print_type(call) ### Asynchronous functions and promises -#TODO promise +> TODO Promise properties #### Async function @@ -300,13 +320,11 @@ function x*() { (await x) satisfies string; ``` -- #TODO +- TODO -### Proxy and Object +### `Proxy` and `Object` -#TODO effects -#TODO traps -#TODO Object.defineProperty +> TODO effects, different traps and `Object.defineProperty` #### Proxy object with default callback @@ -331,6 +349,8 @@ a.prop3 satisfies "prop2" ### Collections +> TODO filter, every and all, find, etc + #### Simple array map ```ts @@ -341,6 +361,8 @@ function mapper(a: Array) { print_type(mapper) ``` +- TODO + #### Generic array map ```ts @@ -351,20 +373,9 @@ function mapper(a: Array, func: T => U) { print_type(mapper) ``` -### Expressions - -#### Statements, declarations and expressions - -```ts -function myTag(static_parts: Array, first_name: string) { - return first_name + static_parts[0] -} - -const name = "Ben"; -myTag`Hello ${name}` satisfies "Hi Ben" -``` +- TODO -- Expected "Hi Ben", found "Hello Ben" +### Expressions #### Bad arithmetic operator @@ -378,33 +389,6 @@ console + 2 - Expected number, found Console -#### Expected argument - -> Requires synthesising arguments later ...? - -```ts -function map(a: (a: number) => number) {} - -map(a => a.t) -``` - -> No property t on string - -#### Spread arguments - -```ts -function spread(main, ...others) { - return { - main, - others, - } -} - -spread(1, 2, 3) satisfies string -``` - -- TODO... - #### Array spread ```ts @@ -419,7 +403,16 @@ array2[2] satisfies string; ### Classes -> TODO extends +#### Extends + +```ts +class BaseClass extends class { x: 2 } { + y: 3 +} + +const b = new BaseClass; +print_type(b.x); +``` #### Privacy @@ -438,3 +431,38 @@ class MyClass { - Cannot get private property "#a" - Expected 3, found 2 + +### Recursion + +#### Application + +```ts +function x(a: number) { + if (a > 10 || a < 0) { + return a + } + return a-- +} + +print_type(x(4)) +print_type(x(90)) +``` + +- TODO + +### Function checking + +#### Default parameter side effect on parameter + +> I don't think this works because of fact combining + +```ts +function doThing(a, b = (a += 2)) { + return a +} + +doThing(3) satisfies 2; +doThing(6, 1) satisfies 6; +``` + +- Expected 2, found 5 diff --git a/checker/src/behavior/modules.rs b/checker/src/behavior/modules.rs deleted file mode 100644 index 26f280b9..00000000 --- a/checker/src/behavior/modules.rs +++ /dev/null @@ -1,61 +0,0 @@ -use super::variables::VariableMutability; -use crate::{context::facts::Facts, TypeId, VariableId}; - -use source_map::Span; - -#[derive(Debug)] -pub struct NamePair<'a> { - pub value: &'a str, - pub r#as: &'a str, - pub position: Span, -} - -pub enum ImportKind<'a, T: Iterator>> { - Parts(T), - All { - under: &'a str, - position: Span, - }, - /// From `export * from ...` - Everything, -} - -pub struct SynthesisedModule { - pub content: M, - pub exported: Exported, - /// TODO ... - pub facts: Facts, -} - -/// TODO tidy -#[derive(Clone, Debug, Default, binary_serialize_derive::BinarySerializable)] -pub struct Exported { - pub default: Option, - pub named: Vec<(String, (VariableId, VariableMutability))>, - pub named_types: Vec<(String, TypeId)>, -} - -pub enum TypeOrVariable { - ExportedVariable((VariableId, VariableMutability)), - Type(TypeId), -} - -impl Exported { - pub(crate) fn get_export(&self, want: &str) -> Option { - self.named - .iter() - .find_map(|(export, value)| { - (export == want).then_some(TypeOrVariable::ExportedVariable((value.0, value.1))) - }) - .or_else(|| { - self.named_types.iter().find_map(|(export, value)| { - (export == want).then_some(TypeOrVariable::Type(*value)) - }) - }) - } -} - -/// After a syntax error -pub struct InvalidModule; - -pub type FinalModule = Result, InvalidModule>; diff --git a/checker/src/context/calling.rs b/checker/src/context/calling.rs deleted file mode 100644 index 116ac5de..00000000 --- a/checker/src/context/calling.rs +++ /dev/null @@ -1,98 +0,0 @@ -use super::facts::Facts; -use crate::{events::EventResult, Environment, FunctionId}; - -/// For anything that might involve a call, including gets, sets and actual calls -pub(crate) trait CallCheckingBehavior { - // TODO - const CHECK_PARAMETERS: bool; - - fn get_latest_facts<'a>(&'a mut self, environment: &'a mut Environment) -> &'a mut Facts; - - fn in_recursive_cycle(&self, function_id: FunctionId) -> bool; - - fn new_function_target( - &mut self, - function_id: FunctionId, - cb: impl for<'a> FnOnce(&'a mut Target) -> T, - ) -> T; -} - -pub struct CheckThings; - -impl CallCheckingBehavior for CheckThings { - const CHECK_PARAMETERS: bool = true; - - fn get_latest_facts<'a>(&'a mut self, environment: &'a mut Environment) -> &'a mut Facts { - &mut environment.facts - } - - fn in_recursive_cycle(&self, _function_id: FunctionId) -> bool { - // cannot get in a loop from checking - false - } - - fn new_function_target( - &mut self, - function_id: FunctionId, - cb: impl for<'a> FnOnce(&'a mut Target) -> T, - ) -> T { - let mut target = Target(vec![TargetKind::Function(function_id)]); - cb(&mut target) - } -} - -pub(crate) struct Target(Vec); - -pub(crate) enum TargetKind { - Conditional(Facts), - Function(FunctionId), -} - -impl CallCheckingBehavior for Target { - const CHECK_PARAMETERS: bool = false; - - fn get_latest_facts<'b>(&'b mut self, environment: &'b mut Environment) -> &'b mut Facts { - self.0 - .iter_mut() - .rev() - .find_map( - |kind| if let TargetKind::Conditional(facts) = kind { Some(facts) } else { None }, - ) - .unwrap_or(&mut environment.facts) - } - - fn in_recursive_cycle(&self, function_id: FunctionId) -> bool { - self.0.iter().any(|kind| matches!(kind, TargetKind::Function(id) if function_id == *id)) - } - - fn new_function_target( - &mut self, - function_id: FunctionId, - cb: impl for<'a> FnOnce(&'a mut Target) -> T, - ) -> T { - self.0.push(TargetKind::Function(function_id)); - let value = cb(self); - self.0.pop(); - value - } -} - -impl Target { - /// TODO temp for loop unrolling - pub(crate) fn new_default() -> Self { - Target(Vec::new()) - } - - pub(crate) fn new_conditional_target( - &mut self, - cb: impl for<'a> FnOnce(&'a mut Target) -> Option, - ) -> (Facts, Option) { - self.0.push(TargetKind::Conditional(Facts::default())); - let result = cb(self); - if let Some(TargetKind::Conditional(facts)) = self.0.pop() { - (facts, result) - } else { - unreachable!() - } - } -} diff --git a/checker/src/context/environment.rs b/checker/src/context/environment.rs index 3eba3e59..9d8fe486 100644 --- a/checker/src/context/environment.rs +++ b/checker/src/context/environment.rs @@ -2,18 +2,18 @@ use source_map::{SourceId, Span, SpanWithSource}; use std::collections::HashSet; use crate::{ - behavior::{ + diagnostics::{NotInLoopOrCouldNotFindLabel, TypeCheckError, TypeStringRepresentation, TDZ}, + events::{Event, FinalEvent, RootReference}, + features::{ assignments::{Assignable, AssignmentKind, Reference}, functions, - modules::{Exported, ImportKind, NamePair}, + modules::Exported, operations::{ evaluate_logical_operation_with_expression, evaluate_pure_binary_operation_handle_errors, MathematicalAndBitwise, }, variables::{VariableMutability, VariableOrImport, VariableWithValue}, }, - diagnostics::{NotInLoopOrCouldNotFindLabel, TypeCheckError, TypeStringRepresentation, TDZ}, - events::{Event, RootReference}, subtyping::BasicEquality, types::{ is_type_truthy_falsy, @@ -25,7 +25,7 @@ use crate::{ }; use super::{ - calling::CheckThings, facts::Publicity, get_on_ctx, get_value_of_variable, AssignmentError, + facts::Publicity, get_on_ctx, get_value_of_variable, invocation::CheckThings, AssignmentError, ClosedOverReferencesInScope, Context, ContextType, Environment, GeneralContext, SetPropertyError, }; @@ -49,6 +49,20 @@ pub struct Syntax<'a> { pub location: ContextLocation, } +/// Code under a dynamic boundary can run more than once +#[derive(Debug, Clone, Copy)] +pub enum DynamicBoundaryKind { + Loop, + Function, +} + +impl DynamicBoundaryKind { + #[must_use] + pub fn can_use_variable_before_definition(self) -> bool { + matches!(self, Self::Function) + } +} + impl<'a> ContextType for Syntax<'a> { fn as_general_context(et: &Context) -> GeneralContext<'_> { GeneralContext::Syntax(et) @@ -58,8 +72,12 @@ impl<'a> ContextType for Syntax<'a> { Some(&self.parent) } - fn is_dynamic_boundary(&self) -> bool { - matches!(self.scope, Scope::Function { .. } | Scope::Looping { .. }) + fn is_dynamic_boundary(&self) -> Option { + match &self.scope { + Scope::Function { .. } => Some(DynamicBoundaryKind::Function), + Scope::Iteration { .. } => Some(DynamicBoundaryKind::Loop), + _ => None, + } } fn is_conditional(&self) -> bool { @@ -121,6 +139,7 @@ pub enum Scope { InterfaceEnvironment { this_constraint: TypeId, }, + DefaultFunctionParameter {}, FunctionAnnotation {}, /// For ifs, elses, or lazy operators Conditional { @@ -130,7 +149,7 @@ pub enum Scope { is_switch: Option