diff --git a/.gitignore b/.gitignore index fcaa00f..1407055 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .direnv/ /target .pre-commit-config.yaml +*.pdf diff --git a/.helix/languages.toml b/.helix/languages.toml new file mode 100644 index 0000000..ca9fd35 --- /dev/null +++ b/.helix/languages.toml @@ -0,0 +1,3 @@ +[[language]] +name = "ron" +file-types = [ "rpl" ] diff --git a/Cargo.lock b/Cargo.lock index ee349ac..b0b723c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,10 +3,16 @@ version = 3 [[package]] -name = "anstream" -version = "0.6.4" +name = "adler" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" dependencies = [ "anstyle", "anstyle-parse", @@ -24,43 +30,88 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" [[package]] name = "anstyle-parse" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" dependencies = [ "windows-sys", ] [[package]] name = "anstyle-wincon" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" dependencies = [ "anstyle", "windows-sys", ] [[package]] -name = "beef" -version = "0.5.2" +name = "autocfg" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.21.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.4.8" +version = "4.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64" +checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" dependencies = [ "clap_builder", "clap_derive", @@ -68,9 +119,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.8" +version = "4.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc" +checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" dependencies = [ "anstream", "anstyle", @@ -97,14 +148,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] -name = "codespan-reporting" -version = "0.11.1" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "colorchoice" @@ -113,10 +160,128 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] -name = "fnv" -version = "1.0.7" +name = "crc32fast" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e3681d554572a651dda4186cd47240627c3d0114d45a95f6ad27f2f22e7548d" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a430a770ebd84726f584a90ee7f020d28db52c6d02138900f22341f866d39c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "executor" +version = "0.1.0" +dependencies = [ + "clap", + "image", + "rpl", +] + +[[package]] +name = "exr" +version = "1.71.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209098dd6dfc4445aa6111f0e98653ac323eaa4dfd212c9ca3931bf9955c31bd" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] [[package]] name = "heck" @@ -125,55 +290,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] -name = "logos" -version = "0.13.0" +name = "image" +version = "0.24.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" dependencies = [ - "logos-derive", + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", ] [[package]] -name = "logos-codegen" -version = "0.13.0" +name = "jpeg-decoder" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" dependencies = [ - "beef", - "fnv", - "proc-macro2", - "quote", - "regex-syntax", - "syn", + "rayon", ] [[package]] -name = "logos-derive" -version = "0.13.0" +name = "lebe" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfc0d229f1f42d790440136d941afd806bc9e949e2bcb8faa813b0f00d1267e" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ - "logos-codegen", + "autocfg", + "scopeguard", ] [[package]] -name = "pipeline-lang" +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "pl-cli" version = "0.1.0" dependencies = [ "clap", - "codespan-reporting", - "logos", + "executor", + "rpl", +] + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", ] [[package]] name = "proc-macro2" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "quote" version = "1.0.33" @@ -184,10 +423,91 @@ dependencies = [ ] [[package]] -name = "regex-syntax" -version = "0.6.29" +name = "rayon" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64", + "bitflags 2.4.1", + "serde", + "serde_derive", +] + +[[package]] +name = "rpl" +version = "0.1.0" +dependencies = [ + "ron", + "serde", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "serde" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.193" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "strsim" @@ -197,9 +517,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "2.0.39" +version = "2.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" +checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269" dependencies = [ "proc-macro2", "quote", @@ -207,12 +527,14 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.4.0" +name = "tiff" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" dependencies = [ - "winapi-util", + "flate2", + "jpeg-decoder", + "weezl", ] [[package]] @@ -221,12 +543,6 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - [[package]] name = "utf8parse" version = "0.2.1" @@ -234,50 +550,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] -name = "winapi" -version = "0.3.9" +name = "weezl" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -290,42 +581,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml index 2291d53..6aa4943 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,13 @@ -[package] -name = "pipeline-lang" -version = "0.1.0" -edition = "2021" +[workspace] +members = [ + "crates/executor", + "crates/pl-cli", + "crates/rpl" +] +resolver = "2" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -logos = "0.13" -codespan-reporting = "0.11" -clap = { version = "4.4.8", features = [ "derive" ] } +[workspace.dependencies] +clap = { version = "4", features = [ "derive" ] } [lints.rust] unsafe_code = "deny" diff --git a/crates/executor/Cargo.toml b/crates/executor/Cargo.toml new file mode 100644 index 0000000..fc01c27 --- /dev/null +++ b/crates/executor/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "executor" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { workspace = true, features = [ "derive" ] } +image = "0.24" +rpl = { path = "../rpl" } diff --git a/crates/executor/src/cpu/mod.rs b/crates/executor/src/cpu/mod.rs new file mode 100644 index 0000000..e82d20a --- /dev/null +++ b/crates/executor/src/cpu/mod.rs @@ -0,0 +1 @@ +pub(crate) struct CpuExecutor; diff --git a/crates/executor/src/debug/instructions/mod.rs b/crates/executor/src/debug/instructions/mod.rs new file mode 100644 index 0000000..0c4b611 --- /dev/null +++ b/crates/executor/src/debug/instructions/mod.rs @@ -0,0 +1,41 @@ +pub mod read { + use image::{io::Reader as ImageReader, DynamicImage}; + use rpl::instructions::read::{Read, SourceType}; + + pub fn read(Read { source, format }: Read) -> DynamicImage { + let mut img = ImageReader::open(match source { + SourceType::File(path) => path, + }) + .expect("something went wrong :((("); + + img.decode().expect("couldn't decode image") + } +} + +pub mod write { + use image::{io::Reader as ImageReader, DynamicImage, ImageFormat}; + use rpl::instructions::write::{TargetFormat, TargetType, Write}; + + pub fn write(Write { target, format }: Write, input_data: DynamicImage) { + input_data.save_with_format( + match target { + TargetType::File(path) => path, + }, + match format { + TargetFormat::Jpeg => ImageFormat::Jpeg, + TargetFormat::Png => ImageFormat::Png, + }, + ); + } +} + +pub mod filters { + pub mod invert { + use image::DynamicImage; + + pub fn invert(mut input_data: DynamicImage) -> DynamicImage { + input_data.invert(); + input_data + } + } +} diff --git a/crates/executor/src/debug/mod.rs b/crates/executor/src/debug/mod.rs new file mode 100644 index 0000000..d56f546 --- /dev/null +++ b/crates/executor/src/debug/mod.rs @@ -0,0 +1,37 @@ +use rpl::instructions::{FilterInstruction, Instruction}; + +use crate::{value::DynamicValue, Executor}; +mod instructions; + +pub struct DebugExecutor; + +impl Executor for DebugExecutor { + fn execute(instruction: Instruction, input: Option) -> Option { + match instruction { + Instruction::Read(read_instruction) => Some(DynamicValue::Image( + instructions::read::read(read_instruction), + )), + Instruction::Write(write_instruction) => { + instructions::write::write( + write_instruction, + match input { + Some(DynamicValue::Image(img)) => img, + _ => panic!("awawwawwa"), + }, + ); + None + } + Instruction::Math(_) => todo!(), + Instruction::Blend(_) => todo!(), + Instruction::Noise(_) => todo!(), + Instruction::Filter(filter_instruction) => match filter_instruction { + FilterInstruction::Invert => Some(DynamicValue::Image( + instructions::filters::invert::invert(match input { + Some(DynamicValue::Image(img)) => img, + _ => panic!("invalid value type for invert"), + }), + )), + }, + } + } +} diff --git a/crates/executor/src/lib.rs b/crates/executor/src/lib.rs new file mode 100644 index 0000000..fb55029 --- /dev/null +++ b/crates/executor/src/lib.rs @@ -0,0 +1,38 @@ +use rpl::instructions::Instruction; +use value::DynamicValue; + +mod debug; +mod value; + +/// The available executors +/// unused in early dev. +#[derive(Debug, Clone, Copy, clap::ValueEnum)] +pub enum Executors { + /// the debug executor is single threaded and really, *really* slow. And unstable. Don't use. Unless you're a dev working on this. + Debug, + /// the CPU executor primarily uses the CPU. Most likely most feature complete, and the fallback. + Cpu, + /// the Vulkan executor (obviously) uses vulkan. there's a good chance this isn't implemented yet as you're reading this. + Vulkan, +} + +trait Executor { + fn execute(instruction: Instruction, input: Option) -> Option; +} + +pub fn execute_all(instructions: Vec) { + let mut tmp = None; + + for instruction in instructions { + tmp = debug::DebugExecutor::execute(instruction, tmp); + } +} + +// scratchpad lol: +// execution structure: +// 1. take in rpl +// 2. analyse/validate structure against allowed executors +// 3. assign executors to instructions +// 4. optimize +// 5. prepare memory management patterns +// 6. run diff --git a/crates/executor/src/value/mod.rs b/crates/executor/src/value/mod.rs new file mode 100644 index 0000000..daf0dd2 --- /dev/null +++ b/crates/executor/src/value/mod.rs @@ -0,0 +1,5 @@ +use image::DynamicImage; + +pub enum DynamicValue { + Image(DynamicImage), +} diff --git a/crates/pl-cli/Cargo.toml b/crates/pl-cli/Cargo.toml new file mode 100644 index 0000000..e6f8cc8 --- /dev/null +++ b/crates/pl-cli/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "pl-cli" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { workspace = true, features = [ "derive" ] } +rpl = { path = "../rpl" } +executor = { path = "../executor" } diff --git a/crates/pl-cli/src/main.rs b/crates/pl-cli/src/main.rs new file mode 100644 index 0000000..9e84d33 --- /dev/null +++ b/crates/pl-cli/src/main.rs @@ -0,0 +1,19 @@ +use std::{fs, path::PathBuf}; + +use clap::Parser; +use executor::{execute_all, Executors}; + +#[derive(Parser, Debug)] +pub struct Args { + file: PathBuf, + primary_executor: Executors, +} + +fn main() { + let args = dbg!(Args::parse()); + + let f = fs::read_to_string(args.file).unwrap(); + let pl = rpl::from_ron(&f); + + execute_all(pl.0); +} diff --git a/crates/rpl/Cargo.toml b/crates/rpl/Cargo.toml new file mode 100644 index 0000000..e406f11 --- /dev/null +++ b/crates/rpl/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rpl" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.193", features = [ "derive" ] } +ron = "0.8" diff --git a/crates/rpl/src/instructions/mod.rs b/crates/rpl/src/instructions/mod.rs new file mode 100644 index 0000000..9fb8a56 --- /dev/null +++ b/crates/rpl/src/instructions/mod.rs @@ -0,0 +1,47 @@ +use serde::{Deserialize, Serialize}; + +pub mod read; +pub mod write; + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum Instruction { + Read(read::Read), + Write(write::Write), + Math(MathInstruction), + Blend(BlendInstruction), + Noise(NoiseInstruction), + Filter(FilterInstruction), +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum MathInstruction { + Add, + Subtract, + Multiply, + Divide, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum BlendInstruction { + Normal, + Multiply, + Additive, + Overlay, + Screen, + Subtractive, + Difference, + Darken, + Lighten, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum NoiseInstruction { + Perlin, + Simplex, + Voronoi, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum FilterInstruction { + Invert, +} diff --git a/crates/rpl/src/instructions/read.rs b/crates/rpl/src/instructions/read.rs new file mode 100644 index 0000000..6ccd4d3 --- /dev/null +++ b/crates/rpl/src/instructions/read.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub struct Read { + pub source: SourceType, + pub format: SourceFormat, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum SourceType { + File(PathBuf), +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum SourceFormat { + Jpeg, + Png, +} diff --git a/crates/rpl/src/instructions/write.rs b/crates/rpl/src/instructions/write.rs new file mode 100644 index 0000000..d5ea207 --- /dev/null +++ b/crates/rpl/src/instructions/write.rs @@ -0,0 +1,19 @@ +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub struct Write { + pub target: TargetType, + pub format: TargetFormat, +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum TargetType { + File(PathBuf), +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub enum TargetFormat { + Jpeg, + Png, +} diff --git a/crates/rpl/src/lib.rs b/crates/rpl/src/lib.rs new file mode 100644 index 0000000..dbecd0a --- /dev/null +++ b/crates/rpl/src/lib.rs @@ -0,0 +1,38 @@ +use instructions::Instruction; +use serde::{Deserialize, Serialize}; + +use crate::instructions::{ + read::{SourceFormat, SourceType}, + write::{TargetFormat, TargetType}, + MathInstruction, +}; + +pub mod instructions; + +pub fn from_ron(raw: &str) -> Rpl { + ron::from_str(raw).unwrap() +} + +#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)] +pub struct Rpl(pub Vec); + +#[test] +fn test_simple_deserialize() { + const TEST_DATA: &str = + "([Read( (source: File(\"~/example/file.png\"), format: Png) ),Math(Add),Write(( target: File(\"~/example/out.jpg\"), format: Jpeg))])"; + + assert_eq!( + from_ron(TEST_DATA), + Rpl(vec![ + Instruction::Read(instructions::read::Read { + source: SourceType::File("~/example/file.png".into()), + format: SourceFormat::Png + }), + Instruction::Math(MathInstruction::Add), + Instruction::Write(instructions::write::Write { + target: TargetType::File("~/example/out.jpg".into()), + format: TargetFormat::Jpeg + }) + ]) + ); +} diff --git a/crates/rpl/src/value/mod.rs b/crates/rpl/src/value/mod.rs new file mode 100644 index 0000000..238b9c2 --- /dev/null +++ b/crates/rpl/src/value/mod.rs @@ -0,0 +1,3 @@ +pub enum DynamicValue { + Image(DynamicImage), +} diff --git a/docs/design/types.typ b/docs/design/types.typ new file mode 100644 index 0000000..2e4af6e --- /dev/null +++ b/docs/design/types.typ @@ -0,0 +1,10 @@ +#import "../template.typ": conf +#show: doc => conf( + doc +) + += meow nya + +nyanyanya + +#lorem(50) diff --git a/docs/template.typ b/docs/template.typ new file mode 100644 index 0000000..6022b41 --- /dev/null +++ b/docs/template.typ @@ -0,0 +1,12 @@ +#let conf( + doc +) = { + set text(font: "Atkinson Hyperlegible"); + show heading: it => [ + #set text(font: "Montserrat", weight: "regular") + + #it + ] + + doc +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..9228b4c --- /dev/null +++ b/justfile @@ -0,0 +1,2 @@ +doc-design: + typst compile docs/design/*.typ --root=docs diff --git a/src/args.rs b/src/args.rs deleted file mode 100644 index 6a0e72b..0000000 --- a/src/args.rs +++ /dev/null @@ -1,11 +0,0 @@ -use clap::Parser; - -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -pub struct Args { - pub text: String, - #[arg(long)] - pub debug_tokens: bool, - #[arg(long)] - pub debug_typed_repr: bool, -} diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs deleted file mode 100644 index a6e6e2f..0000000 --- a/src/builtins/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use crate::namespace::{typedef::TypeDef, GlobalNamespace}; - -pub const TYPE_INTEGER: &str = "int"; -pub const TYPE_FLOAT: &str = "float"; -pub const TYPE_STRING: &str = "string"; - -pub const TRAIT_NUMERIC: &str = "Num"; - -pub const CMD_ADD: &str = "add"; - -#[allow( - clippy::unwrap_used, - reason = "Errs can only be returned in case of duplicate names in the same namespace, which will not happen here" -)] -#[allow(clippy::missing_panics_doc, reason = "will not panic")] -pub fn initialise_globals() -> GlobalNamespace { - let ns = GlobalNamespace::init(); - - let numeric = ns.register_trait(TRAIT_NUMERIC).unwrap(); - - ns.register_type(TYPE_INTEGER).unwrap().add_trait(&numeric); - ns.register_type(TYPE_FLOAT).unwrap().add_trait(&numeric); - - ns.register_type(TYPE_STRING).unwrap(); - - // def math add [ Numeric Numeric ] -> Numeric - ns.register_command( - CMD_ADD, - vec![("T", vec![&numeric])], - Some(&TypeDef::List(vec![ - TypeDef::Generic("T".to_owned()), - TypeDef::Generic("T".to_owned()), - ])), - Some(&TypeDef::Generic("T".to_owned())), - ) - .unwrap(); - - ns -} diff --git a/src/builtins/namespace.rs b/src/builtins/namespace.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/builtins/namespace.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/error/mod.rs b/src/error/mod.rs deleted file mode 100644 index 4f15d36..0000000 --- a/src/error/mod.rs +++ /dev/null @@ -1,90 +0,0 @@ -use codespan_reporting::{ - diagnostic::{Diagnostic, Label}, - files::SimpleFiles, -}; - -use crate::Span; - -#[derive(Debug)] -pub struct Errors { - pub kind: ErrorKind, - pub locs: Vec, -} - -#[derive(Debug)] -pub enum ErrorKind { - InvalidToken, - SyntaxError(SyntaxErrorKind), - CommandNotFound, -} - -#[derive(Debug)] -pub enum SyntaxErrorKind { - /// `MissingStreamer` means, that the pipeline starts with a Pipe (`|`), so it has no streamer as input in front of it. - MissingStreamer, - /// `MissingSink` means, that the pipeline ends with a Pipe (`|`), meaning that the output can't go anywhere - MissingSink, - /// This indicates a missing filter somewhere in the pipeline, meaning that there's 2 pipes after one another - MissingFilter, - /// A literal cannot be a sink - LiteralAsSink, - /// A literal can't be a filter either - LiteralAsFilter, - /// A literal acting as streamer cannot take arguments - LiteralWithArgs, -} - -impl Errors { - pub fn new(kind: ErrorKind, locs: Vec) -> Self { - Self { kind, locs } - } - pub fn new_single(kind: ErrorKind, loc: Span) -> Self { - Self { - kind, - locs: vec![loc], - } - } - pub fn into_diag( - &self, - file_id: usize, - _file_db: &SimpleFiles<&str, String>, - ) -> Diagnostic { - let Errors { kind, locs } = self; - - match kind { - ErrorKind::InvalidToken => simple_diag(locs.clone(), file_id, "invalid tokens"), - ErrorKind::SyntaxError(syntax_error) => match syntax_error { - SyntaxErrorKind::MissingStreamer => simple_diag( - locs.clone(), - file_id, - "pipeline is missing an input provider", - ), - SyntaxErrorKind::MissingSink => { - simple_diag(locs.clone(), file_id, "pipeline is missing a sink") - } - SyntaxErrorKind::MissingFilter => { - simple_diag(locs.clone(), file_id, "missing filters in pipeline") - } - SyntaxErrorKind::LiteralAsSink => { - simple_diag(locs.clone(), file_id, "pipelines can't end in a literal") - } - SyntaxErrorKind::LiteralAsFilter => { - simple_diag(locs.clone(), file_id, "literals can't filter data") - } - SyntaxErrorKind::LiteralWithArgs => { - simple_diag(locs.clone(), file_id, "literals can't take arguments") - } - }, - ErrorKind::CommandNotFound => simple_diag(locs.clone(), file_id, "command not found"), - } - } -} - -fn simple_diag(spans: Vec, file_id: usize, msg: &str) -> Diagnostic { - Diagnostic::error().with_message(msg).with_labels( - spans - .into_iter() - .map(|span| Label::primary(file_id, span)) - .collect(), - ) -} diff --git a/src/evaluator.rs b/src/evaluator.rs deleted file mode 100644 index 9b11f3e..0000000 --- a/src/evaluator.rs +++ /dev/null @@ -1,137 +0,0 @@ -use std::{collections::HashMap, process::exit}; - -use clap::error::Result; -use codespan_reporting::{ - files::SimpleFiles, - term::{ - self, - termcolor::{ColorChoice, StandardStream}, - }, -}; - -use crate::{ - builtins::initialise_globals, - error::{ErrorKind, Errors}, - syntax::{check::check, parse_syntax, PipelineElement}, - typed::into_typed_repr, -}; - -pub struct EvalConfig { - debug_raw_toks: bool, - debug_print_typed_repr: bool, -} - -impl EvalConfig { - pub fn new(debug_raw_toks: bool, debug_print_typed_repr: bool) -> Self { - Self { - debug_raw_toks, - debug_print_typed_repr, - } - } -} - -pub type FileId = usize; - -// this is also bad -// need a better architecture for this -pub struct Evaluator<'a> { - curr_phase: EvalPhase, - files: SimpleFiles<&'a str, String>, - errors: HashMap>, - cfg: EvalConfig, -} - -impl<'a> Evaluator<'a> { - pub fn init(cfg: EvalConfig) -> Self { - Self { - curr_phase: EvalPhase::Lex, - files: SimpleFiles::new(), - errors: HashMap::new(), - cfg, - } - } - - pub fn run(&mut self, input: &str, name: Option<&'a str>) { - let fid = self.files.add(name.unwrap_or("input"), input.to_owned()); - - let syntax = parse_syntax(input); - if self.cfg.debug_raw_toks { - println!("Raw tokens: {syntax:#?}"); - } - - match syntax { - Ok(syntax) => self.curr_phase = EvalPhase::Check(fid, syntax), - Err(errs) => { - self.errors.insert( - fid, - vec![Errors { - kind: ErrorKind::InvalidToken, - locs: errs, - }], - ); - self.curr_phase = EvalPhase::Failed; - } - }; - } - - pub fn next(mut self) { - match self.curr_phase { - EvalPhase::Lex => { - unreachable!() - } - EvalPhase::Check(file_id, syntax) => { - let r = check(&syntax); - - if let Err(errs) = r { - self.errors.insert(file_id, errs); - self.curr_phase = EvalPhase::Failed; - } else { - self.curr_phase = EvalPhase::BareTyped(file_id, syntax.clone()); - } - } - EvalPhase::BareTyped(file_id, syntax) => { - let ns = initialise_globals(); - let r = into_typed_repr(&ns, syntax); - - match r { - Ok(typed) => { - if self.cfg.debug_print_typed_repr { - println!("Typed repr: {typed:#?}"); - } - - todo!() - } - Err(errs) => { - self.errors.insert(file_id, vec![errs]); - self.curr_phase = EvalPhase::Failed; - } - } - } - EvalPhase::Failed => self.error_out().expect("unable to print errors"), - } - self.next(); - } - - pub fn error_out(self) -> Result { - let Evaluator { files, errors, .. } = self; - - let writer = StandardStream::stderr(ColorChoice::Always); - let config = term::Config::default(); - - for (file_id, errors) in &errors { - let writer = &mut writer.lock(); - for error in errors { - term::emit(writer, &config, &files, &error.into_diag(*file_id, &files))?; - } - } - - exit(1) - } -} - -enum EvalPhase { - Lex, - Check(FileId, Vec), - BareTyped(FileId, Vec), - Failed, -} diff --git a/src/globals.rs b/src/globals.rs deleted file mode 100644 index 3de4b77..0000000 --- a/src/globals.rs +++ /dev/null @@ -1,26 +0,0 @@ -// concepts -// root type namespace -// -> builtin types/traits/functions -// -> builtin constants -// -// generic item namespaces -// -> in generic functions ( `add [ T T ] -> T` ) -// -> in generic types ( vec ) -// -> generic traits ( T: From ) -// -// TODO: how builtins? just compile everything to builtin types/defs? - -/// This is the root type namespace. -struct RootTypeNamespace { - -} - -mod r#type { - -} -struct Type<'a> { - pub(super) id: usize, - pub(super) namespace: &'a GlobalNamespace, -} - -struct InternalType diff --git a/src/lexer.rs b/src/lexer.rs deleted file mode 100644 index 917a4e9..0000000 --- a/src/lexer.rs +++ /dev/null @@ -1,58 +0,0 @@ -use logos::Logos; - -#[derive(Logos, Debug, PartialEq)] -#[logos(skip r"[\s]+")] -pub enum Token<'a> { - #[regex("[\\w]+", |lex| lex.slice())] - Word(&'a str), - #[regex("[\\d]+", priority = 2, callback = |lex| lex.slice().parse::().expect("regex should only match valid integers. This is a bug."))] - IntLiteral(i64), - #[regex("[\\d]+\\.[\\d]+", |lex| lex.slice().parse::().expect("regex should only match valid floats. This is a bug."))] - FloatLiteral(f64), - #[regex(r#""([^"\\]|\\["\\bnfrt]|u[a-fA-F0-9]{4})*""#, |lex| lex.slice().to_owned())] - StringLiteral(String), - #[token("|")] - Pipe, - // #[token("def")] - // Define, - // #[token("type")] - // Type, - // #[token("->")] - // RightArrow, - // #[token("[")] - // BracketOpening, - // #[token("]")] - // BracketClosing, - // #[token("(")] - // ParensOpening, - // #[token(")")] - // ParensClosing, - // #[token("{")] - // BraceOpening, - // #[token("}")] - // BraceClosing, - // #[token("+")] - // Plus, - // #[token("-")] - // Minus, - // #[token("*")] - // Multiply, - // #[token("/")] - // Divide, - // #[token("%")] - // Percent, - // #[token("&")] - // Ampersand, - // #[token(":")] - // Colon, - // #[token(";")] - // Semicolon, - // #[token(".")] - // Dot, - // #[token(",")] - // Comma, - // #[token("!")] - // ExclaimationMark, - // #[token("?")] - // QuestionMark, -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index d8a67e7..0000000 --- a/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![feature(never_type, lint_reasons)] - -use std::ops::Range; - -pub mod args; -pub mod builtins; -pub mod error; -pub mod evaluator; - -#[allow(clippy::indexing_slicing, reason = "in logos, outside our control")] -pub mod lexer; - -pub mod namespace; -pub mod syntax; - -#[allow(dead_code, reason = "the future!!!")] -pub mod typed; - -// basically logos::Span but in this repo -pub type Span = Range; diff --git a/src/main.rs b/src/main.rs deleted file mode 100644 index 2727830..0000000 --- a/src/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -use clap::Parser; -use pipeline_lang::args::Args; -use pipeline_lang::evaluator::{EvalConfig, Evaluator}; - -fn main() { - let args = Args::parse(); - - let mut evaluator = Evaluator::init(EvalConfig::new(args.debug_tokens, args.debug_typed_repr)); - - evaluator.run(&args.text, None); - evaluator.next(); -} diff --git a/src/namespace/command.rs b/src/namespace/command.rs deleted file mode 100644 index 9513ca2..0000000 --- a/src/namespace/command.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::fmt::Debug; -use std::fmt::Display; - -use super::typedef::{InternalTypeDef, TypeDef}; -use super::CommandId; - -use super::GlobalNamespace; - -#[derive(Clone, Copy)] -pub struct Command<'a> { - pub(super) id: CommandId, - pub(super) namespace: &'a GlobalNamespace, -} - -impl<'a> Command<'a> { - pub fn get_input_types(&self) -> Option> { - self.namespace.commands.borrow()[self.id] - .input - .as_ref() - .map(|def| TypeDef::from_internal(self.namespace, def)) - } - // get a count of inputs required - pub fn input_count(&self) -> usize { - self.namespace.commands.borrow()[self.id] - .input - .as_ref() - .map_or(0, |inputs| match inputs { - InternalTypeDef::Single(_) | InternalTypeDef::Generic(_) => 1, - InternalTypeDef::List(list) => list.len(), - InternalTypeDef::Record(rec) => rec.len(), - }) - } - pub fn get_output_types(&self) -> Option { - self.namespace.commands.borrow()[self.id] - .output - .as_ref() - .map(|def| TypeDef::from_internal(self.namespace, def)) - } -} - -impl Display for Command<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = &self.namespace.commands.borrow()[self.id].name; - f.write_fmt(format_args!( - "{name} {} -> {}", - self.get_input_types() - .map_or("!".to_owned(), |v| v.to_string()), - self.get_output_types() - .map_or("!".to_owned(), |v| v.to_string()) - )) - } -} - -impl Debug for Command<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = &self.namespace.commands.borrow()[self.id].name; - f.write_fmt(format_args!( - "{name:?} {:?} -> {:?}", - self.get_input_types(), - self.get_output_types() - )) - } -} - -pub(super) struct InternalCommand { - pub(super) name: String, - // gosh this is hacky - pub(super) input: Option, - pub(super) output: Option, -} diff --git a/src/namespace/mod.rs b/src/namespace/mod.rs deleted file mode 100644 index 5931ae6..0000000 --- a/src/namespace/mod.rs +++ /dev/null @@ -1,213 +0,0 @@ -use std::{ - cell::RefCell, - collections::{HashMap, HashSet}, -}; - -use self::{ - command::{Command, InternalCommand}, - r#trait::{InternalTrait, Trait}, - r#type::{InternalType, Type}, - typedef::TypeDef, -}; - -pub mod command; -pub mod r#trait; -pub mod r#type; -pub mod typedef; - -pub struct GlobalNamespace { - types: RefCell>, - traits: RefCell>, - type_namespace: RefCell>, - commands: RefCell>, - data_namespace: RefCell>, -} - -pub type TypeId = usize; -pub type TraitId = usize; -pub type CommandId = usize; - -enum TypeNamespaceId { - Types(TypeId), - Traits(TraitId), -} - -enum DataNamespaceId { - Commands(CommandId), -} - -impl GlobalNamespace { - pub fn init() -> Self { - Self { - types: RefCell::new(Vec::new()), - traits: RefCell::new(Vec::new()), - type_namespace: RefCell::new(HashMap::new()), - commands: RefCell::new(Vec::new()), - data_namespace: RefCell::new(HashMap::new()), - } - } - - /// register a type to the namespace - /// - /// # Errors - /// - /// Will return `NsRegistrationError::NameAlreadyExists` if the desired name is already in use - pub fn register_type(&self, name: &str) -> Result { - if self.type_namespace.borrow().contains_key(name) { - Err(NsRegistrationError::NameAlreadyExists) - } else { - self.types.borrow_mut().push(InternalType { - traits: RefCell::new(HashSet::new()), - name: name.to_owned(), - }); - let id = self.types.borrow().len() - 1; - let _ = self - .type_namespace - .borrow_mut() - .insert(name.to_owned(), TypeNamespaceId::Types(id)); - Ok(Type { - id, - namespace: self, - }) - } - } - - /// register a trait to the namespace - /// - /// # Errors - /// - /// Will return `NsRegistrationError::NameAlreadyExists` if the desired name is already in use - pub fn register_trait(&self, name: &str) -> Result { - if self.type_namespace.borrow().contains_key(name) { - Err(NsRegistrationError::NameAlreadyExists) - } else { - self.traits.borrow_mut().push(InternalTrait { - types: RefCell::new(HashSet::new()), - name: name.to_owned(), - }); - let id = self.traits.borrow().len() - 1; - let _ = self - .type_namespace - .borrow_mut() - .insert(name.to_owned(), TypeNamespaceId::Traits(id)); - Ok(Trait { - id, - namespace: self, - }) - } - } - - /// register a command to the namespace - /// - /// # Errors - /// - /// Will return `NsRegistrationError::NameAlreadyExists` if the desired name is already in use - pub fn register_command<'a>( - &self, - name: &'a str, - // TODO: refacto with builder pattern maybe? - generics: Vec<(&'a str, Vec<&Trait>)>, - input: Option<&'a TypeDef>, - output: Option<&'a TypeDef>, - ) -> Result> { - if self.data_namespace.borrow().contains_key(name) { - Err(NsRegistrationError::NameAlreadyExists) - } else { - let mut internal_generics_namespace: HashMap> = HashMap::new(); - - for (name, conditions) in generics { - if internal_generics_namespace.contains_key(name) { - return Err(NsRegistrationError::GenericNameAlreadyExists); - } - internal_generics_namespace - .insert(name.to_owned(), conditions.iter().map(|t| t.id).collect()); - } - - if let Some(def) = input { - def.check_generics_exist(&internal_generics_namespace) - .map_err(NsRegistrationError::UnregisteredGenericsUsed)?; - } - - if let Some(def) = output { - def.check_generics_exist(&internal_generics_namespace) - .map_err(NsRegistrationError::UnregisteredGenericsUsed)?; - } - - self.commands.borrow_mut().push(InternalCommand { - name: name.to_owned(), - input: input.map(std::convert::Into::into), - output: output.map(std::convert::Into::into), - }); - let id = self.traits.borrow().len() - 1; - let _ = self - .data_namespace - .borrow_mut() - .insert(name.to_owned(), DataNamespaceId::Commands(id)); - Ok(Command { - id, - namespace: self, - }) - } - } - - pub fn get_type(&self, id: TypeId) -> Option { - (self.types.borrow().len() > id).then_some(Type { - id, - namespace: self, - }) - } - - pub fn get_trait(&self, id: TraitId) -> Option { - (self.traits.borrow().len() > id).then_some(Trait { - id, - namespace: self, - }) - } - - pub fn get_command(&self, id: CommandId) -> Option { - (self.commands.borrow().len() > id).then_some(Command { - id, - namespace: self, - }) - } - - pub fn get_type_by_name(&self, name: &str) -> Option { - if let Some(TypeNamespaceId::Types(id)) = self.type_namespace.borrow().get(name) { - Some(Type { - id: *id, - namespace: self, - }) - } else { - None - } - } - - pub fn get_trait_by_name(&self, name: &str) -> Option { - if let Some(TypeNamespaceId::Traits(id)) = self.type_namespace.borrow().get(name) { - Some(Trait { - id: *id, - namespace: self, - }) - } else { - None - } - } - - pub fn get_command_by_name(&self, name: &str) -> Option { - if let Some(DataNamespaceId::Commands(id)) = self.data_namespace.borrow().get(name) { - Some(Command { - id: *id, - namespace: self, - }) - } else { - None - } - } -} - -#[derive(Debug)] -pub enum NsRegistrationError<'a> { - NameAlreadyExists, - GenericNameAlreadyExists, - UnregisteredGenericsUsed(Vec<&'a str>), -} diff --git a/src/namespace/trait.rs b/src/namespace/trait.rs deleted file mode 100644 index 9cb3f74..0000000 --- a/src/namespace/trait.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::collections::HashSet; - -use std::cell::RefCell; -use std::fmt::Debug; -use std::fmt::Display; - -use super::GlobalNamespace; -use super::TraitId; -use super::TypeId; - -#[derive(Clone, Copy)] -pub struct Trait<'a> { - pub(super) id: TraitId, - pub(super) namespace: &'a GlobalNamespace, -} - -impl Display for Trait<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = &self.namespace.traits.borrow()[self.id].name; - - f.write_fmt(format_args!("{name}")) - } -} - -impl Debug for Trait<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Trait({self})") - } -} - -pub(super) struct InternalTrait { - // make resolution easier - pub(super) types: RefCell>, - pub(super) name: String, -} diff --git a/src/namespace/type.rs b/src/namespace/type.rs deleted file mode 100644 index 18a1bad..0000000 --- a/src/namespace/type.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::collections::HashSet; - -use std::cell::RefCell; -use std::fmt::Debug; -use std::fmt::Display; - -use super::Trait; - -use super::GlobalNamespace; -use super::TraitId; -use super::TypeId; - -#[derive(Clone, Copy)] -pub struct Type<'a> { - pub(super) id: TypeId, - pub(super) namespace: &'a GlobalNamespace, -} - -impl<'a> Type<'a> { - pub fn add_trait(&self, to_add: &'a Trait) { - let internal_self = &self.namespace.types.borrow()[self.id]; - - internal_self.traits.borrow_mut().insert(to_add.id); - self.namespace.traits.borrow_mut()[to_add.id] - .types - .borrow_mut() - .insert(self.id); - } - - pub fn has_trait(&self, to_check: &'a Trait) -> bool { - self.namespace.types.borrow()[self.id] - .traits - .borrow() - .contains(&to_check.id) - } -} - -impl Display for Type<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let name = &self.namespace.types.borrow()[self.id].name; - - f.write_fmt(format_args!("{name}")) - } -} - -impl Debug for Type<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Type({self})") - } -} - -pub(super) struct InternalType { - pub(super) traits: RefCell>, - pub(super) name: String, -} diff --git a/src/namespace/typedef.rs b/src/namespace/typedef.rs deleted file mode 100644 index 8afb772..0000000 --- a/src/namespace/typedef.rs +++ /dev/null @@ -1,184 +0,0 @@ -use std::collections::HashMap; -use std::fmt::Debug; -use std::fmt::Display; - -use super::TraitId; -use super::TypeId; - -use super::GlobalNamespace; - -use super::r#type::Type; - -pub enum TypeDef<'a> { - Type(Type<'a>), - Generic(String), - List(Vec>), - Record(Vec<(String, TypeDef<'a>)>), -} - -impl<'a> TypeDef<'a> { - pub(super) fn check_generics_exist( - &'a self, - map: &HashMap>, - ) -> Result<(), Vec<&'a str>> { - match self { - TypeDef::Type(_) => Ok(()), - TypeDef::Generic(name) => { - if map.contains_key(name) { - Ok(()) - } else { - Err(vec![name]) - } - } - TypeDef::List(defs) => { - let r = defs - .iter() - .map(|def| def.check_generics_exist(map)) - .filter_map(|check_res| { - if let Err(invalid_names) = check_res { - Some(invalid_names) - } else { - None - } - }) - .reduce(|mut acc, mut errs| { - acc.append(&mut errs); - acc - }); - - match r { - Some(e) => Err(e), - None => Ok(()), - } - } - TypeDef::Record(rec) => { - let r = rec - .iter() - .map(|(_n, def)| def.check_generics_exist(map)) - .filter_map(|check_res| { - if let Err(invalid_names) = check_res { - Some(invalid_names) - } else { - None - } - }) - .reduce(|mut acc, mut errs| { - acc.append(&mut errs); - acc - }); - - match r { - Some(e) => Err(e), - None => Ok(()), - } - } - } - } - pub(super) fn from_internal(ns: &'a GlobalNamespace, def: &InternalTypeDef) -> TypeDef<'a> { - match def { - InternalTypeDef::Single(id) => TypeDef::Type( - ns.get_type(*id) - .expect("Unregistered internal type ID. This is a bug."), - ), - InternalTypeDef::Generic(name) => TypeDef::Generic(name.clone()), - InternalTypeDef::List(list) => TypeDef::List( - list.iter() - .map(|def| Self::from_internal(ns, def)) - .collect(), - ), - InternalTypeDef::Record(rec) => TypeDef::Record( - rec.iter() - .map(|(name, def)| (name.clone(), Self::from_internal(ns, def))) - .collect(), - ), - } - } -} - -impl Display for TypeDef<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - TypeDef::Type(t) => Display::fmt(&t, f), - TypeDef::Generic(name) => Display::fmt(name, f), - TypeDef::List(l) => { - f.write_str("[ ")?; - if let Some(first) = l.first() { - Display::fmt(&first, f)?; - } - for item in l.iter().skip(1) { - f.write_str(", ")?; - Display::fmt(&item, f)?; - } - f.write_str(" ]") - } - TypeDef::Record(rec) => { - f.write_str("{ ")?; - for (i, item) in rec.iter().enumerate() { - if i != 0 { - f.write_str(", ")?; - } - f.write_fmt(format_args!("{}: {}", item.0, item.1))?; - } - f.write_str(" }") - } - } - } -} - -impl Debug for TypeDef<'_> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - TypeDef::Type(t) => Debug::fmt(&t, f), - TypeDef::Generic(name) => Debug::fmt(name, f), - TypeDef::List(l) => { - f.write_str("[ ")?; - for (i, item) in l.iter().enumerate() { - if i != 0 { - f.write_str(", ")?; - } - Debug::fmt(&item, f)?; - } - f.write_str(" ]") - } - TypeDef::Record(rec) => { - f.write_str("{ ")?; - for (i, item) in rec.iter().enumerate() { - if i != 0 { - f.write_str(", ")?; - } - f.write_fmt(format_args!("{:?}: {:?}", item.0, item.1))?; - } - f.write_str(" }") - } - } - } -} - -impl<'a> From> for TypeDef<'a> { - fn from(value: Type<'a>) -> Self { - TypeDef::Type(value) - } -} - -pub(super) enum InternalTypeDef { - Single(TypeId), - Generic(String), - List(Vec), - Record(Vec<(String, InternalTypeDef)>), -} - -impl From<&TypeDef<'_>> for InternalTypeDef { - fn from(value: &TypeDef) -> Self { - match value { - TypeDef::Type(val) => Self::Single(val.id), - // TODO: rewrite this to be better - TypeDef::Generic(name) => Self::Generic(name.to_owned()), - TypeDef::List(list) => Self::List(list.iter().map(std::convert::Into::into).collect()), - TypeDef::Record(rec) => Self::Record( - rec.iter() - .map(|(name, typ)| (name.to_owned(), typ.into())) - .collect(), - ), - } - } -} diff --git a/src/syntax/check.rs b/src/syntax/check.rs deleted file mode 100644 index ff5b76e..0000000 --- a/src/syntax/check.rs +++ /dev/null @@ -1,214 +0,0 @@ -#[cfg(test)] -#[allow(clippy::unwrap_used, reason = "these are tests. they may unwrap.")] -mod test; - -use crate::{ - error::{ErrorKind, Errors, SyntaxErrorKind}, - syntax::CommandPart, -}; - -use super::{CommandPartKind, PipelineElement, PipelineElementKind}; - -pub fn check(syntax: &[PipelineElement]) -> Result<(), Vec> { - let mut errs = Vec::new(); - - if let Err(e_span) = check_missing_streamer(syntax) { - errs.push(Errors::new_single( - ErrorKind::SyntaxError(SyntaxErrorKind::MissingStreamer), - e_span, - )); - } - - if let Err(err_locs) = check_missing_filters(syntax) { - errs.push(Errors::new( - ErrorKind::SyntaxError(SyntaxErrorKind::MissingFilter), - err_locs, - )); - } - - if let Err(e_span) = check_missing_sink(syntax) { - errs.push(Errors::new_single( - ErrorKind::SyntaxError(SyntaxErrorKind::MissingSink), - e_span, - )); - } - - if let Err(e_span) = check_literal_as_sink(syntax) { - errs.push(Errors::new_single( - ErrorKind::SyntaxError(SyntaxErrorKind::LiteralAsSink), - e_span, - )); - } - - if let Err(err_locs) = check_literal_as_filter(syntax) { - errs.push(Errors::new( - ErrorKind::SyntaxError(SyntaxErrorKind::LiteralAsFilter), - err_locs, - )); - } - - if let Err(e_span) = check_literal_with_args(syntax) { - errs.push(Errors::new_single( - ErrorKind::SyntaxError(SyntaxErrorKind::LiteralWithArgs), - e_span, - )); - } - - if errs.is_empty() { - Ok(()) - } else { - Err(errs) - } -} - -fn check_missing_streamer(syntax: &[PipelineElement]) -> Result<(), logos::Span> { - if let Some(&PipelineElement { - kind: PipelineElementKind::Pipe, - ref span, - }) = syntax.first() - { - Err(span.clone()) - } else { - Ok(()) - } -} - -fn check_missing_filters(syntax: &[PipelineElement]) -> Result<(), Vec> { - let mut missing_filter_locs = Vec::new(); - - for i in 0..syntax.len() { - if let ( - Some(&PipelineElement { - kind: PipelineElementKind::Pipe, - ref span, - }), - Some(&PipelineElement { - kind: PipelineElementKind::Pipe, - span: ref span1, - }), - ) = (syntax.get(i), syntax.get(i + 1)) - { - missing_filter_locs.push(span.start..span1.end); - } - } - - if missing_filter_locs.is_empty() { - Ok(()) - } else { - Err(missing_filter_locs) - } -} - -fn check_missing_sink(syntax: &[PipelineElement]) -> Result<(), logos::Span> { - if let Some(&PipelineElement { - kind: PipelineElementKind::Pipe, - ref span, - }) = syntax.last() - { - Err(span.clone()) - } else { - Ok(()) - } -} - -fn check_literal_as_sink(syntax: &[PipelineElement]) -> Result<(), logos::Span> { - let last_block: Option<&[PipelineElement]> = syntax - .split(|PipelineElement { kind, .. }| kind == &PipelineElementKind::Pipe) - .last(); - - // there HAS to be a better way to do this... this is HORRIBLE - if let Some(last_block) = last_block { - if let Some(PipelineElement { - kind: PipelineElementKind::Command(parts), - span, - }) = last_block.first() - { - if let Some(first_part) = parts.first() { - if matches!( - first_part, - CommandPart { - kind: CommandPartKind::Word(_), - .. - } - ) { - Ok(()) - } else { - Err(span.clone()) - } - } else { - Ok(()) - } - } else { - Ok(()) - } - } else { - Ok(()) - } -} - -fn check_literal_as_filter(syntax: &[PipelineElement]) -> Result<(), Vec> { - let errs = syntax - .iter() - .take(syntax.len() - 1) - .skip(1) - .filter(|element| { - !matches!( - element, - PipelineElement { - kind: PipelineElementKind::Pipe, - .. - } - ) - }) - .map(|item| { - let PipelineElement { - kind: PipelineElementKind::Command(c), - span, - } = item - else { - return None; - }; - - let Some(CommandPart { kind, .. }) = c.first() else { - return None; - }; - - if matches!(kind, CommandPartKind::Word(_)) { - None - } else { - Some(span) - } - }) - .filter_map(|err| err.map(Clone::clone)) - .collect::>(); - - if errs.is_empty() { - Ok(()) - } else { - Err(errs) - } -} - -fn check_literal_with_args(syntax: &[PipelineElement]) -> Result<(), logos::Span> { - if let Some(PipelineElement { - kind: PipelineElementKind::Command(c), - span, - }) = syntax.first() - { - if c.len() > 1 - && !matches!( - c.first(), - Some(CommandPart { - kind: CommandPartKind::Word(_), - .. - }) - ) - { - Err(span.clone()) - } else { - Ok(()) - } - } else { - Ok(()) - } -} diff --git a/src/syntax/check/test.rs b/src/syntax/check/test.rs deleted file mode 100644 index 9166ea3..0000000 --- a/src/syntax/check/test.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::syntax::{ - check::{ - check_literal_as_filter, check_literal_as_sink, check_literal_with_args, - check_missing_filters, check_missing_sink, check_missing_streamer, - }, - parse_syntax, -}; - -#[test] -fn test_check_missing_streamer() { - let test_data = "| invert | save \"./image_processed.jpg\""; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!(check_missing_streamer(&syntax), Err(0..1)); -} - -#[test] -fn test_check_missing_filters() { - let test_data = "meow | | test | awa | | nya"; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!(check_missing_filters(&syntax), Err(vec![5..8, 20..25])); -} - -#[test] -fn test_check_missing_sink() { - let test_data = "meow | invert | "; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!(check_missing_sink(&syntax), Err(14..15)); -} - -#[test] -fn test_check_literal_as_sink() { - let test_data = "meow | test | 3"; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!(check_literal_as_sink(&syntax), Err(14..15)); -} - -#[test] -fn test_check_literal_as_filter() { - let test_data = "meow | \"gay\" | 42 | 3.14 | uwu"; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!( - check_literal_as_filter(&syntax), - Err(vec![7..12, 15..17, 20..24]) - ); -} - -#[test] -fn test_check_literal_as_filter_positive_on_sink() { - let test_data = "meow | 42"; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!(check_literal_as_filter(&syntax), Ok(())); -} - -#[test] -fn test_check_literal_with_args() { - let test_data = "14 12 | sink"; - let syntax = parse_syntax(test_data).unwrap(); - - assert_eq!(check_literal_with_args(&syntax), Err(0..5)); -} diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs deleted file mode 100644 index cb4bbfd..0000000 --- a/src/syntax/mod.rs +++ /dev/null @@ -1,110 +0,0 @@ -use logos::Logos; -use logos::Span; - -use crate::lexer::Token; - -pub mod check; - -#[derive(Debug, Clone, PartialEq)] -pub struct PipelineElement { - pub kind: PipelineElementKind, - pub span: Span, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum PipelineElementKind { - Pipe, - Command(Vec), -} - -#[derive(Debug, Clone, PartialEq)] -pub struct CommandPart { - pub kind: CommandPartKind, - pub span: Span, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum CommandPartKind { - Word(String), - Integer(i64), - Float(f64), - String(String), -} - -pub fn parse_syntax(input: &str) -> Result, Vec> { - let lexer = Token::lexer(input); - let mut errs = Vec::new(); - - let mut r = Vec::new(); - - let mut partial_command: Vec = Vec::new(); - for (tok, span) in lexer.spanned() { - if let Ok(tok) = tok { - match tok { - Token::Pipe => { - if !partial_command.is_empty() { - #[allow( - clippy::unwrap_used, - reason = "this branch can only run if partial_command isn't empty" - )] - let span = partial_command.first().unwrap().span.start - ..partial_command.last().unwrap().span.end; - r.push(PipelineElement { - kind: PipelineElementKind::Command(std::mem::take( - &mut partial_command, - )), - span, - }); - } - r.push(PipelineElement { - kind: PipelineElementKind::Pipe, - span, - }); - } - Token::Word(word) => partial_command.push(CommandPart { - kind: CommandPartKind::Word(word.to_owned()), - span, - }), - Token::IntLiteral(int) => partial_command.push(CommandPart { - kind: CommandPartKind::Integer(int), - span, - }), - Token::FloatLiteral(float) => partial_command.push(CommandPart { - kind: CommandPartKind::Float(float), - span, - }), - Token::StringLiteral(string) => partial_command.push(CommandPart { - kind: CommandPartKind::String(string), - span, - }), - } - } else { - errs.push(span); - } - } - - if !partial_command.is_empty() { - #[allow( - clippy::unwrap_used, - reason = "this branch can only run if partial_command isn't empty" - )] - let span = - partial_command.first().unwrap().span.start..partial_command.last().unwrap().span.end; - r.push(PipelineElement { - kind: PipelineElementKind::Command(std::mem::take(&mut partial_command)), - span, - }); - } - - if errs.is_empty() { - Ok(r) - } else { - Err(errs) - } -} - -#[test] -fn test_invalid_toks() { - let test_data = "meow | gay $ error!"; - assert_eq!(parse_syntax(test_data), Err(vec![11..12, 18..19])); -} diff --git a/src/typed.rs b/src/typed.rs deleted file mode 100644 index fbe86ab..0000000 --- a/src/typed.rs +++ /dev/null @@ -1,234 +0,0 @@ -use core::panic; - -use crate::{ - builtins::{TYPE_FLOAT, TYPE_INTEGER, TYPE_STRING}, - error::Errors, - namespace::{command::Command, r#type::Type, typedef::TypeDef, GlobalNamespace}, - syntax::{CommandPart, CommandPartKind, PipelineElement, PipelineElementKind}, - Span, -}; - -#[allow(dead_code, reason = "will be used later")] -#[derive(Debug)] -pub struct Expr<'a> { - kind: ExprKind<'a>, - span: Span, -} - -impl<'a> Expr<'a> { - fn try_find_concrete(&'a self, ns: &'a GlobalNamespace) -> IoTypes<'a> { - let Self { ref kind, .. } = self; - kind.try_find_concrete(ns) - } - - fn get_input_typedef(&'a self) -> Option> { - match &self.kind { - ExprKind::Command(c) => c.command.get_input_types(), - ExprKind::Literal(_) => None, - } - } -} - -#[derive(Debug)] -pub enum ExprKind<'a> { - Command(CommandExpr<'a>), - Literal(LiteralKind), -} - -impl<'a> ExprKind<'a> { - fn try_find_concrete(&'a self, ns: &'a GlobalNamespace) -> IoTypes<'a> { - match self { - ExprKind::Literal(lit) => IoTypes::Concrete(lit.get_type(ns)), - ExprKind::Command(c) => c.try_find_concrete(ns), - } - } -} - -#[derive(Debug)] -pub struct CommandExpr<'a> { - command: Command<'a>, - args: Vec>, -} - -impl<'a> CommandExpr<'a> { - fn try_find_concrete(&'a self, _ns: &'a GlobalNamespace) -> IoTypes<'a> { - let Self { command, .. } = self; - - match command.get_output_types() { - None => IoTypes::Empty, - Some(def) => { - if let Some(concrete) = ConcreteTypeDef::try_from_typedef(&def) { - IoTypes::Concrete(concrete) - } else { - // TODO: make it possible to get clear output type - IoTypes::Unclear - } - } - } - } -} - -#[derive(Debug)] -pub enum LiteralKind { - Int(i64), - Float(f64), - String(String), -} - -enum IoTypes<'a> { - /// expression does not expect/return anything - Empty, - /// expression does expect/return something, but some types are unclear - Unclear, - /// we know for sure what types the expression expects/returns - Concrete(ConcreteTypeDef<'a>), -} - -impl LiteralKind { - #[allow( - clippy::unwrap_used, - reason = "these are fetched by type name constants used for keeping names consistent in codebase, which cannot be None" - )] - fn get_type<'a>(&self, ns: &'a GlobalNamespace) -> ConcreteTypeDef<'a> { - ConcreteTypeDef::Single(match self { - LiteralKind::Int(_) => ns.get_type_by_name(TYPE_INTEGER).unwrap(), - LiteralKind::Float(_) => ns.get_type_by_name(TYPE_FLOAT).unwrap(), - LiteralKind::String(_) => ns.get_type_by_name(TYPE_STRING).unwrap(), - }) - } -} - -pub fn into_typed_repr( - ns: &GlobalNamespace, - syntax: Vec, -) -> Result, Errors> { - let mut res = Vec::new(); - let mut errs = Vec::new(); - - for item in syntax { - let PipelineElement { kind, span } = item; - match kind { - PipelineElementKind::Command(c) => { - if c.len() == 1 { - let CommandPart { kind, .. } = &c[0]; - - res.push(Expr { - kind: match kind { - CommandPartKind::Word(val) => ExprKind::Command(CommandExpr { - command: { - let Some(c) = ns.get_command_by_name(val) else { - errs.push(span); - continue; - }; - c - }, - args: Vec::new(), - }), - CommandPartKind::Integer(val) => { - ExprKind::Literal(LiteralKind::Int(*val)) - } - CommandPartKind::Float(val) => { - ExprKind::Literal(LiteralKind::Float(*val)) - } - CommandPartKind::String(val) => { - ExprKind::Literal(LiteralKind::String(val.clone())) - } - }, - span, - }); - } else { - let Some(CommandPart { - kind: CommandPartKind::Word(name), - span, - }) = c.first() - else { - panic!("tried conversion to typed representation with invalid syntax") - }; - - res.push(Expr { - kind: ExprKind::Command(CommandExpr { - command: { - let Some(c) = ns.get_command_by_name(name) else { - errs.push(span.clone()); - continue; - }; - c - }, - args: c - .iter() - .skip(1) - .map(|CommandPart { kind, span }| Expr { - kind: ExprKind::Literal(match kind { - CommandPartKind::String(val) - | CommandPartKind::Word(val) => { - LiteralKind::String(val.to_string()) - } - CommandPartKind::Integer(val) => LiteralKind::Int(*val), - CommandPartKind::Float(val) => LiteralKind::Float(*val), - }), - span: span.clone(), - }) - .collect(), - }), - span: span.clone(), - }); - } - } - PipelineElementKind::Pipe => {} - } - } - - if errs.is_empty() { - Ok(res) - } else { - Err(Errors::new(crate::error::ErrorKind::CommandNotFound, errs)) - } -} - -enum ConcreteTypeDef<'a> { - Single(Type<'a>), - List(Vec>), - Record(Vec<(String, ConcreteTypeDef<'a>)>), -} - -impl<'a> ConcreteTypeDef<'a> { - fn try_from_typedef(val: &TypeDef<'a>) -> Option { - match val { - TypeDef::Type(typ) => Some(Self::Single(*typ)), - TypeDef::Generic(_) => todo!(), - TypeDef::List(list) => { - let out: Vec> = - list.iter().filter_map(Self::try_from_typedef).collect(); - - (out.len() == list.len()).then_some(ConcreteTypeDef::List(out)) - } - TypeDef::Record(rec) => { - let out: Vec<(String, ConcreteTypeDef<'a>)> = rec - .iter() - .filter_map(|(name, def)| { - Self::try_from_typedef(def).map(|def| (name.clone(), def)) - }) - .collect(); - - (out.len() == rec.len()).then_some(ConcreteTypeDef::Record(out)) - } - } - } -} - -struct TypeChecker<'a> { - global_ns: &'a GlobalNamespace, - typed_syntax: Vec>, -} - -impl<'a> TypeChecker<'a> { - fn new(ns: &'a GlobalNamespace, syntax: Vec>) -> TypeChecker<'a> { - Self { - global_ns: ns, - typed_syntax: syntax, - } - } - - // not sure if this is the optimal alg, or even a working one, but lets see - fn check_forward() {} -} diff --git a/testfiles/bare.rpl b/testfiles/bare.rpl new file mode 100644 index 0000000..1770e37 --- /dev/null +++ b/testfiles/bare.rpl @@ -0,0 +1,12 @@ +( + [ + Read(( + source: File("/home/jade/example/file.png"), + format: Png + )), + Write(( + target: File("/home/jade/example/out.jpg"), + format: Jpeg + )) + ] +) diff --git a/testfiles/invert.rpl b/testfiles/invert.rpl new file mode 100644 index 0000000..d17fe1a --- /dev/null +++ b/testfiles/invert.rpl @@ -0,0 +1,13 @@ +( + [ + Read(( + source: File("/home/jade/example/file.png"), + format: Png + )), + Filter(Invert), + Write(( + target: File("/home/jade/example/inverted.jpg"), + format: Jpeg + )) + ] +)