From effcc5faf522e8d32375dcae0be9c7fd08364aee Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Sat, 4 Jan 2025 01:45:06 +0100 Subject: [PATCH 01/12] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/6c90912761c43e22b6fb000025ab96dd31c971ff' (2024-12-23) → 'github:NixOS/nixpkgs/edf04b75c13c2ac0e54df5ec5c543e300f76f1c9' (2024-12-31) • Updated input 'rust-overlay': 'github:oxalica/rust-overlay/550e1f10be4a504747a7894c35e887e61235763b' (2024-12-26) → 'github:oxalica/rust-overlay/a599f011db521766cbaf7c2f5874182485554f00' (2025-01-03) --- flake.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/flake.lock b/flake.lock index d957253c..87d3e9b5 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1733261153, - "narHash": "sha256-eq51hyiaIwtWo19fPEeE0Zr2s83DYMKJoukNLgGGpek=", + "lastModified": 1735669367, + "narHash": "sha256-tfYRbFhMOnYaM4ippqqid3BaLOXoFNdImrfBfCp4zn0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "b681065d0919f7eb5309a93cea2cfa84dec9aa88", + "rev": "edf04b75c13c2ac0e54df5ec5c543e300f76f1c9", "type": "github" }, "original": { @@ -48,11 +48,11 @@ ] }, "locked": { - "lastModified": 1733366051, - "narHash": "sha256-Zlas3LFqrW8bVVrZYgkzS4VNkZgtZ/hsbYhO0GtKLys=", + "lastModified": 1735871325, + "narHash": "sha256-6Ta5E4mhSfCP6LdkzkG2+BciLOCPeLKuYTJ6lOHW+mI=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "ba5ed0362eaae83fe8925a2d5cfcf356ff22f70f", + "rev": "a599f011db521766cbaf7c2f5874182485554f00", "type": "github" }, "original": { From b58afe44195cf6e95abd182296b483c62609b9b7 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Sat, 4 Jan 2025 01:49:44 +0100 Subject: [PATCH 02/12] Run clippy against the whole workspace --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 4cefaafe..9496a0ea 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -39,7 +39,7 @@ jobs: with: components: clippy rust-version: nightly - - run: cargo clippy --all-targets --verbose + - run: cargo clippy --all-targets --workspace --verbose rustfmt: name: Verify code formatting From 9ab0c192a04604a03c5feaf42ff29270495b3aa2 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Thu, 26 Dec 2024 08:59:06 +0100 Subject: [PATCH 03/12] Update crates Signed-off-by: Maximilian Marx --- Cargo.lock | 298 +++++++++++++++++++++-------------------------------- 1 file changed, 116 insertions(+), 182 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f7d3cd39..f7ca041d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,9 +104,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" [[package]] name = "arbitrary" @@ -179,7 +179,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -207,7 +207,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -330,9 +330,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.2" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" dependencies = [ "shlex", ] @@ -380,9 +380,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.22" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", @@ -390,9 +390,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.22" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ "anstream", "anstyle", @@ -409,14 +409,14 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" @@ -426,12 +426,12 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -491,9 +491,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -510,9 +510,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "csv" @@ -556,7 +556,7 @@ checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -567,7 +567,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -605,7 +605,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -637,7 +637,7 @@ checksum = "4f4b100e337b021ae69f3e7dd82e230452c54ff833958446c4a3854c66dc9326" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -649,14 +649,14 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "env_filter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -677,9 +677,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0" dependencies = [ "anstream", "anstyle", @@ -727,9 +727,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fixedbitset" @@ -749,9 +749,9 @@ dependencies = [ [[package]] name = "float-cmp" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" dependencies = [ "num-traits", ] @@ -764,9 +764,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -854,7 +854,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1079,9 +1079,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", @@ -1099,9 +1099,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http", @@ -1264,7 +1264,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1384,9 +1384,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" @@ -1470,7 +1470,7 @@ version = "0.0.1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1521,9 +1521,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" dependencies = [ "adler2", ] @@ -1568,7 +1568,7 @@ dependencies = [ "csv", "dyn-clone", "enum-assoc", - "env_logger 0.11.5", + "env_logger 0.11.6", "flate2", "getrandom", "log", @@ -1596,7 +1596,7 @@ dependencies = [ "strum", "strum_macros", "test-log", - "thiserror 2.0.4", + "thiserror 2.0.9", "tokio", "tower-lsp", "unicode-ident", @@ -1609,16 +1609,16 @@ dependencies = [ "ariadne", "assert_cmd", "assert_fs", - "clap 4.5.22", + "clap 4.5.23", "colored", "dir-test", - "env_logger 0.11.5", + "env_logger 0.11.6", "log", "nemo", "predicates", "serde_json", "test-log", - "thiserror 2.0.4", + "thiserror 2.0.9", ] [[package]] @@ -1645,7 +1645,7 @@ dependencies = [ "bitvec", "delegate", "enum_dispatch", - "env_logger 0.11.5", + "env_logger 0.11.6", "flate2", "hashbrown 0.14.5", "howlong", @@ -1662,7 +1662,7 @@ dependencies = [ "reqwest", "streaming-iterator", "test-log", - "thiserror 2.0.4", + "thiserror 2.0.9", "unicode-segmentation", ] @@ -1685,7 +1685,7 @@ dependencies = [ "nemo", "nemo-language-server", "nemo-physical", - "thiserror 2.0.4", + "thiserror 2.0.9", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test", @@ -1843,9 +1843,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] @@ -1879,7 +1879,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -1917,9 +1917,9 @@ dependencies = [ [[package]] name = "oxiri" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038e706f26b00e3981cd08bfd300dbe82f635ea95a263d492c6ccaeb3d1c582" +checksum = "6628603228a6483668f78b29dc400a33ff1444dd5eae0504e40b6ba3bf7d01de" [[package]] name = "parking_lot" @@ -1999,7 +1999,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2037,9 +2037,9 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.2" +version = "3.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" dependencies = [ "anstyle", "difflib", @@ -2051,15 +2051,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" +checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" [[package]] name = "predicates-tree" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" dependencies = [ "predicates-core", "termtree", @@ -2121,7 +2121,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2134,7 +2134,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2170,9 +2170,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] @@ -2224,9 +2224,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ "bitflags 2.6.0", ] @@ -2376,22 +2376,22 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" dependencies = [ "bitflags 2.6.0", "errno 0.3.10", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" dependencies = [ "once_cell", "rustls-pki-types", @@ -2411,9 +2411,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" [[package]] name = "rustls-webpki" @@ -2489,9 +2489,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" dependencies = [ "core-foundation-sys", "libc", @@ -2499,29 +2499,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr", @@ -2537,7 +2537,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2644,7 +2644,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2666,9 +2666,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" dependencies = [ "proc-macro2", "quote", @@ -2692,7 +2692,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2752,9 +2752,9 @@ dependencies = [ [[package]] name = "termtree" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] name = "test-log" @@ -2762,7 +2762,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dffced63c2b5c7be278154d76b479f9f9920ed34e7574201407f0b14e2bbb93" dependencies = [ - "env_logger 0.11.5", + "env_logger 0.11.6", "test-log-macros", "tracing-subscriber", ] @@ -2775,7 +2775,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2804,11 +2804,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "f072643fd0190df67a8bab670c20ef5d8737177d6ac6b2e9a236cb096206b2cc" dependencies = [ - "thiserror-impl 2.0.4", + "thiserror-impl 2.0.9", ] [[package]] @@ -2819,18 +2819,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2877,7 +2877,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2964,7 +2964,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -2992,7 +2992,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -3179,7 +3179,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "wasm-bindgen-shared", ] @@ -3213,7 +3213,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3247,7 +3247,7 @@ checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -3339,15 +3339,6 @@ 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]] name = "windows-sys" version = "0.52.0" @@ -3381,21 +3372,6 @@ dependencies = [ "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]] name = "windows-targets" version = "0.52.6" @@ -3418,12 +3394,6 @@ 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.6" @@ -3436,12 +3406,6 @@ 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.6" @@ -3454,12 +3418,6 @@ 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.6" @@ -3478,12 +3436,6 @@ 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.6" @@ -3496,12 +3448,6 @@ 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.6" @@ -3514,12 +3460,6 @@ 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.6" @@ -3532,12 +3472,6 @@ version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3597,7 +3531,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "synstructure", ] @@ -3619,7 +3553,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] [[package]] @@ -3639,7 +3573,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", "synstructure", ] @@ -3668,5 +3602,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.91", ] From a44f10f3d790359b1f5098e67324a317001d679c Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Thu, 26 Dec 2024 09:32:28 +0100 Subject: [PATCH 04/12] Send appropriate Accept: headers in HTTP requests Fixes #573. Signed-off-by: Maximilian Marx --- nemo-wasm/src/lib.rs | 1 + nemo/src/io/import_manager.rs | 1 + nemo/src/io/resource_providers.rs | 6 +++++- nemo/src/io/resource_providers/file.rs | 1 + nemo/src/io/resource_providers/http.rs | 18 ++++++++++++++--- .../components/import_export/file_formats.rs | 10 ++++++++++ nemo/src/syntax.rs | 20 +++++++++++++++++++ 7 files changed, 53 insertions(+), 4 deletions(-) diff --git a/nemo-wasm/src/lib.rs b/nemo-wasm/src/lib.rs index 70ca1fff..9867e1a0 100644 --- a/nemo-wasm/src/lib.rs +++ b/nemo-wasm/src/lib.rs @@ -168,6 +168,7 @@ impl ResourceProvider for BlobResourceProvider { &self, resource: &Resource, compression: CompressionFormat, + _media_type: &str, ) -> Result>, nemo_physical::error::ReadingError> { if let Some(blob) = self.blobs.get(resource) { let array_buffer: js_sys::ArrayBuffer = self diff --git a/nemo/src/io/import_manager.rs b/nemo/src/io/import_manager.rs index c9d80fab..c7aa1db6 100644 --- a/nemo/src/io/import_manager.rs +++ b/nemo/src/io/import_manager.rs @@ -31,6 +31,7 @@ impl ImportManager { let reader = self.resource_providers.open_resource( &handler.resource().expect("checked when making handler"), handler.compression_format(), + handler.file_format().media_type(), )?; handler.reader(reader) diff --git a/nemo/src/io/resource_providers.rs b/nemo/src/io/resource_providers.rs index 317de6c4..adccf8a2 100644 --- a/nemo/src/io/resource_providers.rs +++ b/nemo/src/io/resource_providers.rs @@ -40,6 +40,7 @@ pub trait ResourceProvider: std::fmt::Debug { &self, resource: &Resource, compression: CompressionFormat, + media_type: &str, ) -> Result>, ReadingError>; } @@ -76,9 +77,12 @@ impl ResourceProviders { &self, resource: &Resource, compression: CompressionFormat, + media_type: &str, ) -> Result, ReadingError> { for resource_provider in self.0.iter() { - if let Some(reader) = resource_provider.open_resource(resource, compression)? { + if let Some(reader) = + resource_provider.open_resource(resource, compression, media_type)? + { return Ok(reader); } } diff --git a/nemo/src/io/resource_providers/file.rs b/nemo/src/io/resource_providers/file.rs index 52962c1b..ff081c7d 100644 --- a/nemo/src/io/resource_providers/file.rs +++ b/nemo/src/io/resource_providers/file.rs @@ -59,6 +59,7 @@ impl ResourceProvider for FileResourceProvider { &self, resource: &Resource, compression: CompressionFormat, + _media_type: &str, ) -> Result>, ReadingError> { // Try to parse as file IRI if let Some(path) = self.parse_resource(resource)? { diff --git a/nemo/src/io/resource_providers/http.rs b/nemo/src/io/resource_providers/http.rs index 0d2a2c35..ca46a203 100644 --- a/nemo/src/io/resource_providers/http.rs +++ b/nemo/src/io/resource_providers/http.rs @@ -1,6 +1,7 @@ use std::io::{BufRead, BufReader, Read}; use nemo_physical::{error::ReadingError, resource::Resource}; +use reqwest::header::InvalidHeaderValue; use crate::rule_model::components::import_export::compression::CompressionFormat; @@ -43,8 +44,18 @@ impl Read for HttpResource { } impl HttpResourceProvider { - async fn get(url: &Resource) -> Result { - let response = reqwest::get(url).await?; + async fn get(url: &Resource, media_type: &str) -> Result { + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert( + reqwest::header::ACCEPT, + media_type + .parse() + .map_err(|err: InvalidHeaderValue| ReadingError::ExternalError(err.into()))?, + ); + let client = reqwest::Client::builder() + .default_headers(headers) + .build()?; + let response = client.get(url).send().await?; // we're expecting potentially compressed data, don't try to // do any character set guessing, as `response.text()` would do. let content = response.bytes().await?; @@ -61,6 +72,7 @@ impl ResourceProvider for HttpResourceProvider { &self, resource: &Resource, compression: CompressionFormat, + media_type: &str, ) -> Result>, ReadingError> { if !is_iri(resource) { return Ok(None); @@ -78,7 +90,7 @@ impl ResourceProvider for HttpResourceProvider { error: e, filename: resource.clone(), })?; - let response = rt.block_on(Self::get(resource))?; + let response = rt.block_on(Self::get(resource, media_type))?; if let Some(reader) = compression.try_decompression(BufReader::new(response)) { Ok(Some(reader)) } else { diff --git a/nemo/src/rule_model/components/import_export/file_formats.rs b/nemo/src/rule_model/components/import_export/file_formats.rs index f570ba4a..15c581f6 100644 --- a/nemo/src/rule_model/components/import_export/file_formats.rs +++ b/nemo/src/rule_model/components/import_export/file_formats.rs @@ -25,6 +25,7 @@ pub(crate) enum AttributeRequirement { #[func(pub fn name(&self) -> &'static str)] #[func(pub fn from_name(name: &str) -> Option)] #[func(pub fn extension(&self) -> &'static str)] +#[func(pub fn media_type(&self) -> &'static str)] #[func(pub fn attributes(&self) -> HashMap)] #[func(pub fn arity(&self) -> Option)] pub enum FileFormat { @@ -32,6 +33,7 @@ pub enum FileFormat { #[assoc(name = file_format::CSV)] #[assoc(from_name = file_format::CSV)] #[assoc(extension = file_format::EXTENSION_CSV)] + #[assoc(media_type = file_format::MEDIA_TYPE_CSV)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Format, AttributeRequirement::Optional), @@ -43,6 +45,7 @@ pub enum FileFormat { #[assoc(name = file_format::DSV)] #[assoc(from_name = file_format::DSV)] #[assoc(extension = file_format::EXTENSION_DSV)] + #[assoc(media_type = file_format::MEDIA_TYPE_DSV)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Delimiter, AttributeRequirement::Required), @@ -55,6 +58,7 @@ pub enum FileFormat { #[assoc(name = file_format::TSV)] #[assoc(from_name = file_format::TSV)] #[assoc(extension = file_format::EXTENSION_TSV)] + #[assoc(media_type = file_format::MEDIA_TYPE_TSV)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Format, AttributeRequirement::Optional), @@ -66,6 +70,7 @@ pub enum FileFormat { #[assoc(name = file_format::JSON)] #[assoc(from_name = file_format::JSON)] #[assoc(extension = file_format::EXTENSION_JSON)] + #[assoc(media_type = file_format::MEDIA_TYPE_JSON)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional) ]))] @@ -75,6 +80,7 @@ pub enum FileFormat { #[assoc(name = file_format::RDF_NTRIPLES)] #[assoc(from_name = file_format::RDF_NTRIPLES)] #[assoc(extension = file_format::EXTENSION_RDF_NTRIPLES)] + #[assoc(media_type = file_format::MEDIA_TYPE_RDF_NTRIPLES)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Base, AttributeRequirement::Optional), @@ -88,6 +94,7 @@ pub enum FileFormat { #[assoc(name = file_format::RDF_NQUADS)] #[assoc(from_name = file_format::RDF_NQUADS)] #[assoc(extension = file_format::EXTENSION_RDF_NQUADS)] + #[assoc(media_type = file_format::MEDIA_TYPE_RDF_NQUADS)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Base, AttributeRequirement::Optional), @@ -101,6 +108,7 @@ pub enum FileFormat { #[assoc(name = file_format::RDF_TURTLE)] #[assoc(from_name = file_format::RDF_TURTLE)] #[assoc(extension = file_format::EXTENSION_RDF_TURTLE)] + #[assoc(media_type = file_format::MEDIA_TYPE_RDF_TURTLE)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Base, AttributeRequirement::Optional), @@ -114,6 +122,7 @@ pub enum FileFormat { #[assoc(name = file_format::RDF_XML)] #[assoc(from_name = file_format::RDF_XML)] #[assoc(extension = file_format::EXTENSION_RDF_XML)] + #[assoc(media_type = file_format::MEDIA_TYPE_RDF_XML)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Base, AttributeRequirement::Optional), @@ -127,6 +136,7 @@ pub enum FileFormat { #[assoc(name = file_format::RDF_TRIG)] #[assoc(from_name = file_format::RDF_TRIG)] #[assoc(extension = file_format::EXTENSION_RDF_TRIG)] + #[assoc(media_type = file_format::MEDIA_TYPE_RDF_TRIG)] #[assoc(attributes = HashMap::from([ (ImportExportAttribute::Resource, AttributeRequirement::Optional), (ImportExportAttribute::Base, AttributeRequirement::Optional), diff --git a/nemo/src/syntax.rs b/nemo/src/syntax.rs index ed23e2c8..37a4f741 100644 --- a/nemo/src/syntax.rs +++ b/nemo/src/syntax.rs @@ -416,5 +416,25 @@ pub mod import_export { pub(crate) const EXTENSION_RDF_XML: &str = "rdf"; /// The file extension used for json files pub(crate) const EXTENSION_JSON: &str = "json"; + + // media types + /// The media type used for CSV resources + pub(crate) const MEDIA_TYPE_CSV: &str = "text/csv"; + /// The media type used for TSV resources + pub(crate) const MEDIA_TYPE_TSV: &str = "text/tab-separated-values"; + /// The media type used for DSV resources + pub(crate) const MEDIA_TYPE_DSV: &str = "text"; + /// The media type used for Ntriples resources + pub(crate) const MEDIA_TYPE_RDF_NTRIPLES: &str = "application/n-triples"; + /// The media type used for NQuads resources + pub(crate) const MEDIA_TYPE_RDF_NQUADS: &str = "application/n-quads"; + /// The media type used for Turtle resources + pub(crate) const MEDIA_TYPE_RDF_TURTLE: &str = "text/turtle"; + /// The media type used for TriG resources + pub(crate) const MEDIA_TYPE_RDF_TRIG: &str = "application/trig"; + /// The media type used for RDF/XML resources + pub(crate) const MEDIA_TYPE_RDF_XML: &str = "application/rdf+xml"; + /// The media type used for json resources + pub(crate) const MEDIA_TYPE_JSON: &str = "application/json"; } } From a79ba5a7ee7c5b51f53efaff8c3991918b1f975d Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Thu, 26 Dec 2024 09:55:35 +0100 Subject: [PATCH 05/12] Set User-Agent header for HTTP requests Fixes #574. Signed-off-by: Maximilian Marx --- nemo/src/io/resource_providers/http.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/nemo/src/io/resource_providers/http.rs b/nemo/src/io/resource_providers/http.rs index ca46a203..f1c9245e 100644 --- a/nemo/src/io/resource_providers/http.rs +++ b/nemo/src/io/resource_providers/http.rs @@ -52,6 +52,18 @@ impl HttpResourceProvider { .parse() .map_err(|err: InvalidHeaderValue| ReadingError::ExternalError(err.into()))?, ); + headers.insert( + reqwest::header::USER_AGENT, + format!( + "{}/{} ({})", + option_env!("CARGO_PKG_NAME").unwrap_or("Nemo"), + option_env!("CARGO_PKG_VERSION").unwrap_or("unknown-version"), + option_env!("CARGO_PKG_HOMEPAGE") + .unwrap_or("https://iccl.inf.tu-dresden.de/web/Nemo/en") + ) + .parse() + .map_err(|err: InvalidHeaderValue| ReadingError::ExternalError(err.into()))?, + ); let client = reqwest::Client::builder() .default_headers(headers) .build()?; From 0d7ccf224149386db6914945f35a22ce703f7368 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Fri, 27 Dec 2024 23:27:04 +0100 Subject: [PATCH 06/12] Add URIENCODE/URIDECODE builtins Fixes #571. Signed-off-by: Maximilian Marx --- Cargo.lock | 7 +++ nemo-cli/tests/blackbox_integration.rs | 1 + nemo-physical/Cargo.toml | 1 + nemo-physical/src/function/definitions.rs | 6 ++- .../src/function/definitions/string.rs | 47 +++++++++++++++++++ nemo-physical/src/function/tree.rs | 25 +++++++++- .../planning/operations/operation.rs | 2 + .../term/operation/operation_kind.rs | 10 ++++ nemo/src/syntax.rs | 4 ++ resources/testcases/arithmetic/builtins.rls | 3 ++ .../testcases/arithmetic/builtins/result.csv | 3 +- .../arithmetic/sources/uri_strings.csv | 1 + 12 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 resources/testcases/arithmetic/sources/uri_strings.csv diff --git a/Cargo.lock b/Cargo.lock index f7ca041d..dbef1dbc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1664,6 +1664,7 @@ dependencies = [ "test-log", "thiserror 2.0.9", "unicode-segmentation", + "urlencoding", ] [[package]] @@ -3081,6 +3082,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf16_iter" version = "1.0.5" diff --git a/nemo-cli/tests/blackbox_integration.rs b/nemo-cli/tests/blackbox_integration.rs index 5ec3e097..34bbff9d 100644 --- a/nemo-cli/tests/blackbox_integration.rs +++ b/nemo-cli/tests/blackbox_integration.rs @@ -109,6 +109,7 @@ impl TestCase { let expected_name = expected_file.file_name().and_then(|s| s.to_str()).unwrap(); let output_file = PathBuf::from_str(self.output_dir.child(expected_name).to_str().unwrap()).unwrap(); + log::info!("output file: {output_file:?}"); assert!(output_file.exists()); let mut output_lines = read_to_string(output_file) .unwrap() diff --git a/nemo-physical/Cargo.toml b/nemo-physical/Cargo.toml index 0223e444..f4ec5715 100644 --- a/nemo-physical/Cargo.toml +++ b/nemo-physical/Cargo.toml @@ -39,6 +39,7 @@ bitvec = "1.0.1" streaming-iterator = "0.1.9" flate2 = "1" unicode-segmentation = "1.11.0" +urlencoding = "2.1.3" [dev-dependencies] arbitrary = { version = "1", features = ["derive"] } diff --git a/nemo-physical/src/function/definitions.rs b/nemo-physical/src/function/definitions.rs index 9125cf4c..4e51c61b 100644 --- a/nemo-physical/src/function/definitions.rs +++ b/nemo-physical/src/function/definitions.rs @@ -35,7 +35,7 @@ use self::{ string::{ StringAfter, StringBefore, StringCompare, StringConcatenation, StringContains, StringEnds, StringLength, StringLowercase, StringRegex, StringReverse, StringStarts, StringSubstring, - StringSubstringLength, StringUppercase, + StringSubstringLength, StringUppercase, StringUriDecode, StringUriEncode, }, }; @@ -155,6 +155,8 @@ pub enum UnaryFunctionEnum { StringReverse(StringReverse), StringLowercase(StringLowercase), StringUppercase(StringUppercase), + StringUriEncode(StringUriEncode), + StringUriDecode(StringUriDecode), } impl UnaryFunction for UnaryFunctionEnum { @@ -188,6 +190,8 @@ impl UnaryFunction for UnaryFunctionEnum { Self::StringReverse(function) => function, Self::StringLowercase(function) => function, Self::StringUppercase(function) => function, + Self::StringUriEncode(function) => function, + Self::StringUriDecode(function) => function, } { fn evaluate(&self, parameter: AnyDataValue) -> Option; fn type_propagation(&self) -> FunctionTypePropagation; diff --git a/nemo-physical/src/function/definitions/string.rs b/nemo-physical/src/function/definitions/string.rs index b4ffff62..321b5fd2 100644 --- a/nemo-physical/src/function/definitions/string.rs +++ b/nemo-physical/src/function/definitions/string.rs @@ -458,6 +458,53 @@ impl UnaryFunction for StringLowercase { } } +/// URI encoding (percent encoding) of a string +/// +/// Returns the percent-encoded version of the provided string. +/// +/// Returns `None` if the provided argument is not a string. +#[derive(Debug, Copy, Clone)] +pub struct StringUriEncode; +impl UnaryFunction for StringUriEncode { + fn evaluate(&self, parameter: AnyDataValue) -> Option { + parameter + .to_plain_string() + .map(|string| AnyDataValue::new_plain_string(urlencoding::encode(&string).to_string())) + } + + fn type_propagation(&self) -> FunctionTypePropagation { + FunctionTypePropagation::KnownOutput( + StorageTypeName::Id32 + .bitset() + .union(StorageTypeName::Id64.bitset()), + ) + } +} + +/// URI encoding (percent encoding) of a string +/// +/// Returns the percent-encoded version of the provided string. +/// +/// Returns `None` if the provided argument is not a string. +#[derive(Debug, Copy, Clone)] +pub struct StringUriDecode; +impl UnaryFunction for StringUriDecode { + fn evaluate(&self, parameter: AnyDataValue) -> Option { + let string = parameter.to_plain_string()?; + let decoded = urlencoding::decode(&string).ok()?; + + Some(AnyDataValue::new_plain_string(decoded.to_string())) + } + + fn type_propagation(&self) -> FunctionTypePropagation { + FunctionTypePropagation::KnownOutput( + StorageTypeName::Id32 + .bitset() + .union(StorageTypeName::Id64.bitset()), + ) + } +} + /// Substring with Length /// /// Expects a string value as the first parameter diff --git a/nemo-physical/src/function/tree.rs b/nemo-physical/src/function/tree.rs index 25c2b44e..4717e2ab 100644 --- a/nemo-physical/src/function/tree.rs +++ b/nemo-physical/src/function/tree.rs @@ -25,7 +25,8 @@ use super::{ string::{ StringAfter, StringBefore, StringCompare, StringConcatenation, StringContains, StringEnds, StringLength, StringLowercase, StringRegex, StringReverse, StringStarts, - StringSubstring, StringSubstringLength, StringUppercase, + StringSubstring, StringSubstringLength, StringUppercase, StringUriDecode, + StringUriEncode, }, BinaryFunctionEnum, NaryFunctionEnum, TernaryFunctionEnum, UnaryFunctionEnum, }, @@ -731,6 +732,28 @@ where ) } + /// Create a tree node representing the URI encoding of a string. + /// + /// This evaluates to a percent-encoded version of the string + /// that results from evaluating `sub`. + pub fn string_uriencode(sub: Self) -> Self { + Self::Unary( + UnaryFunctionEnum::StringUriEncode(StringUriEncode), + Box::new(sub), + ) + } + + /// Create a tree node representing the URI decoding of a string. + /// + /// This evaluates to a percent-decoded version of the string + /// that results from evaluating `sub`. + pub fn string_uridecode(sub: Self) -> Self { + Self::Unary( + UnaryFunctionEnum::StringUriDecode(StringUriDecode), + Box::new(sub), + ) + } + /// Create a tree node representing a substring operation. /// /// This evaluates to a string containing the diff --git a/nemo/src/execution/planning/operations/operation.rs b/nemo/src/execution/planning/operations/operation.rs index 4a1c6cae..72d934d2 100644 --- a/nemo/src/execution/planning/operations/operation.rs +++ b/nemo/src/execution/planning/operations/operation.rs @@ -126,6 +126,8 @@ pub(crate) fn operation_to_function_tree( OperationKind::StringReverse => unary!(string_reverse, sub), OperationKind::StringLowercase => unary!(string_lowercase, sub), OperationKind::StringUppercase => unary!(string_uppercase, sub), + OperationKind::StringUriEncode => unary!(string_uriencode, sub), + OperationKind::StringUriDecode => unary!(string_uridecode, sub), OperationKind::LexicalValue => unary!(lexical_value, sub), OperationKind::NumericSum => FunctionTree::numeric_sum(sub), OperationKind::NumericProduct => FunctionTree::numeric_product(sub), diff --git a/nemo/src/rule_model/components/term/operation/operation_kind.rs b/nemo/src/rule_model/components/term/operation/operation_kind.rs index 90f1bae4..533fc09f 100644 --- a/nemo/src/rule_model/components/term/operation/operation_kind.rs +++ b/nemo/src/rule_model/components/term/operation/operation_kind.rs @@ -311,6 +311,16 @@ pub enum OperationKind { #[assoc(num_arguments = OperationNumArguments::Unary)] #[assoc(return_type = ValueType::String)] StringUppercase, + /// String percent-encoded for URIs + #[assoc(name = function::URIENCODE)] + #[assoc(num_arguments = OperationNumArguments::Unary)] + #[assoc(return_type = ValueType::String)] + StringUriEncode, + /// String percent-decoded for URIs + #[assoc(name = function::URIDECODE)] + #[assoc(num_arguments = OperationNumArguments::Unary)] + #[assoc(return_type = ValueType::String)] + StringUriDecode, /// Bitwise and operation #[assoc(name = function::BITAND)] #[assoc(num_arguments = OperationNumArguments::Arbitrary)] diff --git a/nemo/src/syntax.rs b/nemo/src/syntax.rs index 37a4f741..6ac605ff 100644 --- a/nemo/src/syntax.rs +++ b/nemo/src/syntax.rs @@ -239,6 +239,10 @@ pub mod builtin { pub(crate) const UCASE: &str = "UCASE"; /// Replace characters in strings with their lower case version pub(crate) const LCASE: &str = "LCASE"; + /// Return URI-encoded (percent-encoded) version of string + pub(crate) const URIENCODE: &str = "URIENCODE"; + /// Return URI-decoded (percent-decoded) version of string + pub(crate) const URIDECODE: &str = "URIDECODE"; /// Round a value to the nearest integer pub(crate) const ROUND: &str = "ROUND"; /// Round up to the nearest integer diff --git a/resources/testcases/arithmetic/builtins.rls b/resources/testcases/arithmetic/builtins.rls index 64222c56..83f47711 100644 --- a/resources/testcases/arithmetic/builtins.rls +++ b/resources/testcases/arithmetic/builtins.rls @@ -7,6 +7,7 @@ integers(1, 2, 3). tagged("test"@en). iri(constant). null(!V) :- iri(?X). +@import uri_strings :- csv{resource="sources/uri_strings.csv"}. % Datatype check result(isString, ?R) :- strings(?A, _), ?R = isString(?A). @@ -71,6 +72,8 @@ result(stringstarts_true, ?R) :- strings(?A, _), ?R = STRSTARTS(?A, "Hell"). result(stringstarts_false, ?R) :- strings(_, ?B), ?R = STRSTARTS(?B, "Hell"). result(stringends_true, ?R) :- strings(?A, _), ?R = STRENDS(?A, "ello"). result(stringends_false, ?R) :- strings(_, ?B), ?R = STRENDS(?B, "ello"). +result(uriencode, ?R) :- uri_strings(?A, _), ?R = URIENCODE(?A). +result(uridecode, ?R) :- uri_strings(_, ?A), ?R = URIDECODE(?A). % F-string literal result(fstring_basic, ?R) :- strings(?A, ?B), ?R = f"{?A} and {?B}". diff --git a/resources/testcases/arithmetic/builtins/result.csv b/resources/testcases/arithmetic/builtins/result.csv index ba47af49..b4de6687 100644 --- a/resources/testcases/arithmetic/builtins/result.csv +++ b/resources/testcases/arithmetic/builtins/result.csv @@ -61,4 +61,5 @@ bitand,0 bitor,3 bitxor,0 fstring_basic,"""Hello and World""" -fstring_arithmetic,"""len*10=50""" \ No newline at end of file +fstring_arithmetic,"""len*10=50""" +uriencode,"""%3Ffoo%5B%5D%3D%22bar%20quuz%22""" diff --git a/resources/testcases/arithmetic/sources/uri_strings.csv b/resources/testcases/arithmetic/sources/uri_strings.csv new file mode 100644 index 00000000..a14a9b94 --- /dev/null +++ b/resources/testcases/arithmetic/sources/uri_strings.csv @@ -0,0 +1 @@ +?foo[]="bar quuz","%3Ffoo%5B%5D%3D%22bar%20quuz%22" \ No newline at end of file From a4fc8ffba0f81764d0f660dbc456383a9806eb54 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Fri, 3 Jan 2025 22:19:05 +0100 Subject: [PATCH 07/12] Allow constant bindings in @import/@export directives Fixes #572. --- nemo-cli/src/main.rs | 7 +- nemo/src/parser/ast/directive/export.rs | 30 +++++++-- nemo/src/parser/ast/directive/import.rs | 33 ++++++++-- nemo/src/rule_model/components.rs | 3 + .../rule_model/components/import_export.rs | 47 ++++++++++++-- .../components/import_export/attributes.rs | 2 +- nemo/src/rule_model/components/term.rs | 8 +-- .../rule_model/components/term/function.rs | 2 +- nemo/src/rule_model/components/term/map.rs | 2 +- .../rule_model/components/term/operation.rs | 4 +- .../components/term/primitive/ground.rs | 2 +- nemo/src/rule_model/components/term/tuple.rs | 2 +- .../src/rule_model/error/translation_error.rs | 7 ++ .../translation/directive/import_export.rs | 65 +++++++++++++++++-- .../data-formats/dsv/computed-names.rls | 5 ++ .../dsv/computed-names/data966-output.csv | 6 ++ 16 files changed, 191 insertions(+), 34 deletions(-) create mode 100644 resources/testcases/data-formats/dsv/computed-names.rls create mode 100644 resources/testcases/data-formats/dsv/computed-names/data966-output.csv diff --git a/nemo-cli/src/main.rs b/nemo-cli/src/main.rs index 543a818e..794bf48c 100644 --- a/nemo-cli/src/main.rs +++ b/nemo-cli/src/main.rs @@ -48,7 +48,12 @@ use nemo::{ }; fn default_export(predicate: Tag) -> ExportDirective { - ExportDirective::new(predicate, FileFormat::CSV, Map::empty_unnamed()) + ExportDirective::new( + predicate, + FileFormat::CSV, + Map::empty_unnamed(), + Default::default(), + ) } /// Set exports according to command-line parameter. diff --git a/nemo/src/parser/ast/directive/export.rs b/nemo/src/parser/ast/directive/export.rs index 5c01fc68..cfe16edd 100644 --- a/nemo/src/parser/ast/directive/export.rs +++ b/nemo/src/parser/ast/directive/export.rs @@ -1,11 +1,14 @@ //! This module defines the [Export] directive. -use nom::sequence::tuple; +use nom::{ + combinator::opt, + sequence::{delimited, preceded, tuple}, +}; use crate::parser::{ ast::{ - comment::wsoc::WSoC, expression::complex::map::Map, tag::structure::StructureTag, - token::Token, ProgramAST, + comment::wsoc::WSoC, expression::complex::map::Map, guard::Guard, sequence::Sequence, + tag::structure::StructureTag, token::Token, ProgramAST, }, context::{context, ParserContext}, input::ParserInput, @@ -23,6 +26,8 @@ pub struct Export<'a> { predicate: StructureTag<'a>, /// Map of instructions instructions: Map<'a>, + /// Additional variable bindings + guards: Option>>, } impl<'a> Export<'a> { @@ -36,7 +41,13 @@ impl<'a> Export<'a> { &self.instructions } - pub fn parse_body(input: ParserInput<'a>) -> ParserResult<'a, (StructureTag<'a>, Map<'a>)> { + pub fn guards(&self) -> &Option> { + &self.guards + } + + pub fn parse_body( + input: ParserInput<'a>, + ) -> ParserResult<'a, (StructureTag<'a>, Map<'a>, Option>>)> { context( ParserContext::ExportBody, tuple(( @@ -45,9 +56,15 @@ impl<'a> Export<'a> { Token::export_assignment, WSoC::parse, Map::parse, + opt(preceded( + delimited(WSoC::parse, Token::seq_sep, WSoC::parse), + Sequence::::parse, + )), )), )(input) - .map(|(rest, (predicate, _, _, _, instructions))| (rest, (predicate, instructions))) + .map(|(rest, (predicate, _, _, _, instructions, guards))| { + (rest, (predicate, instructions, guards)) + }) } } @@ -77,7 +94,7 @@ impl<'a> ProgramAST<'a> for Export<'a> { Self::parse_body, )), )(input) - .map(|(rest, (_, _, _, (predicate, instructions)))| { + .map(|(rest, (_, _, _, (predicate, instructions, guards)))| { let rest_span = rest.span; ( @@ -86,6 +103,7 @@ impl<'a> ProgramAST<'a> for Export<'a> { span: input_span.until_rest(&rest_span), predicate, instructions, + guards, }, ) }) diff --git a/nemo/src/parser/ast/directive/import.rs b/nemo/src/parser/ast/directive/import.rs index 37b8dd58..1bfbe9c0 100644 --- a/nemo/src/parser/ast/directive/import.rs +++ b/nemo/src/parser/ast/directive/import.rs @@ -1,11 +1,14 @@ //! This module defines the [Import] directive. -use nom::sequence::tuple; +use nom::{ + combinator::opt, + sequence::{delimited, preceded, tuple}, +}; use crate::parser::{ ast::{ - comment::wsoc::WSoC, expression::complex::map::Map, tag::structure::StructureTag, - token::Token, ProgramAST, + comment::wsoc::WSoC, expression::complex::map::Map, guard::Guard, sequence::Sequence, + tag::structure::StructureTag, token::Token, ProgramAST, }, context::{context, ParserContext}, input::ParserInput, @@ -19,10 +22,12 @@ pub struct Import<'a> { /// [Span] associated with this node span: Span<'a>, - /// Predicate that is being Imported + /// Predicate that is being imported predicate: StructureTag<'a>, /// Map of instructions instructions: Map<'a>, + /// Additional variable bindings + guards: Option>>, } impl<'a> Import<'a> { @@ -36,7 +41,14 @@ impl<'a> Import<'a> { &self.instructions } - pub fn parse_body(input: ParserInput<'a>) -> ParserResult<'a, (StructureTag<'a>, Map<'a>)> { + /// Return the variable bindings. + pub fn guards(&self) -> &Option> { + &self.guards + } + + pub fn parse_body( + input: ParserInput<'a>, + ) -> ParserResult<'a, (StructureTag<'a>, Map<'a>, Option>>)> { context( ParserContext::ImportBody, tuple(( @@ -45,9 +57,15 @@ impl<'a> Import<'a> { Token::import_assignment, WSoC::parse, Map::parse, + opt(preceded( + delimited(WSoC::parse, Token::seq_sep, WSoC::parse), + Sequence::::parse, + )), )), )(input) - .map(|(rest, (predicate, _, _, _, instructions))| (rest, (predicate, instructions))) + .map(|(rest, (predicate, _, _, _, instructions, guards))| { + (rest, (predicate, instructions, guards)) + }) } } @@ -77,7 +95,7 @@ impl<'a> ProgramAST<'a> for Import<'a> { Self::parse_body, )), )(input) - .map(|(rest, (_, _, _, (predicate, instructions)))| { + .map(|(rest, (_, _, _, (predicate, instructions, guards)))| { let rest_span = rest.span; ( @@ -86,6 +104,7 @@ impl<'a> ProgramAST<'a> for Import<'a> { span: input_span.until_rest(&rest_span), predicate, instructions, + guards, }, ) }) diff --git a/nemo/src/rule_model/components.rs b/nemo/src/rule_model/components.rs index af2e333a..99f5bf99 100644 --- a/nemo/src/rule_model/components.rs +++ b/nemo/src/rule_model/components.rs @@ -95,6 +95,9 @@ pub enum ProgramComponentKind { /// Program #[assoc(name = "program")] Program, + /// One of the given kinds: + #[assoc(name = "oneof")] + OneOf(&'static [ProgramComponentKind]), } /// Trait implemented by objects that are part of the logical rule model of the nemo language. diff --git a/nemo/src/rule_model/components/import_export.rs b/nemo/src/rule_model/components/import_export.rs index d1b86f00..64ff047d 100644 --- a/nemo/src/rule_model/components/import_export.rs +++ b/nemo/src/rule_model/components/import_export.rs @@ -27,6 +27,7 @@ use crate::{ rule_model::{ error::{hint::Hint, validation_error::ValidationErrorKind, ValidationErrorBuilder}, origin::Origin, + substitution::Substitution, translation::ASTProgramTranslation, }, }; @@ -206,7 +207,27 @@ impl ImportExportDirective { )); } - if attribute.value_type() != value.kind() { + if let ProgramComponentKind::OneOf(types) = attribute.value_type() { + if types.iter().any(|&typ| typ == value.kind()) { + continue; + } + + builder.report_error( + *value.origin(), + ValidationErrorKind::ImportExportAttributeValueType { + parameter: attribute.name().to_string(), + given: value.kind().name().to_string(), + expected: format!( + "one of {}", + types + .iter() + .map(|typ| typ.name()) + .intersperse(", ") + .collect::() + ), + }, + ); + } else if attribute.value_type() != value.kind() { builder.report_error( *value.origin(), ValidationErrorKind::ImportExportAttributeValueType { @@ -367,12 +388,20 @@ pub struct ImportDirective(pub(crate) ImportExportDirective); impl ImportDirective { /// Create a new [ImportDirective]. - pub fn new(predicate: Tag, format: FileFormat, attributes: Map) -> Self { + pub fn new( + predicate: Tag, + format: FileFormat, + attributes: Map, + bindings: Substitution, + ) -> Self { + let mut attributes = attributes; + bindings.apply(&mut attributes); + Self(ImportExportDirective { origin: Origin::default(), predicate, format, - attributes, + attributes: attributes.reduce(), }) } @@ -454,12 +483,20 @@ pub struct ExportDirective(pub(crate) ImportExportDirective); impl ExportDirective { /// Create a new [ExportDirective]. - pub fn new(predicate: Tag, format: FileFormat, attributes: Map) -> Self { + pub fn new( + predicate: Tag, + format: FileFormat, + attributes: Map, + bindings: Substitution, + ) -> Self { + let mut attributes = attributes; + bindings.apply(&mut attributes); + Self(ImportExportDirective { origin: Origin::default(), predicate, format, - attributes, + attributes: attributes.reduce(), }) } diff --git a/nemo/src/rule_model/components/import_export/attributes.rs b/nemo/src/rule_model/components/import_export/attributes.rs index 0c0fee9d..81f77874 100644 --- a/nemo/src/rule_model/components/import_export/attributes.rs +++ b/nemo/src/rule_model/components/import_export/attributes.rs @@ -16,7 +16,7 @@ pub enum ImportExportAttribute { /// Location of the file #[assoc(name = attribute::RESOURCE)] #[assoc(from_name = attribute::RESOURCE)] - #[assoc(value_type = ProgramComponentKind::PlainString)] + #[assoc(value_type = ProgramComponentKind::OneOf(&[ProgramComponentKind::PlainString, ProgramComponentKind::Operation]))] Resource, /// Data types of the input relations #[assoc(name = attribute::FORMAT)] diff --git a/nemo/src/rule_model/components/term.rs b/nemo/src/rule_model/components/term.rs index 392a327d..10a8a5e5 100644 --- a/nemo/src/rule_model/components/term.rs +++ b/nemo/src/rule_model/components/term.rs @@ -146,10 +146,10 @@ impl Term { match self { Term::Primitive(term) => term.is_ground(), Term::Aggregate(term) => term.is_ground(), - Term::FunctionTerm(term) => term.is_gound(), - Term::Map(term) => term.is_gound(), - Term::Operation(term) => term.is_gound(), - Term::Tuple(term) => term.is_gound(), + Term::FunctionTerm(term) => term.is_ground(), + Term::Map(term) => term.is_ground(), + Term::Operation(term) => term.is_ground(), + Term::Tuple(term) => term.is_ground(), } } diff --git a/nemo/src/rule_model/components/term/function.rs b/nemo/src/rule_model/components/term/function.rs index 9c11296b..701521e9 100644 --- a/nemo/src/rule_model/components/term/function.rs +++ b/nemo/src/rule_model/components/term/function.rs @@ -103,7 +103,7 @@ impl FunctionTerm { /// Return whether this term is ground, /// i.e. if it does not contain any variables. - pub fn is_gound(&self) -> bool { + pub fn is_ground(&self) -> bool { self.terms.iter().all(Term::is_ground) } diff --git a/nemo/src/rule_model/components/term/map.rs b/nemo/src/rule_model/components/term/map.rs index 07ef4cf0..8b553465 100644 --- a/nemo/src/rule_model/components/term/map.rs +++ b/nemo/src/rule_model/components/term/map.rs @@ -114,7 +114,7 @@ impl Map { /// Return whether this term is ground, /// i.e. if it does not contain any variables. - pub fn is_gound(&self) -> bool { + pub fn is_ground(&self) -> bool { self.key_value() .all(|(key, value)| key.is_ground() && value.is_ground()) } diff --git a/nemo/src/rule_model/components/term/operation.rs b/nemo/src/rule_model/components/term/operation.rs index 21cd1527..b680d57c 100644 --- a/nemo/src/rule_model/components/term/operation.rs +++ b/nemo/src/rule_model/components/term/operation.rs @@ -91,13 +91,13 @@ impl Operation { /// Return whether this term is ground, /// i.e. if it does not contain any variables. - pub fn is_gound(&self) -> bool { + pub fn is_ground(&self) -> bool { self.subterms.iter().all(Term::is_ground) } /// Reduce constant expressions returning a copy of the reduced [Term]. pub fn reduce(&self) -> Term { - if !self.is_gound() { + if !self.is_ground() { return Term::Operation(Self { origin: self.origin, kind: self.kind, diff --git a/nemo/src/rule_model/components/term/primitive/ground.rs b/nemo/src/rule_model/components/term/primitive/ground.rs index 877eea1e..41a3db9a 100644 --- a/nemo/src/rule_model/components/term/primitive/ground.rs +++ b/nemo/src/rule_model/components/term/primitive/ground.rs @@ -22,7 +22,7 @@ use super::Primitive; /// Primitive ground term /// -/// Represents a basic, indivisble constant value like integers, or strings. +/// Represents a basic, indivisible constant value like integers, or strings. /// Such terms are the atomic values used in the construction of more complex expressions. #[derive(Debug, Clone, Eq)] pub struct GroundTerm { diff --git a/nemo/src/rule_model/components/term/tuple.rs b/nemo/src/rule_model/components/term/tuple.rs index 4089ec98..2de4b6fb 100644 --- a/nemo/src/rule_model/components/term/tuple.rs +++ b/nemo/src/rule_model/components/term/tuple.rs @@ -72,7 +72,7 @@ impl Tuple { /// Return whether this term is ground, /// i.e. if it does not contain any variables. - pub fn is_gound(&self) -> bool { + pub fn is_ground(&self) -> bool { self.terms.iter().all(Term::is_ground) } diff --git a/nemo/src/rule_model/error/translation_error.rs b/nemo/src/rule_model/error/translation_error.rs index 8b635ce4..21e81a41 100644 --- a/nemo/src/rule_model/error/translation_error.rs +++ b/nemo/src/rule_model/error/translation_error.rs @@ -119,6 +119,13 @@ pub enum TranslationErrorKind { #[error("attribute parameter is {found}, expected {expected}")] #[assoc(code = 124)] AttributeParameterWrongComponent { expected: String, found: String }, + /// Non-variable-assignment in directive + #[error("Expected a variable assignment, found {found}")] + #[assoc(code = 125)] + NonAssignment { found: String }, + #[error("Expected a ground term, found {found}")] + #[assoc(code = 126)] + NonGroundTerm { found: String }, /// Unsupported: Declare statements #[error(r#"declare statements are currently unsupported"#)] diff --git a/nemo/src/rule_model/translation/directive/import_export.rs b/nemo/src/rule_model/translation/directive/import_export.rs index 3b06b94f..44fcc606 100644 --- a/nemo/src/rule_model/translation/directive/import_export.rs +++ b/nemo/src/rule_model/translation/directive/import_export.rs @@ -5,7 +5,10 @@ use std::path::Path; use strum::IntoEnumIterator; use crate::{ - parser::ast::{self, ProgramAST}, + parser::{ + ast::{self, ProgramAST}, + span::Span, + }, rule_model::{ components::{ import_export::{ @@ -14,9 +17,10 @@ use crate::{ ExportDirective, ImportDirective, }, tag::Tag, - ProgramComponent, + IterablePrimitives, ProgramComponent, }, error::{translation_error::TranslationErrorKind, TranslationError}, + substitution::Substitution, translation::ASTProgramTranslation, }, syntax::import_export::file_format::RDF_UNSPECIFIED, @@ -97,6 +101,57 @@ impl<'a> ASTProgramTranslation<'a> { } } + fn import_export_bindings( + &mut self, + guards: &'a Option>>, + span: Span, + ) -> Result { + let mut result = Vec::new(); + + if let Some(guards) = guards { + for guard in guards { + if let ast::guard::Guard::Infix(infix) = guard { + let operation = self.build_infix(infix)?; + + if let Some((left, right)) = operation.variable_assignment() { + let right = right.reduce(); + let terms = right.primitive_terms().collect::>(); + + if !right.is_ground() || terms.len() != 1 { + return Err(TranslationError::new( + span, + TranslationErrorKind::NonGroundTerm { + found: right.kind().name().to_string(), + }, + )); + } + + result.push(( + left.clone(), + (*terms.first().expect("is not empty")).clone(), + )); + } else { + return Err(TranslationError::new( + span, + TranslationErrorKind::NonAssignment { + found: operation.operation_kind().to_string(), + }, + )); + } + } else { + return Err(TranslationError::new( + span, + TranslationErrorKind::NonAssignment { + found: "expression".to_string(), + }, + )); + } + } + } + + Ok(Substitution::new(result.into_iter())) + } + /// Given a [ast::directive::import::Import], build an [ImportDirective]. pub fn build_import( &mut self, @@ -106,9 +161,10 @@ impl<'a> ASTProgramTranslation<'a> { .set_origin(self.register_node(import.predicate())); let attributes = self.build_map(import.instructions())?; let file_format = self.import_export_format(import.instructions())?; + let bindings = self.import_export_bindings(import.guards(), import.span())?; Ok(self.register_component( - ImportDirective::new(predicate, file_format, attributes), + ImportDirective::new(predicate, file_format, attributes, bindings), import, )) } @@ -135,9 +191,10 @@ impl<'a> ASTProgramTranslation<'a> { .set_origin(self.register_node(export.predicate())); let attributes = self.build_map(export.instructions())?; let file_format = self.import_export_format(export.instructions())?; + let bindings = self.import_export_bindings(export.guards(), export.span())?; Ok(self.register_component( - ExportDirective::new(predicate, file_format, attributes), + ExportDirective::new(predicate, file_format, attributes, bindings), export, )) } diff --git a/resources/testcases/data-formats/dsv/computed-names.rls b/resources/testcases/data-formats/dsv/computed-names.rls new file mode 100644 index 00000000..a45ef507 --- /dev/null +++ b/resources/testcases/data-formats/dsv/computed-names.rls @@ -0,0 +1,5 @@ +@import dataB :- csv{ resource = f"./sources/data{?X}.csv" }, ?X = "B" . + +data(?Z, ?Y, ?X) :- dataB(?X, ?Y, ?Z) . + +@export data :- csv{ resource = f"data{?X}.csv" }, ?X = f"{23 * 42}-output" . \ No newline at end of file diff --git a/resources/testcases/data-formats/dsv/computed-names/data966-output.csv b/resources/testcases/data-formats/dsv/computed-names/data966-output.csv new file mode 100644 index 00000000..caa908e4 --- /dev/null +++ b/resources/testcases/data-formats/dsv/computed-names/data966-output.csv @@ -0,0 +1,6 @@ +D,B,B +A,D,B +F,C,A +Q,G,A +A,Q,Q +D,D,C From 2796e97dd0b8833d27710debe6c46b9e1f473984 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Sat, 4 Jan 2025 01:10:25 +0100 Subject: [PATCH 08/12] Implement multiline strings and multiline f-strings Fixes #575. --- nemo-physical/src/datavalues/syntax.rs | 5 + .../src/parser/ast/expression/basic/string.rs | 17 +++- .../parser/ast/expression/complex/fstring.rs | 38 ++++++-- nemo/src/parser/ast/token.rs | 97 +++++++++++++++++-- nemo/src/syntax.rs | 9 +- resources/testcases/arithmetic/builtins.rls | 5 +- .../testcases/arithmetic/builtins/result.csv | 1 + 7 files changed, 146 insertions(+), 26 deletions(-) diff --git a/nemo-physical/src/datavalues/syntax.rs b/nemo-physical/src/datavalues/syntax.rs index f53062fe..aff1379d 100644 --- a/nemo-physical/src/datavalues/syntax.rs +++ b/nemo-physical/src/datavalues/syntax.rs @@ -44,6 +44,11 @@ pub mod iri { pub mod string { /// Language tag indicator after strings pub const LANG_TAG: &str = "@"; + + /// Quote to delimit string literals + pub const QUOTE: &str = r#"""#; + /// Triple quotes to delimit multi-line strings + pub const TRIPLE_QUOTE: &str = r#"""""#; } /// RDF datatype indicator diff --git a/nemo/src/parser/ast/expression/basic/string.rs b/nemo/src/parser/ast/expression/basic/string.rs index d3478faa..2e4dc889 100644 --- a/nemo/src/parser/ast/expression/basic/string.rs +++ b/nemo/src/parser/ast/expression/basic/string.rs @@ -40,11 +40,18 @@ impl<'a> StringLiteral<'a> { /// Parse the main part of the string. pub fn parse_string(input: ParserInput<'a>) -> ParserResult<'a, Token<'a>> { - delimited( - Token::quote, - alt((Token::string, Token::empty)), - Token::quote, - )(input) + alt(( + delimited( + Token::triple_quote, + alt((Token::multiline_string, Token::empty)), + Token::triple_quote, + ), + delimited( + Token::quote, + alt((Token::string, Token::empty)), + Token::quote, + ), + ))(input) } /// Parse the language tag of the string. diff --git a/nemo/src/parser/ast/expression/complex/fstring.rs b/nemo/src/parser/ast/expression/complex/fstring.rs index ad0adb2a..625ea2a9 100644 --- a/nemo/src/parser/ast/expression/complex/fstring.rs +++ b/nemo/src/parser/ast/expression/complex/fstring.rs @@ -51,6 +51,16 @@ impl<'a> FormatString<'a> { map(Self::parse_expression, FormatStringElement::Expression), ))(input) } + + /// Parse a multi-line [FormatStringElement] by parsing either a string or an expression element. + fn parse_multiline_element( + input: ParserInput<'a>, + ) -> ParserResult<'a, FormatStringElement<'a>> { + alt(( + map(Token::multiline_fstring, FormatStringElement::String), + map(Self::parse_expression, FormatStringElement::Expression), + ))(input) + } } const CONTEXT: ParserContext = ParserContext::FormatString; @@ -81,11 +91,18 @@ impl<'a> ProgramAST<'a> for FormatString<'a> { context( CONTEXT, - delimited( - Token::fstring_open, - many0(Self::parse_element), - Token::fstring_close, - ), + alt(( + delimited( + Token::fstring_multiline_open, + many0(Self::parse_multiline_element), + Token::fstring_multiline_close, + ), + delimited( + Token::fstring_open, + many0(Self::parse_element), + Token::fstring_close, + ), + )), )(input) .map(|(rest, elements)| { let rest_span = rest.span; @@ -118,11 +135,12 @@ mod test { #[test] fn parse_format_string() { let test = vec![ - ("f\"\"", 0), - ("f\"string\"", 1), - ("f\"{?x + 1}\"", 1), - ("f\"result: {?x + 1}\"", 2), - ("f\"{?x} + {?y} = {?x + ?y}\"", 5), + (r#"f"""#, 0), + (r#"f"string""#, 1), + (r#"f"""string""""#, 1), + (r#"f"{?x + 1}""#, 1), + (r#"f"result: {?x + 1}""#, 2), + (r#"f"{?x} + {?y} = {?x + ?y}""#, 5), ]; for (input, expected) in test { diff --git a/nemo/src/parser/ast/token.rs b/nemo/src/parser/ast/token.rs index 9d2a0375..14bc7334 100644 --- a/nemo/src/parser/ast/token.rs +++ b/nemo/src/parser/ast/token.rs @@ -7,16 +7,19 @@ use enum_assoc::Assoc; use nom::{ branch::alt, - bytes::complete::{is_a, is_not, tag}, + bytes::complete::{is_a, is_not, tag, take_until}, character::complete::{alpha1, alphanumeric1, digit1, multispace1, space0, space1}, combinator::{map, opt, recognize, verify}, multi::many0, sequence::pair, + FindSubstring, InputTake, }; +use nom_supreme::error::{BaseErrorKind, Expectation}; use crate::{ parser::{ context::{context, ParserContext}, + error::ParserErrorTree, span::Span, ParserInput, ParserResult, }, @@ -33,10 +36,10 @@ use crate::{ #[derive(Assoc, Debug, Clone, Copy, PartialEq, Eq)] #[func(pub fn name(&self) -> &'static str)] pub enum TokenKind { - /// Opening parenthesis for parenthesised arithmitic terms + /// Opening parenthesis for parenthesised arithmetic terms #[assoc(name = "(")] OpenParenthesis, - /// Closing parenthesis for parenthesised arithmitic terms + /// Closing parenthesis for parenthesised arithmetic terms #[assoc(name = ")")] ClosedParenthesis, /// Opening delimiter for maps @@ -148,18 +151,27 @@ pub enum TokenKind { #[assoc(name = datavalues::DOT)] Dot, /// Quote - #[assoc(name = "\"")] + #[assoc(name = string::QUOTE)] Quote, + /// Triple Quotes + #[assoc(name = string::TRIPLE_QUOTE)] + TripleQuote, /// Format string open #[assoc(name = format_string::OPEN)] FormatStringOpen, /// Format string close #[assoc(name = format_string::CLOSE)] FormatStringClose, - /// Format string open + /// Format string multi-line open + #[assoc(name = format_string::MULTILINE_OPEN)] + FormatStringMultilineOpen, + /// Format string multi-line close + #[assoc(name = format_string::MULTILINE_CLOSE)] + FormatStringMultilineClose, + /// Format string expression open #[assoc(name = format_string::EXPRESSION_START)] FormatStringExpressionStart, - /// Format string close + /// Format string expression close #[assoc(name = format_string::EXPRESSION_END)] FormatStringExpressionEnd, /// Blank node prefix @@ -374,15 +386,66 @@ impl<'a> Token<'a> { }) } + fn parse_character_sequence_until( + input: ParserInput<'a>, + tag: &str, + ) -> ParserResult<'a, Token<'a>> { + take_until(tag)(input).map(|(rest, result)| { + ( + rest.clone(), + Token { + span: result.span, + kind: TokenKind::String, + }, + ) + }) + } + + fn parse_character_sequence_until_one_of( + input: ParserInput<'a>, + tags: &'static [&'static str], + ) -> ParserResult<'a, Token<'a>> { + match tags + .iter() + .filter_map(|tag| input.find_substring(tag)) + .min() + { + None => Err(nom::Err::Error(ParserErrorTree::Base { + location: input, + kind: BaseErrorKind::Expected(Expectation::Tag(tags[0])), + })), + Some(0) => Err(nom::Err::Error(ParserErrorTree::Base { + location: input, + kind: BaseErrorKind::Kind(nom::error::ErrorKind::Eof), + })), + Some(idx @ 1..) => { + let (rest, result) = input.take_split(idx); + Ok(( + rest.clone(), + Token { + span: result.span, + kind: TokenKind::String, + }, + )) + } + } + } + /// Parse [TokenKind::String]. pub fn string(input: ParserInput<'a>) -> ParserResult<'a, Token<'a>> { - Self::parse_character_sequence(input, "\"") + Self::parse_character_sequence(input, string::QUOTE) + } + + /// Parse a multi-line [TokenKind::String].o + pub fn multiline_string(input: ParserInput<'a>) -> ParserResult<'a, Token<'a>> { + Self::parse_character_sequence_until(input, string::TRIPLE_QUOTE) } /// Parse [TokenKind::FormatString]. pub fn fstring(input: ParserInput<'a>) -> ParserResult<'a, Token<'a>> { let excluded = format!( - "\"{}{}", + "{}{}{}", + format_string::CLOSE, format_string::EXPRESSION_START, format_string::EXPRESSION_END ); @@ -390,6 +453,18 @@ impl<'a> Token<'a> { Self::parse_character_sequence(input, &excluded) } + /// Parse a multi-line [TokenKind::FormatString]. + pub fn multiline_fstring(input: ParserInput<'a>) -> ParserResult<'a, Token<'a>> { + Self::parse_character_sequence_until_one_of( + input, + &[ + format_string::MULTILINE_CLOSE, + format_string::EXPRESSION_START, + format_string::EXPRESSION_END, + ], + ) + } + /// Parse [TokenKind::Digits]. pub fn digits(input: ParserInput<'a>) -> ParserResult<'a, Token<'a>> { context(ParserContext::token(TokenKind::Digits), digit1)(input).map( @@ -633,8 +708,14 @@ impl<'a> Token<'a> { string_token!(doc_comment, TokenKind::DocComment); string_token!(toplevel_comment, TokenKind::TopLevelComment); string_token!(quote, TokenKind::Quote); + string_token!(triple_quote, TokenKind::TripleQuote); string_token!(fstring_open, TokenKind::FormatStringOpen); string_token!(fstring_close, TokenKind::FormatStringClose); + string_token!(fstring_multiline_open, TokenKind::FormatStringMultilineOpen); + string_token!( + fstring_multiline_close, + TokenKind::FormatStringMultilineClose + ); string_token!( fstring_expression_start, TokenKind::FormatStringExpressionStart diff --git a/nemo/src/syntax.rs b/nemo/src/syntax.rs index 6ac605ff..3e19f23b 100644 --- a/nemo/src/syntax.rs +++ b/nemo/src/syntax.rs @@ -129,9 +129,14 @@ pub mod expression { /// Syntax for format strings pub mod format_string { /// Opening part of a format string - pub const OPEN: &str = "f\""; + pub const OPEN: &str = r#"f""#; /// Closing part of a format string - pub const CLOSE: &str = "\""; + pub const CLOSE: &str = r#"""#; + + /// Opening part of a multi-line format string + pub const MULTILINE_OPEN: &str = r#"f""""#; + /// Closing part of a multi-line format string + pub const MULTILINE_CLOSE: &str = r#"""""#; /// Marker of the start of an expression pub const EXPRESSION_START: &str = "{"; diff --git a/resources/testcases/arithmetic/builtins.rls b/resources/testcases/arithmetic/builtins.rls index 83f47711..cebf7d31 100644 --- a/resources/testcases/arithmetic/builtins.rls +++ b/resources/testcases/arithmetic/builtins.rls @@ -76,7 +76,10 @@ result(uriencode, ?R) :- uri_strings(?A, _), ?R = URIENCODE(?A). result(uridecode, ?R) :- uri_strings(_, ?A), ?R = URIDECODE(?A). % F-string literal -result(fstring_basic, ?R) :- strings(?A, ?B), ?R = f"{?A} and {?B}". +result(fstring_basic, ?R) :- strings(?A, ?B), ?R = f"{?A} and {?B}". +result(fstring_multiline, ?R) :- strings(?A, ?B), ?M = f"""{?A} +and +{?B}""", ?R = CONCAT(SUBSTR(?M, 1, 5), " ", SUBSTR(?M, 7, 3), " ", SUBSTR(?M, 11)). result(fstring_arithmetic, ?R) :- strings(?A, ?B), ?R = f"len*10={STRLEN(?A) * 10}". % Numeric arithmetic diff --git a/resources/testcases/arithmetic/builtins/result.csv b/resources/testcases/arithmetic/builtins/result.csv index b4de6687..51e558c4 100644 --- a/resources/testcases/arithmetic/builtins/result.csv +++ b/resources/testcases/arithmetic/builtins/result.csv @@ -62,4 +62,5 @@ bitor,3 bitxor,0 fstring_basic,"""Hello and World""" fstring_arithmetic,"""len*10=50""" +fstring_multiline,"""Hello and World""" uriencode,"""%3Ffoo%5B%5D%3D%22bar%20quuz%22""" From fec0caa403d9efd6448e171b5634001334e1a9fc Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Sat, 4 Jan 2025 01:22:16 +0100 Subject: [PATCH 09/12] Placate clippy --- nemo-language-server/src/language_server.rs | 14 +++++++------- .../src/language_server/lsp_component.rs | 15 +++++++-------- nemo-physical/src/management/database.rs | 8 ++++---- nemo-physical/src/management/database/order.rs | 2 +- nemo/src/parser/ast/statement.rs | 1 + .../translation/directive/import_export.rs | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/nemo-language-server/src/language_server.rs b/nemo-language-server/src/language_server.rs index 57254a74..70e291ad 100644 --- a/nemo-language-server/src/language_server.rs +++ b/nemo-language-server/src/language_server.rs @@ -4,6 +4,7 @@ mod token_type; use nemo::rule_model::translation::ProgramErrorReport; use std::collections::{BTreeMap, BTreeSet, HashMap}; +use std::fmt::Write; use std::vec; use strum::IntoEnumIterator; @@ -149,11 +150,10 @@ impl Backend { .note() .map(|n| format!("\nNote: {n}")) .unwrap_or("".to_string()), - error - .hints() - .iter() - .map(|h| format!("\nHint: {h}")) - .collect::(), + error.hints().iter().fold(String::new(), |mut acc, h| { + let _ = write!(acc, "\nHint: {h}"); + acc + }) ); if let Some(set) = errors_by_posision.get_mut(&range) { @@ -607,11 +607,11 @@ fn node_path_deepest_identifier<'a>( } } - return info.map(|info| IdentifiedNode { + info.map(|info| IdentifiedNode { node: info.node, identifier: info.identifier, scoping_node: *node_path.first().unwrap(), - }); + }) } /// Finds all children of the given node (potentially the node itself) that match the identifier diff --git a/nemo-language-server/src/language_server/lsp_component.rs b/nemo-language-server/src/language_server/lsp_component.rs index a2bec8fc..ebc2a86f 100644 --- a/nemo-language-server/src/language_server/lsp_component.rs +++ b/nemo-language-server/src/language_server/lsp_component.rs @@ -150,14 +150,13 @@ where kind.map(|kind| LSPSymbolInfo { kind, - name: format!( - "{}", - self.span() - .fragment() - .split_whitespace() - .collect::>() - .join(" ") - ), + name: self + .span() + .fragment() + .split_whitespace() + .collect::>() + .join(" ") + .to_string(), }) } diff --git a/nemo-physical/src/management/database.rs b/nemo-physical/src/management/database.rs index 8a432a98..7c8d027e 100644 --- a/nemo-physical/src/management/database.rs +++ b/nemo-physical/src/management/database.rs @@ -93,7 +93,7 @@ impl DatabaseInstance { &self .table_infos .get(&id) - .expect("No table with id {id} exists.") + .unwrap_or_else(|| panic!("No table with the id {id} exists.")) .name } @@ -104,7 +104,7 @@ impl DatabaseInstance { pub fn table_arity(&self, id: PermanentTableId) -> usize { self.table_infos .get(&id) - .expect("No table with id {id} exists.") + .unwrap_or_else(|| panic!("No table with the id {id} exists.")) .arity } @@ -146,7 +146,7 @@ impl DatabaseInstance { let storage_id = self .reference_manager .trie_id(&self.dictionary, id, ColumnOrder::default()) - .expect("No table with id {id} exists."); + .unwrap_or_else(|err| panic!("No table with the id {id} exists: {err}")); let trie = self.reference_manager.trie(storage_id); Ok(trie.row_iterator().map(|values| { @@ -168,7 +168,7 @@ impl DatabaseInstance { let storage_id = self .reference_manager .trie_id(&self.dictionary, id, ColumnOrder::default()) - .expect("No table with id {id} exists."); + .unwrap_or_else(|err| panic!("No table with the id {id} exists: {err}")); let trie = self.reference_manager.trie(storage_id); let dictionary: &Dict = &self.dictionary(); diff --git a/nemo-physical/src/management/database/order.rs b/nemo-physical/src/management/database/order.rs index 8342e64a..28c629d2 100644 --- a/nemo-physical/src/management/database/order.rs +++ b/nemo-physical/src/management/database/order.rs @@ -126,7 +126,7 @@ impl OrderedReferenceManager { for &storage_id in self .storage_map .get(&id) - .expect("No table with the id {id} exists.") + .unwrap_or_else(|| panic!("No table with the id {id} exists.")) .values() { result += self.stored_tables[storage_id].size_bytes(); diff --git a/nemo/src/parser/ast/statement.rs b/nemo/src/parser/ast/statement.rs index ac0a438e..6647f1e0 100644 --- a/nemo/src/parser/ast/statement.rs +++ b/nemo/src/parser/ast/statement.rs @@ -22,6 +22,7 @@ use super::{ ProgramAST, }; +#[allow(clippy::large_enum_variant)] /// Types of [Statement]s #[derive(Debug)] pub enum StatementKind<'a> { diff --git a/nemo/src/rule_model/translation/directive/import_export.rs b/nemo/src/rule_model/translation/directive/import_export.rs index 44fcc606..7355a7cd 100644 --- a/nemo/src/rule_model/translation/directive/import_export.rs +++ b/nemo/src/rule_model/translation/directive/import_export.rs @@ -149,7 +149,7 @@ impl<'a> ASTProgramTranslation<'a> { } } - Ok(Substitution::new(result.into_iter())) + Ok(Substitution::new(result)) } /// Given a [ast::directive::import::Import], build an [ImportDirective]. From 9ef2550e59ae6011f1c679d4c688c4f210fdaf39 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Sat, 4 Jan 2025 02:21:35 +0100 Subject: [PATCH 10/12] Drop obsolote proc macro --- Cargo.lock | 131 ++++++++++++++++++++++------------------- libs/macros/Cargo.toml | 14 ----- libs/macros/src/lib.rs | 45 -------------- nemo/Cargo.toml | 1 - 4 files changed, 69 insertions(+), 122 deletions(-) delete mode 100644 libs/macros/Cargo.toml delete mode 100644 libs/macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index dbef1dbc..18a74f72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -173,13 +173,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -207,7 +207,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -295,9 +295,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.11.1" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" +checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0" dependencies = [ "memchr", "regex-automata 0.4.9", @@ -330,9 +330,9 @@ checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" [[package]] name = "cc" -version = "1.2.5" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +checksum = "a012a0df96dd6d06ba9a1b29d6402d1a5d77c6befd2566afdc26e10603dc93d7" dependencies = [ "shlex", ] @@ -409,7 +409,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -556,7 +556,7 @@ checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -567,7 +567,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -605,7 +605,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -637,7 +637,7 @@ checksum = "4f4b100e337b021ae69f3e7dd82e230452c54ff833958446c4a3854c66dc9326" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -649,7 +649,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -854,7 +854,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -908,9 +908,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "globset" @@ -1264,7 +1264,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -1464,15 +1464,6 @@ dependencies = [ "url", ] -[[package]] -name = "macros" -version = "0.0.1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.91", -] - [[package]] name = "matchers" version = "0.1.0" @@ -1572,7 +1563,6 @@ dependencies = [ "flate2", "getrandom", "log", - "macros", "nemo-physical", "nom 7.1.3", "nom-greedyerror", @@ -1880,7 +1870,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2000,7 +1990,7 @@ checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2122,7 +2112,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2135,7 +2125,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2278,9 +2268,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64", "bytes", @@ -2311,6 +2301,7 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tower 0.5.2", "tower-service", "url", "wasm-bindgen", @@ -2429,9 +2420,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" @@ -2500,22 +2491,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.217" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2538,7 +2529,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2645,7 +2636,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2667,9 +2658,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.91" +version = "2.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53cbcb5a243bd33b7858b1d7f4aca2153490815872d86d955d6ea29f743c035" +checksum = "987bc0be1cdea8b10216bd06e2ca407d40b9543468fafd3ddfb02f36e77f71f3" dependencies = [ "proc-macro2", "quote", @@ -2693,7 +2684,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2731,12 +2722,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -2776,7 +2768,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2820,7 +2812,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2831,7 +2823,7 @@ checksum = "7b50fa271071aae2e6ee85f842e2e28ba8cd2c5fb67f11fcb1fd70b276f9e7d4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2878,7 +2870,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2928,6 +2920,21 @@ dependencies = [ "tower-service", ] +[[package]] +name = "tower" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2952,7 +2959,7 @@ dependencies = [ "serde_json", "tokio", "tokio-util", - "tower", + "tower 0.4.13", "tower-lsp-macros", "tracing", ] @@ -2965,7 +2972,7 @@ checksum = "84fd902d4e0b9a4b27f2f440108dc034e1758628a9b702f8ec61ad66355422fa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -2993,7 +3000,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -3186,7 +3193,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", "wasm-bindgen-shared", ] @@ -3220,7 +3227,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3254,7 +3261,7 @@ checksum = "c97b2ef2c8d627381e51c071c2ab328eac606d3f69dd82bcbca20a9e389d95f0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -3538,7 +3545,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", "synstructure", ] @@ -3560,7 +3567,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] [[package]] @@ -3580,7 +3587,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", "synstructure", ] @@ -3609,5 +3616,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.91", + "syn 2.0.94", ] diff --git a/libs/macros/Cargo.toml b/libs/macros/Cargo.toml deleted file mode 100644 index 51ab1200..00000000 --- a/libs/macros/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "macros" -version = "0.0.1" -edition = "2018" -authors = ["Stefan Ellmauthaler TokenStream { - let target: Literal = match parse(attrs) { - Ok(lit) => lit, - _ => panic!("#[traced] must be applied with one string argument specifying the log target"), - }; - - let mut fun: ItemFn = match parse(item) { - Ok(fun) => fun, - Err(..) => panic!("#[traced] must be applied on functions"), - }; - - let args = fun - .sig - .inputs - .iter() - .filter_map(|input| match input { - Typed(pat) => match &*pat.pat { - Ident(ident) => Some(ident), - _ => None, - }, - _ => None, - }) - .collect::>(); - - let name = &fun.sig.ident; - let fmt_before = format!("{}{{:?}}", name); - let fmt_after = format!("{}{{:?}} -> {{:?}}", name); - let stmts = &fun.block.stmts; - let block = quote! {{ - log::trace!(target: #target, #fmt_before, (#(#args)*,)); - let result = { #(#stmts)* }; - log::trace!(target: #target, #fmt_after, (#(#args)*,), result); - result - } - }; - - fun.block = parse(block.into()).expect("should parse"); - fun.to_token_stream().into() -} diff --git a/nemo/Cargo.toml b/nemo/Cargo.toml index 8f42a1e3..c5bea130 100644 --- a/nemo/Cargo.toml +++ b/nemo/Cargo.toml @@ -19,7 +19,6 @@ timing = ["nemo-physical/timing"] [dependencies] nemo-physical = { path = "../nemo-physical", default-features = false } -macros = { path = "../libs/macros" } log = "0.4" nom = "7.1.1" petgraph = "0.6.3" From bfbd6c356afdbae62e97a900f21c3fec355eb414 Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Tue, 7 Jan 2025 16:35:58 +0100 Subject: [PATCH 11/12] Lowercase start of error messages --- nemo/src/rule_model/error/translation_error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nemo/src/rule_model/error/translation_error.rs b/nemo/src/rule_model/error/translation_error.rs index 21e81a41..e8e06754 100644 --- a/nemo/src/rule_model/error/translation_error.rs +++ b/nemo/src/rule_model/error/translation_error.rs @@ -120,10 +120,10 @@ pub enum TranslationErrorKind { #[assoc(code = 124)] AttributeParameterWrongComponent { expected: String, found: String }, /// Non-variable-assignment in directive - #[error("Expected a variable assignment, found {found}")] + #[error("expected a variable assignment, found {found}")] #[assoc(code = 125)] NonAssignment { found: String }, - #[error("Expected a ground term, found {found}")] + #[error("expected a ground term, found {found}")] #[assoc(code = 126)] NonGroundTerm { found: String }, From bda2ca7d7a04a79f1b856e1bb39a928a14f1dbbe Mon Sep 17 00:00:00 2001 From: Maximilian Marx Date: Tue, 7 Jan 2025 17:54:37 +0100 Subject: [PATCH 12/12] Add unit tests for import/export directives with guards --- nemo/src/parser/ast/directive/export.rs | 47 +++++++++++++++++++++++- nemo/src/parser/ast/directive/import.rs | 48 +++++++++++++++++++++++-- 2 files changed, 92 insertions(+), 3 deletions(-) diff --git a/nemo/src/parser/ast/directive/export.rs b/nemo/src/parser/ast/directive/export.rs index cfe16edd..37fb1c84 100644 --- a/nemo/src/parser/ast/directive/export.rs +++ b/nemo/src/parser/ast/directive/export.rs @@ -116,10 +116,17 @@ impl<'a> ProgramAST<'a> for Export<'a> { #[cfg(test)] mod test { + use std::assert_matches::assert_matches; + use nom::combinator::all_consuming; use crate::parser::{ - ast::{directive::export::Export, ProgramAST}, + ast::{ + directive::export::Export, + expression::{complex::infix::InfixExpressionKind, Expression}, + guard::Guard, + ProgramAST, + }, input::ParserInput, ParserState, }; @@ -147,4 +154,42 @@ mod test { ); } } + + #[test] + fn parse_export_with_guards() { + let parser_input = ParserInput::new( + r#"@export predicate :- csv { resource = f"{?x}.{?y}" }, ?x = "test", ?y = "csv""#, + ParserState::default(), + ); + let result = all_consuming(Export::parse)(parser_input); + + assert!(result.is_ok()); + + let (_, result) = result.unwrap(); + + assert_eq!(result.predicate().to_string(), "predicate".to_string()); + assert_eq!( + result.instructions().tag().unwrap().to_string(), + "csv".to_string() + ); + + assert!(result.guards().is_some()); + + if let Some(sequence) = result.guards() { + let guards = sequence.iter().collect::>(); + assert_eq!(guards.len(), 2); + + for guard in guards { + assert_matches!(guard, Guard::Infix(_)); + + if let Guard::Infix(infix) = guard { + assert_eq!(infix.kind(), InfixExpressionKind::Equality); + let (left, right) = infix.pair(); + + assert_matches!(left, Expression::Variable(_)); + assert_matches!(right, Expression::String(_)); + } + } + } + } } diff --git a/nemo/src/parser/ast/directive/import.rs b/nemo/src/parser/ast/directive/import.rs index 1bfbe9c0..820ad09f 100644 --- a/nemo/src/parser/ast/directive/import.rs +++ b/nemo/src/parser/ast/directive/import.rs @@ -118,9 +118,15 @@ impl<'a> ProgramAST<'a> for Import<'a> { #[cfg(test)] mod test { use nom::combinator::all_consuming; + use std::assert_matches::assert_matches; use crate::parser::{ - ast::{directive::import::Import, ProgramAST}, + ast::{ + directive::import::Import, + expression::{complex::infix::InfixExpressionKind, Expression}, + guard::Guard, + ProgramAST, + }, input::ParserInput, ParserState, }; @@ -143,9 +149,47 @@ mod test { expected, ( result.1.predicate().to_string(), - result.1.instructions().tag().unwrap().to_string() + result.1.instructions().tag().unwrap().to_string(), ) ); } } + + #[test] + fn parse_import_with_guards() { + let parser_input = ParserInput::new( + r#"@import predicate :- csv { resource = f"{?x}.{?y}" }, ?x = "test", ?y = "csv""#, + ParserState::default(), + ); + let result = all_consuming(Import::parse)(parser_input); + + assert!(result.is_ok()); + + let (_, result) = result.unwrap(); + + assert_eq!(result.predicate().to_string(), "predicate".to_string()); + assert_eq!( + result.instructions().tag().unwrap().to_string(), + "csv".to_string() + ); + + assert!(result.guards().is_some()); + + if let Some(sequence) = result.guards() { + let guards = sequence.iter().collect::>(); + assert_eq!(guards.len(), 2); + + for guard in guards { + assert_matches!(guard, Guard::Infix(_)); + + if let Guard::Infix(infix) = guard { + assert_eq!(infix.kind(), InfixExpressionKind::Equality); + let (left, right) = infix.pair(); + + assert_matches!(left, Expression::Variable(_)); + assert_matches!(right, Expression::String(_)); + } + } + } + } }