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:
ElKowar 2021-03-02 10:27:52 +01:00 committed by GitHub
parent a18901f187
commit 9a8bbf4114
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 678 additions and 151 deletions

309
Cargo.lock generated
View file

@ -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"

View file

@ -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"

View 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'`

View file

@ -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("&", "&amp;");
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()?;

View file

@ -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()
}

View file

@ -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)]

View file

@ -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()

View 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")
}
}

View 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::*;

View 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),
)
}
}

View file

@ -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::*;

View file

@ -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())

View file

@ -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 = {