Compare commits
7 commits
49995bbc62
...
34fc4f1caf
Author | SHA1 | Date | |
---|---|---|---|
34fc4f1caf | |||
a3a7a00808 | |||
e7863402f3 | |||
2b3c74053e | |||
b92977d8f1 | |||
f046393af8 | |||
b4d48a598a |
41 changed files with 770 additions and 1694 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
.direnv/
|
.direnv/
|
||||||
/target
|
/target
|
||||||
.pre-commit-config.yaml
|
.pre-commit-config.yaml
|
||||||
|
*.pdf
|
||||||
|
|
3
.helix/languages.toml
Normal file
3
.helix/languages.toml
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[[language]]
|
||||||
|
name = "ron"
|
||||||
|
file-types = [ "rpl" ]
|
518
Cargo.lock
generated
518
Cargo.lock
generated
|
@ -3,10 +3,16 @@
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "adler"
|
||||||
version = "0.6.4"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
|
@ -24,43 +30,88 @@ checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-query"
|
name = "anstyle-query"
|
||||||
version = "1.0.0"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "3.0.1"
|
version = "3.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "beef"
|
name = "autocfg"
|
||||||
version = "0.5.2"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.4.8"
|
version = "4.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2275f18819641850fa26c89acc84d465c1bf91ce57bc2748b28c420473352f64"
|
checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
@ -68,9 +119,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.4.8"
|
version = "4.4.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "07cdf1b148b25c1e1f7a42225e30a0d99a615cd4637eae7365548dd4529b95bc"
|
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
@ -97,14 +148,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "color_quant"
|
||||||
version = "0.11.1"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
|
||||||
dependencies = [
|
|
||||||
"termcolor",
|
|
||||||
"unicode-width",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
|
@ -113,10 +160,128 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "crc32fast"
|
||||||
version = "1.0.7"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
@ -125,55 +290,129 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "logos"
|
name = "image"
|
||||||
version = "0.13.0"
|
version = "0.24.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c000ca4d908ff18ac99b93a062cb8958d331c3220719c52e77cb19cc6ac5d2c1"
|
checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"logos-derive",
|
"bytemuck",
|
||||||
|
"byteorder",
|
||||||
|
"color_quant",
|
||||||
|
"exr",
|
||||||
|
"gif",
|
||||||
|
"jpeg-decoder",
|
||||||
|
"num-rational",
|
||||||
|
"num-traits",
|
||||||
|
"png",
|
||||||
|
"qoi",
|
||||||
|
"tiff",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "logos-codegen"
|
name = "jpeg-decoder"
|
||||||
version = "0.13.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc487311295e0002e452025d6b580b77bb17286de87b57138f3b5db711cded68"
|
checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"beef",
|
"rayon",
|
||||||
"fnv",
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"regex-syntax",
|
|
||||||
"syn",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "logos-derive"
|
name = "lebe"
|
||||||
version = "0.13.0"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"logos-codegen",
|
"autocfg",
|
||||||
|
"scopeguard",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[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"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"codespan-reporting",
|
"executor",
|
||||||
"logos",
|
"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]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
|
checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "qoi"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.33"
|
version = "1.0.33"
|
||||||
|
@ -184,10 +423,91 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "rayon"
|
||||||
version = "0.6.29"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "strsim"
|
name = "strsim"
|
||||||
|
@ -197,9 +517,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.39"
|
version = "2.0.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
|
checksum = "44c8b28c477cc3bf0e7966561e3460130e1255f7a1cf71931075f1c5e7a7e269"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -207,12 +527,14 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "tiff"
|
||||||
version = "1.4.0"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff1bc3d3f05aff0403e8ac0d92ced918ec05b666a43f83297ccef5bea8a3d449"
|
checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"flate2",
|
||||||
|
"jpeg-decoder",
|
||||||
|
"weezl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -221,12 +543,6 @@ version = "1.0.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "unicode-width"
|
|
||||||
version = "0.1.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -234,50 +550,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "weezl"
|
||||||
version = "0.3.9"
|
version = "0.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb"
|
||||||
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"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets",
|
"windows-targets",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc",
|
||||||
|
@ -290,42 +581,51 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.52.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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",
|
||||||
|
]
|
||||||
|
|
19
Cargo.toml
19
Cargo.toml
|
@ -1,14 +1,13 @@
|
||||||
[package]
|
[workspace]
|
||||||
name = "pipeline-lang"
|
members = [
|
||||||
version = "0.1.0"
|
"crates/executor",
|
||||||
edition = "2021"
|
"crates/pl-cli",
|
||||||
|
"crates/rpl"
|
||||||
|
]
|
||||||
|
resolver = "2"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
[workspace.dependencies]
|
||||||
|
clap = { version = "4", features = [ "derive" ] }
|
||||||
[dependencies]
|
|
||||||
logos = "0.13"
|
|
||||||
codespan-reporting = "0.11"
|
|
||||||
clap = { version = "4.4.8", features = [ "derive" ] }
|
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unsafe_code = "deny"
|
unsafe_code = "deny"
|
||||||
|
|
11
crates/executor/Cargo.toml
Normal file
11
crates/executor/Cargo.toml
Normal file
|
@ -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" }
|
1
crates/executor/src/cpu/mod.rs
Normal file
1
crates/executor/src/cpu/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub(crate) struct CpuExecutor;
|
41
crates/executor/src/debug/instructions/mod.rs
Normal file
41
crates/executor/src/debug/instructions/mod.rs
Normal file
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
crates/executor/src/debug/mod.rs
Normal file
37
crates/executor/src/debug/mod.rs
Normal file
|
@ -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<DynamicValue>) -> Option<DynamicValue> {
|
||||||
|
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"),
|
||||||
|
}),
|
||||||
|
)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
crates/executor/src/lib.rs
Normal file
38
crates/executor/src/lib.rs
Normal file
|
@ -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<DynamicValue>) -> Option<DynamicValue>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute_all(instructions: Vec<Instruction>) {
|
||||||
|
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
|
5
crates/executor/src/value/mod.rs
Normal file
5
crates/executor/src/value/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use image::DynamicImage;
|
||||||
|
|
||||||
|
pub enum DynamicValue {
|
||||||
|
Image(DynamicImage),
|
||||||
|
}
|
11
crates/pl-cli/Cargo.toml
Normal file
11
crates/pl-cli/Cargo.toml
Normal file
|
@ -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" }
|
19
crates/pl-cli/src/main.rs
Normal file
19
crates/pl-cli/src/main.rs
Normal file
|
@ -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);
|
||||||
|
}
|
10
crates/rpl/Cargo.toml
Normal file
10
crates/rpl/Cargo.toml
Normal file
|
@ -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"
|
47
crates/rpl/src/instructions/mod.rs
Normal file
47
crates/rpl/src/instructions/mod.rs
Normal file
|
@ -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,
|
||||||
|
}
|
19
crates/rpl/src/instructions/read.rs
Normal file
19
crates/rpl/src/instructions/read.rs
Normal file
|
@ -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,
|
||||||
|
}
|
19
crates/rpl/src/instructions/write.rs
Normal file
19
crates/rpl/src/instructions/write.rs
Normal file
|
@ -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,
|
||||||
|
}
|
38
crates/rpl/src/lib.rs
Normal file
38
crates/rpl/src/lib.rs
Normal file
|
@ -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<Instruction>);
|
||||||
|
|
||||||
|
#[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
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
}
|
3
crates/rpl/src/value/mod.rs
Normal file
3
crates/rpl/src/value/mod.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub enum DynamicValue {
|
||||||
|
Image(DynamicImage),
|
||||||
|
}
|
10
docs/design/types.typ
Normal file
10
docs/design/types.typ
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#import "../template.typ": conf
|
||||||
|
#show: doc => conf(
|
||||||
|
doc
|
||||||
|
)
|
||||||
|
|
||||||
|
= meow nya
|
||||||
|
|
||||||
|
nyanyanya
|
||||||
|
|
||||||
|
#lorem(50)
|
12
docs/template.typ
Normal file
12
docs/template.typ
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#let conf(
|
||||||
|
doc
|
||||||
|
) = {
|
||||||
|
set text(font: "Atkinson Hyperlegible");
|
||||||
|
show heading: it => [
|
||||||
|
#set text(font: "Montserrat", weight: "regular")
|
||||||
|
|
||||||
|
#it
|
||||||
|
]
|
||||||
|
|
||||||
|
doc
|
||||||
|
}
|
2
justfile
Normal file
2
justfile
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
doc-design:
|
||||||
|
typst compile docs/design/*.typ --root=docs
|
11
src/args.rs
11
src/args.rs
|
@ -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,
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -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<Span>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<Span>) -> 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<usize> {
|
|
||||||
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<Span>, file_id: usize, msg: &str) -> Diagnostic<usize> {
|
|
||||||
Diagnostic::error().with_message(msg).with_labels(
|
|
||||||
spans
|
|
||||||
.into_iter()
|
|
||||||
.map(|span| Label::primary(file_id, span))
|
|
||||||
.collect(),
|
|
||||||
)
|
|
||||||
}
|
|
137
src/evaluator.rs
137
src/evaluator.rs
|
@ -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<FileId, Vec<Errors>>,
|
|
||||||
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<!, codespan_reporting::files::Error> {
|
|
||||||
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<PipelineElement>),
|
|
||||||
BareTyped(FileId, Vec<PipelineElement>),
|
|
||||||
Failed,
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
// concepts
|
|
||||||
// root type namespace
|
|
||||||
// -> builtin types/traits/functions
|
|
||||||
// -> builtin constants
|
|
||||||
//
|
|
||||||
// generic item namespaces
|
|
||||||
// -> in generic functions ( `add<T: Num> [ T T ] -> T` )
|
|
||||||
// -> in generic types ( vec<T> )
|
|
||||||
// -> generic traits ( T: From<E> )
|
|
||||||
//
|
|
||||||
// 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
|
|
58
src/lexer.rs
58
src/lexer.rs
|
@ -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::<i64>().expect("regex should only match valid integers. This is a bug."))]
|
|
||||||
IntLiteral(i64),
|
|
||||||
#[regex("[\\d]+\\.[\\d]+", |lex| lex.slice().parse::<f64>().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,
|
|
||||||
}
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -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<usize>;
|
|
12
src/main.rs
12
src/main.rs
|
@ -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();
|
|
||||||
}
|
|
|
@ -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<TypeDef<'a>> {
|
|
||||||
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<TypeDef> {
|
|
||||||
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<InternalTypeDef>,
|
|
||||||
pub(super) output: Option<InternalTypeDef>,
|
|
||||||
}
|
|
|
@ -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<Vec<InternalType>>,
|
|
||||||
traits: RefCell<Vec<InternalTrait>>,
|
|
||||||
type_namespace: RefCell<HashMap<String, TypeNamespaceId>>,
|
|
||||||
commands: RefCell<Vec<InternalCommand>>,
|
|
||||||
data_namespace: RefCell<HashMap<String, DataNamespaceId>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<Type, NsRegistrationError> {
|
|
||||||
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<Trait, NsRegistrationError> {
|
|
||||||
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<Command, NsRegistrationError<'a>> {
|
|
||||||
if self.data_namespace.borrow().contains_key(name) {
|
|
||||||
Err(NsRegistrationError::NameAlreadyExists)
|
|
||||||
} else {
|
|
||||||
let mut internal_generics_namespace: HashMap<String, Vec<TraitId>> = 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<Type> {
|
|
||||||
(self.types.borrow().len() > id).then_some(Type {
|
|
||||||
id,
|
|
||||||
namespace: self,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_trait(&self, id: TraitId) -> Option<Trait> {
|
|
||||||
(self.traits.borrow().len() > id).then_some(Trait {
|
|
||||||
id,
|
|
||||||
namespace: self,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_command(&self, id: CommandId) -> Option<Command> {
|
|
||||||
(self.commands.borrow().len() > id).then_some(Command {
|
|
||||||
id,
|
|
||||||
namespace: self,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_type_by_name(&self, name: &str) -> Option<Type> {
|
|
||||||
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<Trait> {
|
|
||||||
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<Command> {
|
|
||||||
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>),
|
|
||||||
}
|
|
|
@ -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<HashSet<TypeId>>,
|
|
||||||
pub(super) name: String,
|
|
||||||
}
|
|
|
@ -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<HashSet<TraitId>>,
|
|
||||||
pub(super) name: String,
|
|
||||||
}
|
|
|
@ -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<TypeDef<'a>>),
|
|
||||||
Record(Vec<(String, TypeDef<'a>)>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TypeDef<'a> {
|
|
||||||
pub(super) fn check_generics_exist(
|
|
||||||
&'a self,
|
|
||||||
map: &HashMap<String, Vec<TraitId>>,
|
|
||||||
) -> 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<Type<'a>> for TypeDef<'a> {
|
|
||||||
fn from(value: Type<'a>) -> Self {
|
|
||||||
TypeDef::Type(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) enum InternalTypeDef {
|
|
||||||
Single(TypeId),
|
|
||||||
Generic(String),
|
|
||||||
List(Vec<InternalTypeDef>),
|
|
||||||
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(),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<Errors>> {
|
|
||||||
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<logos::Span>> {
|
|
||||||
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<logos::Span>> {
|
|
||||||
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::<Vec<logos::Span>>();
|
|
||||||
|
|
||||||
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(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
|
@ -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<CommandPart>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[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<PipelineElement>, Vec<logos::Span>> {
|
|
||||||
let lexer = Token::lexer(input);
|
|
||||||
let mut errs = Vec::new();
|
|
||||||
|
|
||||||
let mut r = Vec::new();
|
|
||||||
|
|
||||||
let mut partial_command: Vec<CommandPart> = 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]));
|
|
||||||
}
|
|
234
src/typed.rs
234
src/typed.rs
|
@ -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<TypeDef<'a>> {
|
|
||||||
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<Expr<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<PipelineElement>,
|
|
||||||
) -> Result<Vec<Expr>, 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<ConcreteTypeDef<'a>>),
|
|
||||||
Record(Vec<(String, ConcreteTypeDef<'a>)>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> ConcreteTypeDef<'a> {
|
|
||||||
fn try_from_typedef(val: &TypeDef<'a>) -> Option<Self> {
|
|
||||||
match val {
|
|
||||||
TypeDef::Type(typ) => Some(Self::Single(*typ)),
|
|
||||||
TypeDef::Generic(_) => todo!(),
|
|
||||||
TypeDef::List(list) => {
|
|
||||||
let out: Vec<ConcreteTypeDef<'a>> =
|
|
||||||
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<Expr<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TypeChecker<'a> {
|
|
||||||
fn new(ns: &'a GlobalNamespace, syntax: Vec<Expr<'a>>) -> 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() {}
|
|
||||||
}
|
|
12
testfiles/bare.rpl
Normal file
12
testfiles/bare.rpl
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
(
|
||||||
|
[
|
||||||
|
Read((
|
||||||
|
source: File("/home/jade/example/file.png"),
|
||||||
|
format: Png
|
||||||
|
)),
|
||||||
|
Write((
|
||||||
|
target: File("/home/jade/example/out.jpg"),
|
||||||
|
format: Jpeg
|
||||||
|
))
|
||||||
|
]
|
||||||
|
)
|
13
testfiles/invert.rpl
Normal file
13
testfiles/invert.rpl
Normal file
|
@ -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
|
||||||
|
))
|
||||||
|
]
|
||||||
|
)
|
Loading…
Reference in a new issue