Expression language (#124)
* Add AST * add make-shift testing parser, and make stuff ocmpile * add proper expression parser * make string format use ' * Add empty doc page for expressions * add tests * Clean up file structure and add unary operators * Write documentation
This commit is contained in:
parent
a18901f187
commit
9a8bbf4114
13 changed files with 678 additions and 151 deletions
309
Cargo.lock
generated
309
Cargo.lock
generated
|
@ -26,9 +26,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.37"
|
||||
version = "1.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86"
|
||||
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "async-stream"
|
||||
|
@ -47,8 +53,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a3548b8efc9f8e8a5a0a2808c5bd8451a9031b9e5b879a79590304ae928b0a70"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -117,16 +123,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.3.4"
|
||||
name = "bitvec"
|
||||
version = "0.19.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
|
||||
checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81"
|
||||
dependencies = [
|
||||
"funty",
|
||||
"radium",
|
||||
"tap",
|
||||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad1f8e949d755f9d79112b5bb46938e0ef9d3804a0b16dfab13aafcaa5f0fa72"
|
||||
checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040"
|
||||
|
||||
[[package]]
|
||||
name = "cairo-rs"
|
||||
|
@ -195,12 +213,12 @@ checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24"
|
|||
|
||||
[[package]]
|
||||
name = "ctor"
|
||||
version = "0.1.17"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "373c88d9506e2e9230f6107701b7d8425f4cb3f6df108ec3042a26e936666da5"
|
||||
checksum = "e8f45d9ad417bcef4817d614a501ab55cdd96a6fdb24f49aab89a54acfd66b19"
|
||||
dependencies = [
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -220,8 +238,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "41cb0e6161ad61ed084a36ba71fbba9e3ac5aee3606fb607fe08da6acbcf3d8c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -282,6 +300,7 @@ dependencies = [
|
|||
"log",
|
||||
"maplit",
|
||||
"nix 0.19.1",
|
||||
"nom",
|
||||
"num",
|
||||
"pretty_assertions",
|
||||
"pretty_env_logger",
|
||||
|
@ -306,15 +325,21 @@ checksum = "0c635fdc695a9cbf89115695b04c27c864fa1bf5a94a253798a7bd0752fad5e5"
|
|||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.8"
|
||||
name = "funty"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b3b0c040a1fe6529d30b3c5944b280c7f0dcb2930d2c3062bca967b602583d0"
|
||||
checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -327,9 +352,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-channel"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b7109687aa4e177ef6fe84553af6280ef2778bdb7783ba44c9dc3399110fe64"
|
||||
checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
|
@ -337,15 +362,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-core"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "847ce131b72ffb13b6109a221da9ad97a64cbe48feb1028356b836b47b8f1748"
|
||||
checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4caa2b2b68b880003057c1dd49f1ed937e38f22fcf6c212188a121f08cf40a65"
|
||||
checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
|
@ -354,42 +379,42 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "611834ce18aaa1bd13c4b374f5d653e1027cf99b6b502584ff8c9a64413b30bb"
|
||||
checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500"
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77408a692f1f97bcc61dc001d752e00643408fbc922e4d634c655df50d595556"
|
||||
checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f878195a49cee50e006b02b93cf7e0a95a38ac7b776b4c4d9cc1207cd20fcb3d"
|
||||
checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6"
|
||||
|
||||
[[package]]
|
||||
name = "futures-task"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c554eb5bf48b2426c4771ab68c6b14468b6e76cc90996f528c3338d761a4d0d"
|
||||
checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-util"
|
||||
version = "0.3.8"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d304cff4a7b99cfb7986f7d43fbe93d175e72e704a8860787cc95e9ffd85cbd2"
|
||||
checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b"
|
||||
dependencies = [
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
|
@ -398,7 +423,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"futures-task",
|
||||
"memchr",
|
||||
"pin-project",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"proc-macro-hack",
|
||||
"proc-macro-nested",
|
||||
|
@ -595,8 +620,8 @@ dependencies = [
|
|||
"proc-macro-crate",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -713,9 +738,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.17"
|
||||
version = "0.1.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8"
|
||||
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -754,9 +779,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.4"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4563555856585ab3180a5bf0b2f9f8d301a728462afffc8195b3f5394229c55"
|
||||
checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
@ -804,10 +829,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.81"
|
||||
name = "lexical-core"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
|
||||
checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"cfg-if 1.0.0",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.86"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7282d924be3275cec7f6756ff4121987bc6481325397dde6ba3e7802b1a8b1c"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
|
@ -820,11 +858,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.11"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10",
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -886,6 +924,19 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "6.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2"
|
||||
dependencies = [
|
||||
"bitvec",
|
||||
"funty",
|
||||
"lexical-core",
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.3.6"
|
||||
|
@ -1036,9 +1087,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272"
|
||||
checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
|
@ -1088,8 +1139,8 @@ dependencies = [
|
|||
"phf_shared",
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1101,31 +1152,11 @@ dependencies = [
|
|||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a83804639aad6ba65345661744708855f9fbcb71176ea8d28d05aeb11d975e7"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7bcc46b8f73443d15bc1c5fecbb315718491fa9187fa483f0e359323cde8b3a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.1"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36743d754ccdf9954c2e352ce2d4b106e024c814f6499c2dadff80da9a442d8"
|
||||
checksum = "439697af366c49a6d0a010c56a0d97685bc140ce0d377b13a2ea2aa42d64a827"
|
||||
|
||||
[[package]]
|
||||
name = "pin-utils"
|
||||
|
@ -1184,8 +1215,8 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
|||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -1196,7 +1227,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"quote 1.0.9",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
|
@ -1208,9 +1239,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro-nested"
|
||||
version = "0.1.6"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
|
||||
checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
|
@ -1235,13 +1266,19 @@ checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
|||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.8"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "radium"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
|
@ -1295,15 +1332,18 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.57"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.2"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
|
||||
checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1313,9 +1353,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.21"
|
||||
version = "0.6.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
|
||||
checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
|
||||
|
||||
[[package]]
|
||||
name = "roxmltree"
|
||||
|
@ -1326,6 +1366,12 @@ dependencies = [
|
|||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
|
@ -1334,22 +1380,22 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.118"
|
||||
version = "1.0.123"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800"
|
||||
checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.118"
|
||||
version = "1.0.123"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df"
|
||||
checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1385,9 +1431,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.6.0"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0"
|
||||
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||
|
||||
[[package]]
|
||||
name = "smart-default"
|
||||
|
@ -1396,8 +1442,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1411,6 +1457,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
|
@ -1437,8 +1489,8 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1455,8 +1507,8 @@ checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
|
|||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1472,12 +1524,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.58"
|
||||
version = "1.0.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
|
||||
checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"quote 1.0.9",
|
||||
"unicode-xid 0.2.1",
|
||||
]
|
||||
|
||||
|
@ -1505,6 +1557,12 @@ dependencies = [
|
|||
"version-compare",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tap"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
|
@ -1539,24 +1597,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
|
||||
checksum = "8018d24e04c95ac8790716a5987d0fec4f8b27249ffa0f7d33f1369bdfb88cbd"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.0.1"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d258221f566b6c803c7b4714abadc080172b272090cdc5e244a6d4dd13c3a6bd"
|
||||
checksum = "e8190d04c665ea9e6b6a0dc45523ade572c088d2e6566244c1122671dbf4ae3a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"bytes",
|
||||
|
@ -1574,20 +1632,20 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42517d2975ca3114b22a16192634e8241dc5cc1f130be194645970cc1c371494"
|
||||
checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote 1.0.8",
|
||||
"syn 1.0.58",
|
||||
"quote 1.0.9",
|
||||
"syn 1.0.60",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4cdeb73537e63f98adcd73138af75e3f368ccaecffaa29d7eb61b9f5a440457"
|
||||
checksum = "1981ad97df782ab506a1f43bf82c967326960d278acf3bf8279809648c3ff3ea"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
|
@ -1596,9 +1654,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.6.0"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36135b7e7da911f5f8b9331209f7fab4cc13498f3fff52f72a710c78187e3148"
|
||||
checksum = "ebb7cb2f00c5ae8df755b252306272cd1790d39728363936e01827e11f0b017b"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
|
@ -1606,7 +1664,6 @@ dependencies = [
|
|||
"log",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1712,6 +1769,12 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
|
||||
|
||||
[[package]]
|
||||
name = "x11"
|
||||
version = "2.18.2"
|
||||
|
|
|
@ -55,8 +55,9 @@ futures-core = "0.3"
|
|||
futures-util = "0.3"
|
||||
tokio-util = "0.6"
|
||||
|
||||
dyn-clone = "1.0"
|
||||
|
||||
nom = "6.1"
|
||||
dyn-clone = "1.0"
|
||||
|
||||
[target.'cfg(target_os="linux")'.dependencies]
|
||||
inotify = "0.9"
|
||||
|
|
33
docs/content/main/expression_language.md
Normal file
33
docs/content/main/expression_language.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
+++
|
||||
title = "Eww expressions"
|
||||
slug = "Embedded eww expression language"
|
||||
weight = 6
|
||||
+++
|
||||
|
||||
# The embedded Eww expression-language
|
||||
|
||||
Within variable references, you can make use of a small, built-in expression language.
|
||||
This can be used whereever you can use variable-references (`{{varname}}`).
|
||||
|
||||
## Example
|
||||
|
||||
```xml
|
||||
<button
|
||||
class="{{if button_active then 'active' else 'inactive'}}"
|
||||
onclick="toggle_thing">
|
||||
{{if button_active then 'disable' else 'enable'}}
|
||||
</button>
|
||||
|
||||
Some math: {{12 + 2 * 10}}
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
The expression language supports:
|
||||
- simple mathematical operations (`+`, `-`, `*`, `/`, `%`)
|
||||
- comparisons (`==`, `!=`, `>`, `<`)
|
||||
- boolean operations (`||`, `&&`, `!`)
|
||||
- conditionals (`if condition then 'value' else 'other value'`)
|
||||
- numbers, strings, booleans and variable references (`12`, `'hi'`, `true`, `some_variable`)
|
||||
- strings can contain other expressions again: `'foo {{some_variable}} bar'`
|
||||
|
|
@ -121,6 +121,7 @@ impl RawEwwConfig {
|
|||
pub fn read_from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
|
||||
let result: Result<_> = try {
|
||||
let content = util::replace_env_var_references(std::fs::read_to_string(path.as_ref())?);
|
||||
let content = content.replace("&", "&");
|
||||
let document = roxmltree::Document::parse(&content).map_err(|e| anyhow!(e))?;
|
||||
let root_node = XmlNode::from(document.root_element());
|
||||
let root_element = root_node.as_element()?;
|
||||
|
|
|
@ -121,7 +121,7 @@ impl EwwState {
|
|||
.iter()
|
||||
.map(|element| match element {
|
||||
AttrValueElement::Primitive(primitive) => Ok(primitive.clone()),
|
||||
AttrValueElement::VarRef(var_name) => self.lookup(var_name).cloned(),
|
||||
AttrValueElement::Expr(expr) => expr.clone().eval(&self.variables_state),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
#![feature(trace_macros)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(box_patterns)]
|
||||
#![feature(slice_concat_trait)]
|
||||
#![feature(result_cloned)]
|
||||
#![feature(iterator_fold_self)]
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use anyhow::*;
|
||||
use std::{collections::HashMap, iter::FromIterator};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fmt, iter::FromIterator};
|
||||
|
||||
use super::*;
|
||||
use super::super::*;
|
||||
|
||||
/// A value assigned to an attribute in a widget.
|
||||
/// This can be a primitive String that contains any amount of variable
|
||||
|
@ -9,6 +11,12 @@ use super::*;
|
|||
#[derive(Serialize, Deserialize, Clone, PartialEq, derive_more::Into, derive_more::From, Default)]
|
||||
pub struct AttrValue(Vec<AttrValueElement>);
|
||||
|
||||
impl fmt::Display for AttrValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.iter().map(|x| format!("{}", x)).join(""))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AttrValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "AttrValue({:?})", self.0)
|
||||
|
@ -40,7 +48,7 @@ impl AttrValue {
|
|||
}
|
||||
|
||||
pub fn var_refs(&self) -> impl Iterator<Item = &VarName> {
|
||||
self.0.iter().filter_map(|x| x.as_var_ref())
|
||||
self.0.iter().filter_map(|x| Some(x.as_expr()?.var_refs())).flatten()
|
||||
}
|
||||
|
||||
/// resolve partially.
|
||||
|
@ -48,12 +56,16 @@ impl AttrValue {
|
|||
/// If a referenced variable is not found in the given hashmap, returns the var-ref unchanged.
|
||||
pub fn resolve_one_level(self, variables: &HashMap<VarName, AttrValue>) -> AttrValue {
|
||||
self.into_iter()
|
||||
.flat_map(|entry| match entry {
|
||||
AttrValueElement::VarRef(var_name) => match variables.get(&var_name) {
|
||||
Some(value) => value.0.clone(),
|
||||
_ => vec![AttrValueElement::VarRef(var_name)],
|
||||
},
|
||||
_ => vec![entry],
|
||||
.map(|entry| match entry {
|
||||
AttrValueElement::Expr(expr) => AttrValueElement::Expr(expr.map_terminals_into(|child_expr| match child_expr {
|
||||
AttrValueExpr::VarRef(var_name) => match variables.get(&var_name) {
|
||||
Some(value) => AttrValueExpr::Literal(value.clone()),
|
||||
None => AttrValueExpr::VarRef(var_name),
|
||||
},
|
||||
other => other,
|
||||
})),
|
||||
|
||||
_ => entry,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -65,10 +77,7 @@ impl AttrValue {
|
|||
self.into_iter()
|
||||
.map(|element| match element {
|
||||
AttrValueElement::Primitive(x) => Ok(x),
|
||||
AttrValueElement::VarRef(var_name) => variables
|
||||
.get(&var_name)
|
||||
.cloned()
|
||||
.with_context(|| format!("Unknown variable '{}' referenced", var_name)),
|
||||
AttrValueElement::Expr(expr) => expr.eval(variables),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
@ -85,7 +94,7 @@ impl AttrValue {
|
|||
if c == '}' {
|
||||
curly_count -= 1;
|
||||
if curly_count == 0 {
|
||||
elements.push(AttrValueElement::VarRef(VarName(std::mem::take(varref))));
|
||||
elements.push(AttrValueElement::Expr(AttrValueExpr::parse(varref).unwrap()));
|
||||
cur_varref = None
|
||||
}
|
||||
} else {
|
||||
|
@ -120,14 +129,22 @@ impl AttrValue {
|
|||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum AttrValueElement {
|
||||
Primitive(PrimitiveValue),
|
||||
VarRef(VarName),
|
||||
Expr(AttrValueExpr),
|
||||
}
|
||||
impl fmt::Display for AttrValueElement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AttrValueElement::Primitive(x) => write!(f, "{}", x),
|
||||
AttrValueElement::Expr(x) => write!(f, "{{{{{}}}}}", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for AttrValueElement {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
AttrValueElement::Primitive(x) => write!(f, "Primitive({:?})", x),
|
||||
AttrValueElement::VarRef(x) => write!(f, "VarRef({:?})", x),
|
||||
AttrValueElement::Expr(x) => write!(f, "Expr({:?})", x),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -137,9 +154,9 @@ impl AttrValueElement {
|
|||
AttrValueElement::Primitive(PrimitiveValue::from_string(s))
|
||||
}
|
||||
|
||||
pub fn as_var_ref(&self) -> Option<&VarName> {
|
||||
pub fn as_expr(&self) -> Option<&AttrValueExpr> {
|
||||
match self {
|
||||
AttrValueElement::VarRef(x) => Some(&x),
|
||||
AttrValueElement::Expr(x) => Some(&x),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -163,12 +180,12 @@ mod test {
|
|||
assert_eq!(
|
||||
output,
|
||||
AttrValue(vec![
|
||||
AttrValueElement::VarRef(VarName("foo".to_owned())),
|
||||
AttrValueElement::VarRef(VarName("bar".to_owned())),
|
||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("foo".to_owned()))),
|
||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("bar".to_owned()))),
|
||||
AttrValueElement::primitive("b{}azb{a}z".to_owned()),
|
||||
AttrValueElement::VarRef(VarName("bat".to_owned())),
|
||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("bat".to_owned()))),
|
||||
AttrValueElement::primitive("{}quok".to_owned()),
|
||||
AttrValueElement::VarRef(VarName("test".to_owned())),
|
||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("test".to_owned()))),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
@ -177,7 +194,7 @@ mod test {
|
|||
assert_eq!(
|
||||
AttrValue(
|
||||
vec![
|
||||
AttrValueElement::VarRef(VarName("var".to_owned())),
|
||||
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("var".to_owned()))),
|
||||
AttrValueElement::primitive("something".to_owned())
|
||||
]
|
||||
.into()
|
179
src/value/attr_value/attr_value_expr.rs
Normal file
179
src/value/attr_value/attr_value_expr.rs
Normal file
|
@ -0,0 +1,179 @@
|
|||
use super::super::*;
|
||||
use anyhow::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||
pub enum BinOp {
|
||||
Plus,
|
||||
Minus,
|
||||
Times,
|
||||
Div,
|
||||
Mod,
|
||||
Equals,
|
||||
NotEquals,
|
||||
And,
|
||||
Or,
|
||||
GT,
|
||||
LT,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BinOp {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
BinOp::Plus => write!(f, "+"),
|
||||
BinOp::Minus => write!(f, "-"),
|
||||
BinOp::Times => write!(f, "*"),
|
||||
BinOp::Div => write!(f, "/"),
|
||||
BinOp::Mod => write!(f, "%"),
|
||||
BinOp::Equals => write!(f, "=="),
|
||||
BinOp::NotEquals => write!(f, "!="),
|
||||
BinOp::And => write!(f, "&&"),
|
||||
BinOp::Or => write!(f, "||"),
|
||||
BinOp::GT => write!(f, ">"),
|
||||
BinOp::LT => write!(f, "<"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
|
||||
pub enum UnaryOp {
|
||||
Not,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for UnaryOp {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
UnaryOp::Not => write!(f, "!"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub enum AttrValueExpr {
|
||||
Literal(AttrValue),
|
||||
VarRef(VarName),
|
||||
BinOp(Box<AttrValueExpr>, BinOp, Box<AttrValueExpr>),
|
||||
UnaryOp(UnaryOp, Box<AttrValueExpr>),
|
||||
IfElse(Box<AttrValueExpr>, Box<AttrValueExpr>, Box<AttrValueExpr>),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AttrValueExpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
AttrValueExpr::VarRef(x) => write!(f, "{}", x),
|
||||
AttrValueExpr::Literal(x) => write!(f, "\"{}\"", x),
|
||||
AttrValueExpr::BinOp(l, op, r) => write!(f, "({} {} {})", l, op, r),
|
||||
AttrValueExpr::UnaryOp(op, x) => write!(f, "{}{}", op, x),
|
||||
AttrValueExpr::IfElse(a, b, c) => write!(f, "(if {} then {} else {})", a, b, c),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for AttrValueExpr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl AttrValueExpr {
|
||||
pub fn map_terminals_into(self, f: impl Fn(Self) -> Self) -> Self {
|
||||
use AttrValueExpr::*;
|
||||
match self {
|
||||
BinOp(box a, op, box b) => BinOp(box f(a), op, box f(b)),
|
||||
IfElse(box a, box b, box c) => IfElse(box f(a), box f(b), box f(c)),
|
||||
other => f(other),
|
||||
}
|
||||
}
|
||||
|
||||
/// resolve variable references in the expression. Fails if a variable cannot be resolved.
|
||||
pub fn resolve_refs(self, variables: &HashMap<VarName, PrimitiveValue>) -> Result<Self> {
|
||||
use AttrValueExpr::*;
|
||||
match self {
|
||||
Literal(x) => Ok(AttrValueExpr::Literal(x)),
|
||||
VarRef(ref name) => Ok(Literal(AttrValue::from_primitive(
|
||||
variables
|
||||
.get(name)
|
||||
.with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?
|
||||
.clone(),
|
||||
))),
|
||||
BinOp(box a, op, box b) => Ok(BinOp(box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)),
|
||||
UnaryOp(op, box x) => Ok(UnaryOp(op, box x.resolve_refs(variables)?)),
|
||||
IfElse(box a, box b, box c) => Ok(IfElse(
|
||||
box a.resolve_refs(variables)?,
|
||||
box b.resolve_refs(variables)?,
|
||||
box c.resolve_refs(variables)?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn var_refs(&self) -> Vec<&VarName> {
|
||||
use AttrValueExpr::*;
|
||||
match self {
|
||||
Literal(_) => vec![],
|
||||
VarRef(name) => vec![name],
|
||||
BinOp(box a, _, box b) => {
|
||||
let mut refs = a.var_refs();
|
||||
refs.append(&mut b.var_refs());
|
||||
refs
|
||||
}
|
||||
UnaryOp(_, box x) => x.var_refs(),
|
||||
IfElse(box a, box b, box c) => {
|
||||
let mut refs = a.var_refs();
|
||||
refs.append(&mut b.var_refs());
|
||||
refs.append(&mut c.var_refs());
|
||||
refs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eval(self, values: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> {
|
||||
match self {
|
||||
AttrValueExpr::Literal(x) => x.resolve_fully(&values),
|
||||
AttrValueExpr::VarRef(ref name) => values.get(name).cloned().context(format!(
|
||||
"Got unresolved variable {} while trying to evaluate expression {:?}",
|
||||
&name, &self
|
||||
)),
|
||||
AttrValueExpr::BinOp(a, op, b) => {
|
||||
let a = a.eval(values)?;
|
||||
let b = b.eval(values)?;
|
||||
Ok(match op {
|
||||
BinOp::Equals => PrimitiveValue::from(a == b),
|
||||
BinOp::NotEquals => PrimitiveValue::from(a != b),
|
||||
BinOp::And => PrimitiveValue::from(a.as_bool()? && b.as_bool()?),
|
||||
BinOp::Or => PrimitiveValue::from(a.as_bool()? || b.as_bool()?),
|
||||
|
||||
BinOp::Plus => PrimitiveValue::from(a.as_f64()? + b.as_f64()?),
|
||||
BinOp::Minus => PrimitiveValue::from(a.as_f64()? - b.as_f64()?),
|
||||
BinOp::Times => PrimitiveValue::from(a.as_f64()? * b.as_f64()?),
|
||||
BinOp::Div => PrimitiveValue::from(a.as_f64()? / b.as_f64()?),
|
||||
BinOp::Mod => PrimitiveValue::from(a.as_f64()? % b.as_f64()?),
|
||||
BinOp::GT => PrimitiveValue::from(a.as_f64()? > b.as_f64()?),
|
||||
BinOp::LT => PrimitiveValue::from(a.as_f64()? < b.as_f64()?),
|
||||
})
|
||||
}
|
||||
AttrValueExpr::UnaryOp(op, a) => {
|
||||
let a = a.eval(values)?;
|
||||
Ok(match op {
|
||||
UnaryOp::Not => PrimitiveValue::from(!a.as_bool()?),
|
||||
})
|
||||
}
|
||||
AttrValueExpr::IfElse(cond, yes, no) => {
|
||||
if cond.eval(values)?.as_bool()? {
|
||||
yes.eval(values)
|
||||
} else {
|
||||
no.eval(values)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse<'a>(s: &'a str) -> Result<Self> {
|
||||
let parsed = match parser::parse(s) {
|
||||
Ok((_, x)) => Ok(x),
|
||||
Err(nom::Err::Error(e) | nom::Err::Failure(e)) => Err(anyhow!(nom::error::convert_error(s, e))),
|
||||
Err(nom::Err::Incomplete(_)) => Err(anyhow!("Parsing incomplete")),
|
||||
};
|
||||
parsed.context("Failed to parse expression")
|
||||
}
|
||||
}
|
5
src/value/attr_value/mod.rs
Normal file
5
src/value/attr_value/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
pub mod attr_value;
|
||||
pub mod attr_value_expr;
|
||||
pub mod parser;
|
||||
pub use attr_value::*;
|
||||
pub use attr_value_expr::*;
|
209
src/value/attr_value/parser.rs
Normal file
209
src/value/attr_value/parser.rs
Normal file
|
@ -0,0 +1,209 @@
|
|||
use super::*;
|
||||
|
||||
use nom::{
|
||||
branch::*,
|
||||
bytes::complete::{tag, take_while},
|
||||
character::complete::{multispace0 as multispace, *},
|
||||
combinator::{map, map_res, *},
|
||||
error::{context, ParseError, VerboseError},
|
||||
multi::many0,
|
||||
sequence::{delimited, preceded, *},
|
||||
IResult, Parser,
|
||||
};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
fn ws<'a, P, O, E: ParseError<&'a str>>(p: P) -> impl FnMut(&'a str) -> IResult<&'a str, O, E>
|
||||
where
|
||||
P: Parser<&'a str, O, E>,
|
||||
{
|
||||
delimited(multispace, p, multispace)
|
||||
}
|
||||
|
||||
fn parse_num(i: &str) -> IResult<&str, i32, VerboseError<&str>> {
|
||||
alt((
|
||||
map_res(digit1, |s: &str| s.parse::<i32>()),
|
||||
map_res(preceded(tag("-"), digit1), |s: &str| s.parse::<i32>().map(|x| x * -1)),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn parse_stringlit(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
||||
alt((
|
||||
delimited(tag("'"), take_while(|c| c != '\''), tag("'")),
|
||||
delimited(tag("\""), take_while(|c| c != '"'), tag("\"")),
|
||||
))(i)
|
||||
}
|
||||
|
||||
fn parse_bool(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
||||
alt((tag("true"), tag("false")))(i)
|
||||
}
|
||||
|
||||
fn parse_literal(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
||||
alt((parse_bool, parse_stringlit, recognize(parse_num)))(i)
|
||||
}
|
||||
|
||||
fn parse_identifier(i: &str) -> IResult<&str, &str, VerboseError<&str>> {
|
||||
verify(
|
||||
recognize(pair(
|
||||
alt((alpha1, tag("_"), tag("-"))),
|
||||
many0(alt((alphanumeric1, tag("_"), tag("-")))),
|
||||
)),
|
||||
|x| !["if", "then", "else"].contains(x),
|
||||
)(i)
|
||||
}
|
||||
|
||||
fn parse_unary_op(i: &str) -> IResult<&str, UnaryOp, VerboseError<&str>> {
|
||||
value(UnaryOp::Not, tag("!"))(i)
|
||||
}
|
||||
|
||||
/////////////////
|
||||
// actual tree //
|
||||
/////////////////
|
||||
|
||||
fn parse_factor(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||
let (i, unary_op) = opt(parse_unary_op)(i)?;
|
||||
let (i, factor) = alt((
|
||||
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
|
||||
context("if-expression", ws(parse_ifelse)),
|
||||
context(
|
||||
"literal",
|
||||
map(ws(parse_literal), |x| AttrValueExpr::Literal(AttrValue::parse_string(x))),
|
||||
),
|
||||
context(
|
||||
"identifier",
|
||||
map(ws(parse_identifier), |x| AttrValueExpr::VarRef(VarName(x.to_string()))),
|
||||
),
|
||||
))(i)?;
|
||||
Ok((
|
||||
i,
|
||||
match unary_op {
|
||||
Some(op) => AttrValueExpr::UnaryOp(op, box factor),
|
||||
None => factor,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||
let (i, initial) = parse_factor(i)?;
|
||||
let (i, remainder) = many0(alt((
|
||||
map(preceded(tag("*"), parse_factor), |x| (BinOp::Times, x)),
|
||||
map(preceded(tag("/"), parse_factor), |x| (BinOp::Div, x)),
|
||||
map(preceded(tag("%"), parse_factor), |x| (BinOp::Mod, x)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
Ok((i, exprs))
|
||||
}
|
||||
fn parse_term2(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||
let (i, initial) = parse_term3(i)?;
|
||||
let (i, remainder) = many0(alt((
|
||||
map(preceded(tag("+"), parse_term3), |x| (BinOp::Plus, x)),
|
||||
map(preceded(tag("-"), parse_term3), |x| (BinOp::Minus, x)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
Ok((i, exprs))
|
||||
}
|
||||
|
||||
fn parse_term1(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||
let (i, initial) = parse_term2(i)?;
|
||||
let (i, remainder) = many0(alt((
|
||||
map(preceded(tag("=="), parse_term2), |x| (BinOp::Equals, x)),
|
||||
map(preceded(tag("!="), parse_term2), |x| (BinOp::NotEquals, x)),
|
||||
map(preceded(tag(">"), parse_term2), |x| (BinOp::GT, x)),
|
||||
map(preceded(tag("<"), parse_term2), |x| (BinOp::LT, x)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
Ok((i, exprs))
|
||||
}
|
||||
pub fn parse_expr(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||
let (i, initial) = parse_term1(i)?;
|
||||
let (i, remainder) = many0(alt((
|
||||
map(preceded(tag("&&"), parse_term1), |x| (BinOp::And, x)),
|
||||
map(preceded(tag("||"), parse_term1), |x| (BinOp::Or, x)),
|
||||
)))(i)?;
|
||||
|
||||
let exprs = remainder
|
||||
.into_iter()
|
||||
.fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
|
||||
|
||||
Ok((i, exprs))
|
||||
}
|
||||
|
||||
fn parse_ifelse(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
|
||||
let (i, _) = tag("if")(i)?;
|
||||
let (i, a) = context("condition", ws(parse_expr))(i)?;
|
||||
let (i, _) = tag("then")(i)?;
|
||||
let (i, b) = context("true-case", ws(parse_expr))(i)?;
|
||||
let (i, _) = tag("else")(i)?;
|
||||
let (i, c) = context("false-case", ws(parse_expr))(i)?;
|
||||
Ok((i, AttrValueExpr::IfElse(box a, box b, box c)))
|
||||
}
|
||||
|
||||
pub fn parse<'a>(i: &'a str) -> IResult<&'a str, AttrValueExpr, VerboseError<&'a str>> {
|
||||
complete(parse_expr)(i)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
assert_eq!(
|
||||
AttrValueExpr::Literal(AttrValue::from_primitive("12")),
|
||||
AttrValueExpr::parse("12").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
AttrValueExpr::UnaryOp(UnaryOp::Not, box AttrValueExpr::Literal(AttrValue::from_primitive("false"))),
|
||||
AttrValueExpr::parse("!false").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
AttrValueExpr::BinOp(
|
||||
box AttrValueExpr::Literal(AttrValue::from_primitive("12")),
|
||||
BinOp::Plus,
|
||||
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
|
||||
),
|
||||
AttrValueExpr::parse("12 + 2").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
AttrValueExpr::UnaryOp(
|
||||
UnaryOp::Not,
|
||||
box AttrValueExpr::BinOp(
|
||||
box AttrValueExpr::Literal(AttrValue::from_primitive("1")),
|
||||
BinOp::Equals,
|
||||
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
|
||||
)
|
||||
),
|
||||
AttrValueExpr::parse("!(1 == 2)").unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
AttrValueExpr::IfElse(
|
||||
box AttrValueExpr::VarRef(VarName("a".to_string())),
|
||||
box AttrValueExpr::VarRef(VarName("b".to_string())),
|
||||
box AttrValueExpr::VarRef(VarName("c".to_string())),
|
||||
),
|
||||
AttrValueExpr::parse("if a then b else c").unwrap()
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_complex() {
|
||||
let parsed =
|
||||
AttrValueExpr::parse(r#"if hi > 12 + 2 * 2 && 12 == 15 then "foo" else if !true then 'hi' else "{{bruh}}""#).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
r#"(if ((hi > ("12" + ("2" * "2"))) && ("12" == "15")) then "foo" else (if !"true" then "hi" else "{{bruh}}"))"#,
|
||||
format!("{}", parsed),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
use derive_more::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
pub mod attr_value;
|
||||
pub mod coords;
|
||||
pub mod primitive;
|
||||
pub use attr_value::*;
|
||||
pub use attr_value_expr::*;
|
||||
pub use coords::*;
|
||||
pub use primitive::*;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use std::{convert::TryFrom, fmt, iter::FromIterator};
|
|||
|
||||
use crate::impl_try_from;
|
||||
|
||||
#[derive(Clone, PartialEq, Deserialize, Serialize, derive_more::From, Default)]
|
||||
#[derive(Clone, Deserialize, Serialize, derive_more::From, Default)]
|
||||
pub struct PrimitiveValue(String);
|
||||
|
||||
impl fmt::Display for PrimitiveValue {
|
||||
|
@ -19,6 +19,17 @@ impl fmt::Debug for PrimitiveValue {
|
|||
}
|
||||
}
|
||||
|
||||
/// Manually implement equality, to allow for values in different formats (i.e. "1" and "1.0") to still be considered as equal.
|
||||
impl std::cmp::PartialEq<Self> for PrimitiveValue {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
if let (Ok(a), Ok(b)) = (self.as_f64(), other.as_f64()) {
|
||||
a == b
|
||||
} else {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromIterator<PrimitiveValue> for PrimitiveValue {
|
||||
fn from_iter<T: IntoIterator<Item = PrimitiveValue>>(iter: T) -> Self {
|
||||
PrimitiveValue(iter.into_iter().join(""))
|
||||
|
@ -54,6 +65,12 @@ impl From<i32> for PrimitiveValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<f64> for PrimitiveValue {
|
||||
fn from(s: f64) -> Self {
|
||||
PrimitiveValue(s.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for PrimitiveValue {
|
||||
fn from(s: &str) -> Self {
|
||||
PrimitiveValue(s.to_string())
|
||||
|
|
|
@ -125,7 +125,6 @@ mod test {
|
|||
use super::*;
|
||||
use crate::config::xml_ext::*;
|
||||
use maplit::hashmap;
|
||||
use pretty_assertions::assert_eq;
|
||||
#[test]
|
||||
fn test_generic_generate() {
|
||||
let w_def1 = {
|
||||
|
|
Loading…
Add table
Reference in a new issue