diff --git a/experiments/css/.gitignore b/experiments/css/.gitignore new file mode 100644 index 0000000..32541a4 --- /dev/null +++ b/experiments/css/.gitignore @@ -0,0 +1,3 @@ +/target/ +/demo/bombshell_css_wasm.wasm +/wasm.ts diff --git a/experiments/css/Cargo.lock b/experiments/css/Cargo.lock new file mode 100644 index 0000000..30280be --- /dev/null +++ b/experiments/css/Cargo.lock @@ -0,0 +1,623 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "bitflags" +version = "2.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" + +[[package]] +name = "bombshell-css-compiler" +version = "0.1.0" +dependencies = [ + "bombshell-css-core", + "cc", + "cssparser", +] + +[[package]] +name = "bombshell-css-conformance" +version = "0.1.0" +dependencies = [ + "bombshell-css-compiler", + "bombshell-css-core", + "bombshell-css-runtime", +] + +[[package]] +name = "bombshell-css-core" +version = "0.1.0" +dependencies = [ + "cssparser", + "parcel_selectors", + "postcard", + "serde", +] + +[[package]] +name = "bombshell-css-runtime" +version = "0.1.0" +dependencies = [ + "bombshell-css-compiler", + "bombshell-css-core", + "cssparser", + "parcel_selectors", + "rustc-hash", +] + +[[package]] +name = "bombshell-css-wasm" +version = "0.1.0" +dependencies = [ + "bombshell-css-compiler", + "bombshell-css-core", + "bombshell-css-runtime", + "wit-bindgen", +] + +[[package]] +name = "cc" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror", +] + +[[package]] +name = "cssparser" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf 0.13.1", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a" +dependencies = [ + "quote", + "syn 3.0.6", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "find-msvc-tools" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "indexmap" +version = "2.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" +dependencies = [ + "equivalent", + "hashbrown", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "parcel_selectors" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05f71e01edca03d245ab0a9f7ce13a974ceb79baaae8faf2ba0b11de6b90913" +dependencies = [ + "bitflags", + "cssparser", + "log", + "phf 0.11.3", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "smallvec", +] + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_shared 0.11.3", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared 0.13.1", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" +dependencies = [ + "phf_generator 0.11.3", + "phf_shared 0.11.3", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared 0.11.3", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared 0.13.1", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator 0.13.1", + "phf_shared 0.13.1", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "prettyplease" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bfe0f4c752e450fc2faf62654f1c134747922825d5b04ca717b8874f41a40c0" +dependencies = [ + "proc-macro2", + "syn 3.0.6", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "siphasher" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" + +[[package]] +name = "smallvec" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba467056f1b547ed52077911161fc86985becbc60e8e1857c8a144dab0def891" + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.6", +] + +[[package]] +name = "unicode-ident" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab72a15cf68d77cb0987d3684aa8a45c5ef827e8cb49ee2f30bfd7ba2feb519f" + +[[package]] +name = "wasm-encoder" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d0246511d901aacf25d2dc9111f0054947de5e093fe662099e709ff7530dc3" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7bf119eb01f4a246864c10bd87c8f26c566350abb25aa4d5273c415bbab338" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f7c12eac7bb587801590f6a67ff0bc84d0748513864b71108e4b311cc3df694" +dependencies = [ + "bitflags", + "hashbrown", + "indexmap", + "semver", +] + +[[package]] +name = "wit-bindgen" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53cb4b5556c3a791e86838ea287782bdafa704d55b0e68b5b81a3a16b9ea5f4b" +dependencies = [ + "bitflags", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ad22a37ecbc0e1fdca34d2b670ba41368cb0920735643e00fdf39a16ee5431" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84ba5213d4332c260a0d4e69e34b0f7e4b85ddae10b6ebfbac00d9c185ba628a" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 3.0.6", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.62.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f19d63da8e478a370ef8192d90ccb517965b7747d6b46cd2d831dd0ef4d2541" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 3.0.6", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092f783dee3253265fcde131475055f8c275ac0176a9c0396db1dc7b5544bfb4" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.259.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6390f4f02493ce678d509c859cf1698e38929fb75c8012a6ee2f7d6b6cb66cd7" +dependencies = [ + "anyhow", + "hashbrown", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-ident", + "wasmparser", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/experiments/css/Cargo.toml b/experiments/css/Cargo.toml new file mode 100644 index 0000000..5cd752d --- /dev/null +++ b/experiments/css/Cargo.toml @@ -0,0 +1,38 @@ +[workspace] +members = [ + "crates/css-core", + "crates/css-compiler", + "crates/css-runtime", + "crates/css-wasm", + "crates/css-conformance", +] +resolver = "2" + +[workspace.package] +edition = "2024" +license = "MIT" +repository = "https://github.com/natemoo-re/css" +rust-version = "1.85" + +[workspace.dependencies] +bombshell-css-core = { path = "crates/css-core" } +bombshell-css-compiler = { path = "crates/css-compiler" } +bombshell-css-runtime = { path = "crates/css-runtime" } +cc = "1" +cssparser = "0.37.0" +parcel_selectors = "0.28.3" +rustc-hash = "2" +serde = { version = "1", default-features = false, features = ["derive", "alloc"] } +postcard = { version = "1", default-features = false, features = ["alloc"] } +wit-bindgen = { version = "0.62.0", default-features = false, features = [ + "macros", + "realloc", + "bitflags", +] } + +[profile.release] +lto = true +codegen-units = 1 +panic = "abort" +opt-level = "z" +strip = true diff --git a/experiments/css/crates/css-compiler/Cargo.toml b/experiments/css/crates/css-compiler/Cargo.toml new file mode 100644 index 0000000..d2ff04d --- /dev/null +++ b/experiments/css/crates/css-compiler/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bombshell-css-compiler" +version = "0.1.0" +description = "Lexbor-backed CSS compiler emitting the Bombshell stylesheet IR" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +build = "build.rs" + +[dependencies] +bombshell-css-core = { workspace = true, features = ["selectors"] } +cssparser = { workspace = true } + +[build-dependencies] +cc = { workspace = true } diff --git a/experiments/css/crates/css-compiler/build.rs b/experiments/css/crates/css-compiler/build.rs new file mode 100644 index 0000000..8e5032c --- /dev/null +++ b/experiments/css/crates/css-compiler/build.rs @@ -0,0 +1,122 @@ +//! Builds the vendored lexbor sources plus the front-end shim. +//! +//! For `wasm32-unknown-unknown` the build is freestanding: stub libc headers +//! under `vendor/stubs` stand in for the missing sysroot and the shim provides +//! minimal memcpy-family implementations. On native targets the system libc is +//! used; on macOS an explicit `-isysroot` works around CLT/Xcode SDK +//! resolution issues. + +use std::path::PathBuf; +use std::process::Command; + +fn main() { + let manifest = std::env::var("CARGO_MANIFEST_DIR").unwrap(); + let manifest = PathBuf::from(manifest); + let vendor = manifest.join("vendor"); + let lexbor = vendor.join("lexbor/lexbor"); + let target = std::env::var("TARGET").unwrap(); + let freestanding = target == "wasm32-unknown-unknown"; + + let mut build = cc::Build::new(); + + build + .opt_level_str("z") + .flag("-fno-exceptions") + .include(vendor.join("lexbor")) + .file(manifest.join("c/shim.c")) + .warnings(false); + + if freestanding { + build + .flag("--target=wasm32-unknown-unknown") + .flag("-ffreestanding") + .flag("-mbulk-memory") + .define("LBX_FREESTANDING", None) + .include(vendor.join("stubs")); + } + + if target.contains("darwin") { + if let Some(sdk) = macos_sdk() { + build.flag("-isysroot").flag(&sdk); + } + } + + // Only the modules the shim actually reaches: the syntax tokenizer/parser + // and the core memory/string/number primitives they sit on. Selector + // validation and specificity are parcel_selectors' job on the Rust side + // (one parser shared with the runtime matcher), and lexbor's typed + // at-rule/property/value layers, serializers, and search structures + // (avl/bst/hash/shs) are never touched by the event-stream shim. + let keep = [ + // core primitives + "core/array.c", + "core/array_obj.c", + "core/bst.c", + "core/diyfp.c", + "core/dobject.c", + "core/mem.c", + "core/mraw.c", + "core/str.c", + "core/strtod.c", + // css front-end used by the shim + "css/css.c", + "css/log.c", + "css/parser.c", + "css/rule.c", + "css/syntax/parser.c", + "css/syntax/syntax.c", + "css/syntax/state.c", + "css/syntax/token.c", + "css/syntax/tokenizer.c", + "css/syntax/tokenizer/error.c", + "ports/posix/lexbor/core/memory.c", + ]; + + for rel in keep { + build.file(lexbor.join(rel)); + } + + build.compile("lexbor_css"); + + println!("cargo:rerun-if-changed=c/shim.c"); + println!("cargo:rerun-if-changed=vendor"); +} + +fn macos_sdk() -> Option { + if let Ok(output) = Command::new("xcrun").arg("--show-sdk-path").output() { + if output.status.success() { + let path = String::from_utf8_lossy(&output.stdout).trim().to_string(); + if !path.is_empty() && std::path::Path::new(&path).join("usr/include").exists() { + return Some(path); + } + } + } + + // CLT/Xcode SDK resolution can break out from under us; probe known + // locations and pick the newest existing SDK. + for root in [ + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs", + "/Library/Developer/CommandLineTools/SDKs", + ] { + let mut candidates: Vec = std::fs::read_dir(root) + .ok()? + .filter_map(|entry| entry.ok()) + .map(|entry| entry.path()) + .filter(|path| { + path.file_name() + .and_then(|name| name.to_str()) + .map(|name| name.starts_with("MacOSX") && name.ends_with(".sdk")) + .unwrap_or(false) + }) + .map(|path| path.to_string_lossy().into_owned()) + .collect(); + candidates.sort(); + if let Some(path) = candidates.pop() { + if std::path::Path::new(&path).join("usr/include").exists() { + return Some(path); + } + } + } + + None +} diff --git a/experiments/css/crates/css-compiler/c/shim.c b/experiments/css/crates/css-compiler/c/shim.c new file mode 100644 index 0000000..c038623 --- /dev/null +++ b/experiments/css/crates/css-compiler/c/shim.c @@ -0,0 +1,799 @@ +/* + * Lexbor-backed front-end shim for the Bombshell CSS pipeline. + * + * Drives lexbor's syntax parser with custom callbacks and emits a flat event + * stream (byte spans into the original stylesheet text) for the Rust side, + * which does all semantic work: nesting expansion, condition parsing, + * canonicalization, and IR emission. + * + * Event kinds: + * LBX_STYLE_BEGIN a = prelude span flags bit1 = failed + * LBX_STYLE_END (no data) + * LBX_AT_BEGIN a = at-rule name span + * LBX_AT_PRELUDE a = prelude span flags bit1 = failed + * LBX_AT_END a = full rule span flags bit0 = has_block + * LBX_DECL a = name span, b = value span + * flags bit0 = important, bit1 = failed + */ +#include +#include + +#ifdef LBX_FREESTANDING +/* Minimal libc for wasm32-unknown-unknown; word-wise for speed. */ +void * +memcpy(void *d, const void *s, unsigned long n) +{ + unsigned char *dd = d; + const unsigned char *ss = s; + + for (; n >= 8; n -= 8, dd += 8, ss += 8) { + __builtin_memcpy(dd, ss, 8); + } + + while (n--) { + *dd++ = *ss++; + } + + return d; +} + +void * +memmove(void *d, const void *s, unsigned long n) +{ + unsigned char *dd = d; + const unsigned char *ss = s; + + if ((uintptr_t) dd < (uintptr_t) ss) { + return memcpy(d, s, n); + } + + dd += n; + ss += n; + + for (; n >= 8; n -= 8, dd -= 8, ss -= 8) { + __builtin_memcpy(dd - 8, ss - 8, 8); + } + + while (n--) { + *--dd = *--ss; + } + + return d; +} + +void * +memset(void *d, int c, unsigned long n) +{ + unsigned char *dd = d; + unsigned char v = (unsigned char) c; + + for (; n >= 8; n -= 8, dd += 8) { + __builtin_memset(dd, v, 8); + } + + while (n--) { + *dd++ = v; + } + + return d; +} + +int +memcmp(const void *a, const void *b, unsigned long n) +{ + const unsigned char *x = a; + const unsigned char *y = b; + + while (n--) { + if (*x != *y) { + return *x - *y; + } + + x++; + y++; + } + + return 0; +} + +unsigned long +strlen(const char *s) +{ + const char *p = s; + + while (*p) { + p++; + } + + return (unsigned long) (p - s); +} +#endif /* LBX_FREESTANDING */ + +#define LBX_STYLE_BEGIN 0 +#define LBX_STYLE_END 1 +#define LBX_AT_BEGIN 2 +#define LBX_AT_PRELUDE 3 +#define LBX_AT_END 4 +#define LBX_DECL 5 + +#define LBX_FLAG_HAS_BLOCK 0x01 +#define LBX_FLAG_IMPORTANT 0x01 +#define LBX_FLAG_FAILED 0x02 + +typedef struct { + uint8_t kind; + uint8_t flags; + uint32_t a0; + uint32_t a1; + uint32_t b0; + uint32_t b1; +} +lbx_event_t; + +typedef struct { + const unsigned char *css; + size_t css_len; + + lbx_event_t *events; + size_t events_len; + size_t events_cap; + + uintptr_t prelude_begin; + uintptr_t prelude_end; + bool prelude_seen; + + uintptr_t decl_name_begin; + uintptr_t decl_name_end; + + uintptr_t q_begin; + bool q_open; + + struct { + uintptr_t begin; + bool has_block; + } + at_stack[64]; + size_t at_depth; + + bool oom; +} +lbx_ctx_t; + +static void lbx_emit(lbx_ctx_t *ctx, uint8_t kind, uint8_t flags, + uintptr_t a0, uintptr_t a1, uintptr_t b0, uintptr_t b1); + +static bool lbx_state_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +static bool lbx_next_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t lbx_noop_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static bool lbx_at_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +static lxb_status_t lbx_at_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static lxb_status_t lbx_at_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static const lxb_css_syntax_cb_at_rule_t *lbx_begin_at_rule( + lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule); + +static bool lbx_qualified_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +static lxb_status_t lbx_qualified_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static lxb_status_t lbx_qualified_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static const lxb_css_syntax_cb_qualified_rule_t *lbx_begin_qualified( + lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule); + +static const lxb_css_syntax_cb_declarations_t *lbx_begin_declarations( + lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule); + +static const lxb_css_syntax_cb_block_t *lbx_begin_block( + lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule); + +static lxb_css_parser_state_f lbx_decl_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +static bool lbx_decl_value_state(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +static lxb_status_t lbx_decl_end(lxb_css_parser_t *parser, void *declaration, + void *context, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed); + +static lbx_ctx_t lbx_ctx; + +static const lxb_css_syntax_cb_list_rules_t lbx_list_rules_cb; +static const lxb_css_syntax_cb_at_rule_t lbx_at_rule_cb; +static const lxb_css_syntax_cb_qualified_rule_t lbx_qualified_rule_cb; +static const lxb_css_syntax_cb_block_t lbx_block_cb; +static const lxb_css_syntax_cb_declarations_t lbx_declarations_cb; + +static uintptr_t +lbx_clamp(lbx_ctx_t *ctx, uintptr_t off) +{ + uintptr_t base = (uintptr_t) ctx->css; + + if (off < base || off > base + ctx->css_len) { + return base + ctx->css_len; + } + + return off; +} + +static void +lbx_emit(lbx_ctx_t *ctx, uint8_t kind, uint8_t flags, + uintptr_t a0, uintptr_t a1, uintptr_t b0, uintptr_t b1) +{ + if (ctx->oom) { + return; + } + + /* Synthetic tokens (e.g. _END) carry pointers outside the input; clamp + * spans to the stylesheet bounds. */ + a0 = lbx_clamp(ctx, a0); + a1 = lbx_clamp(ctx, a1); + b0 = lbx_clamp(ctx, b0); + b1 = lbx_clamp(ctx, b1); + + if (ctx->events_len == ctx->events_cap) { + size_t cap = ctx->events_cap == 0 ? 256 : ctx->events_cap * 2; + lbx_event_t *events = lexbor_realloc(ctx->events, cap * sizeof(lbx_event_t)); + + if (events == NULL) { + ctx->oom = true; + return; + } + + ctx->events = events; + ctx->events_cap = cap; + } + + lbx_event_t *event = &ctx->events[ctx->events_len++]; + + event->kind = kind; + event->flags = flags; + event->a0 = (uint32_t) (a0 - (uintptr_t) ctx->css); + event->a1 = (uint32_t) (a1 - (uintptr_t) ctx->css); + event->b0 = (uint32_t) (b0 - (uintptr_t) ctx->css); + event->b1 = (uint32_t) (b1 - (uintptr_t) ctx->css); +} + +static void +lbx_prelude_reset(lbx_ctx_t *ctx) +{ + ctx->prelude_begin = 0; + ctx->prelude_end = 0; + ctx->prelude_seen = false; +} + +/* Consume every remaining token of the current phase. */ +static bool +lbx_consume_all(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +/* State callbacks ---------------------------------------------------------- */ + +static bool +lbx_state_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lbx_consume_all(parser, token); +} + +/* `next` states run after a child rule completes; the parser owns the + * current token, so they must not consume. */ +static bool +lbx_next_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + (void) token; + (void) ctx; + + return lxb_css_parser_success(parser); +} + +static bool +lbx_decl_value_state(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lbx_consume_all(parser, token); +} + +/* Prelude readers: accumulate the span, then consume. */ + +static bool +lbx_read_prelude(lbx_ctx_t *ctx, lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + uintptr_t begin = (uintptr_t) lxb_css_syntax_token_base(token)->begin; + uintptr_t end = begin + lxb_css_syntax_token_base(token)->length; + + if (!ctx->prelude_seen) { + ctx->prelude_seen = true; + ctx->prelude_begin = begin; + ctx->prelude_end = end; + } + else { + if (begin < ctx->prelude_begin) { + ctx->prelude_begin = begin; + } + if (end > ctx->prelude_end) { + ctx->prelude_end = end; + } + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static bool +lbx_at_prelude(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lbx_read_prelude((lbx_ctx_t *) ctx, parser, token); +} + +static bool +lbx_qualified_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lbx_read_prelude((lbx_ctx_t *) ctx, parser, token); +} + +/* Done callbacks ----------------------------------------------------------- */ + +static lxb_status_t +lbx_noop_end(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static lxb_status_t +lbx_at_prelude_end(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *context, bool failed) +{ + lbx_ctx_t *ctx = context; + uint8_t flags = failed ? LBX_FLAG_FAILED : 0; + + if (ctx->prelude_seen) { + lbx_emit(ctx, LBX_AT_PRELUDE, flags, + ctx->prelude_begin, ctx->prelude_end, 0, 0); + } + else if (ctx->at_depth > 0) { + /* The prelude state never ran; reconstruct the span from the + * at-keyword start to the terminator token (`;`, `{`, or EOF). */ + uintptr_t begin = ctx->at_stack[ctx->at_depth - 1].begin; + uintptr_t end = (uintptr_t) lxb_css_syntax_token_base(token)->begin; + + if (end > begin) { + lbx_emit(ctx, LBX_AT_PRELUDE, flags, begin, end, 0, 0); + } + } + + lbx_prelude_reset(ctx); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lbx_at_end(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *context, bool failed) +{ + lbx_ctx_t *ctx = context; + uint8_t flags = failed ? LBX_FLAG_FAILED : 0; + + if (ctx->at_depth == 0) { + return LXB_STATUS_OK; + } + + ctx->at_depth--; + + uintptr_t begin = ctx->at_stack[ctx->at_depth].begin; + uintptr_t end = (uintptr_t) lxb_css_syntax_token_base(token)->begin + + lxb_css_syntax_token_base(token)->length; + + if (end > ctx->css_len + (uintptr_t) ctx->css) { + end = ctx->css_len + (uintptr_t) ctx->css; + } + + if (ctx->at_stack[ctx->at_depth].has_block) { + flags |= LBX_FLAG_HAS_BLOCK; + } + + lbx_emit(ctx, LBX_AT_END, flags, begin, end, 0, 0); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lbx_qualified_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *context, + bool failed) +{ + lbx_ctx_t *ctx = context; + + uint8_t flags = failed ? LBX_FLAG_FAILED : 0; + + if (ctx->prelude_seen) { + lbx_emit(ctx, LBX_STYLE_BEGIN, flags, + ctx->prelude_begin, ctx->prelude_end, 0, 0); + } + + lbx_prelude_reset(ctx); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lbx_qualified_end(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *context, bool failed) +{ + lbx_emit((lbx_ctx_t *) context, LBX_STYLE_END, 0, 0, 0, 0, 0); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lbx_decl_end(lxb_css_parser_t *parser, void *declaration, void *context, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed) +{ + lbx_ctx_t *ctx = context; + uint8_t flags = 0; + + if (important) { + flags |= LBX_FLAG_IMPORTANT; + } + + if (failed) { + flags |= LBX_FLAG_FAILED; + } + + uintptr_t value_begin = (uintptr_t) ctx->css + offset->value_begin; + uintptr_t value_end = (uintptr_t) ctx->css + offset->value_end; + + lbx_emit(ctx, LBX_DECL, flags, ctx->decl_name_begin, ctx->decl_name_end, + value_begin, value_end); + + return LXB_STATUS_OK; +} + +/* Begin callbacks ---------------------------------------------------------- */ + +static const lxb_css_syntax_cb_at_rule_t * +lbx_begin_at_rule(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lbx_ctx_t *c = &lbx_ctx; + + (void) ctx; + + if (c->at_depth == sizeof(c->at_stack) / sizeof(c->at_stack[0])) { + c->oom = true; + return NULL; + } + + uintptr_t begin = (uintptr_t) lxb_css_syntax_token_base(token)->begin; + + c->at_stack[c->at_depth].begin = begin; + c->at_stack[c->at_depth].has_block = false; + c->at_depth++; + + lbx_emit(c, LBX_AT_BEGIN, 0, begin, + begin + lxb_css_syntax_token_base(token)->length, 0, 0); + + *out_rule = c; + + return &lbx_at_rule_cb; +} + +static const lxb_css_syntax_cb_qualified_rule_t * +lbx_begin_qualified(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule) +{ + (void) ctx; + *out_rule = &lbx_ctx; + + return &lbx_qualified_rule_cb; +} + +static const lxb_css_syntax_cb_declarations_t * +lbx_begin_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule) +{ + (void) parser; + (void) token; + (void) ctx; + *out_rule = &lbx_ctx; + + return &lbx_declarations_cb; +} + +static const lxb_css_syntax_cb_block_t * +lbx_begin_block(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lbx_ctx_t *c = &lbx_ctx; + + (void) parser; + (void) token; + + + if (c->at_depth > 0) { + c->at_stack[c->at_depth - 1].has_block = true; + } + + (void) parser; + (void) token; + *out_rule = &lbx_ctx; + + return &lbx_block_cb; +} + +/* Declaration name: record the span, return the value state. */ + +static lxb_css_parser_state_f +lbx_decl_name(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lbx_ctx_t *c = ctx; + + c->decl_name_begin = (uintptr_t) lxb_css_syntax_token_base(token)->begin; + c->decl_name_end = c->decl_name_begin + + lxb_css_syntax_token_base(token)->length; + + *out_rule = &lbx_ctx; + + return lbx_decl_value_state; +} + +/* Callback structs ---------------------------------------------------------- */ + +static const lxb_css_syntax_cb_list_rules_t lbx_list_rules_cb = { + .cb = { + .failed = lbx_state_success, + .end = lbx_noop_end, + }, + .next = lbx_next_success, + .at_rule = lbx_begin_at_rule, + .qualified_rule = lbx_begin_qualified, +}; + +static const lxb_css_syntax_cb_at_rule_t lbx_at_rule_cb = { + .cb = { + .failed = lbx_state_success, + .end = lbx_at_end, + }, + .prelude = lbx_at_prelude, + .prelude_end = lbx_at_prelude_end, + .block = lbx_begin_block, +}; + +static const lxb_css_syntax_cb_qualified_rule_t lbx_qualified_rule_cb = { + .cb = { + .failed = lbx_state_success, + .end = lbx_qualified_end, + }, + .prelude = lbx_qualified_prelude, + .prelude_end = lbx_qualified_prelude_end, + .block = lbx_begin_block, +}; + +static const lxb_css_syntax_cb_block_t lbx_block_cb = { + .cb = { + .failed = lbx_state_success, + .end = lbx_noop_end, + }, + .next = lbx_next_success, + .at_rule = lbx_begin_at_rule, + .declarations = lbx_begin_declarations, + .qualified_rule = lbx_begin_qualified, +}; + +static const lxb_css_syntax_cb_declarations_t lbx_declarations_cb = { + .cb = { + .failed = lbx_state_success, + .end = lbx_noop_end, + }, + .name = lbx_decl_name, + .end = lbx_decl_end, +}; + +/* Entry points --------------------------------------------------------------- */ + +static lbx_ctx_t lbx_ctx; + +int +lbx_parse(const unsigned char *css, size_t css_len, + lbx_event_t **out_events, size_t *out_len) +{ + lxb_css_parser_t *parser; + lxb_css_memory_t *memory; + lxb_status_t status; + + *out_events = NULL; + *out_len = 0; + + memset(&lbx_ctx, 0, sizeof(lbx_ctx_t)); + + lbx_ctx.css = css; + lbx_ctx.css_len = css_len; + + parser = lxb_css_parser_create(); + if (parser == NULL) { + return 1; + } + + status = lxb_css_parser_init(parser, NULL); + if (status != LXB_STATUS_OK) { + lxb_css_parser_destroy(parser, true); + return 1; + } + + memory = lxb_css_memory_create(); + if (memory == NULL) { + lxb_css_parser_destroy(parser, true); + return 1; + } + + status = lxb_css_memory_init(memory, 1024); + if (status != LXB_STATUS_OK) { + lxb_css_memory_destroy(memory, true); + lxb_css_parser_destroy(parser, true); + return 1; + } + + lxb_css_parser_memory_set(parser, memory); + + if (lxb_css_syntax_parse_list_rules(parser, &lbx_list_rules_cb, + (const lxb_char_t *) css, css_len) == NULL + && parser->status != LXB_STATUS_OK && !lbx_ctx.oom) + { + lexbor_free(lbx_ctx.events); + lxb_css_memory_destroy(memory, true); + lxb_css_parser_destroy(parser, true); + return 1; + } + + lxb_css_memory_destroy(memory, true); + lxb_css_parser_destroy(parser, true); + + if (lbx_ctx.oom) { + lexbor_free(lbx_ctx.events); + return 1; + } + + *out_events = lbx_ctx.events; + *out_len = lbx_ctx.events_len; + + + return 0; +} + +void +lbx_free_events(lbx_event_t *events, size_t len) +{ + lexbor_free(events); +} + +/* + * Compat shims for the trimmed vendor build. The legacy css/state.c and the + * typed at-rule/property layers are not compiled; only these handful of + * symbols remain referenced by the syntax parser: + * + * - lxb_css_state_success is the parser's default running state. + * - The typed destroy hooks are only reached through lxb_css_rule_destroy's + * switch arms for payloads this shim never builds (rule contexts are the + * parse context, so `u.*` members are always NULL); real lexbor frees + * nothing for a NULL payload either. + */ +bool +lxb_css_state_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + return true; + case LXB_CSS_SYNTAX_TOKEN__END: + return true; + default: + return lxb_css_parser_failed(parser); + } +} + +bool +lxb_css_state_blank(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_parser_success(parser); +} + +bool +lxb_css_state_stop(lxb_css_parser_t *parser, const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_parser_stop(parser); +} + +void * +lxb_css_at_rule__undef_destroy(lxb_css_memory_t *memory, void *style, + bool self_destroy) +{ + (void) memory; + (void) style; + (void) self_destroy; + + return NULL; +} + +void * +lxb_css_at_rule_media_destroy(lxb_css_memory_t *memory, void *style, + bool self_destroy) +{ + (void) memory; + (void) style; + (void) self_destroy; + + return NULL; +} + +void * +lxb_css_at_rule_namespace_destroy(lxb_css_memory_t *memory, void *style, + bool self_destroy) +{ + (void) memory; + (void) style; + (void) self_destroy; + + return NULL; +} + +void * +lxb_css_property_destroy(lxb_css_memory_t *memory, void *style, + int type, bool self_destroy) +{ + (void) memory; + (void) style; + (void) type; + (void) self_destroy; + + return NULL; +} + +void +lxb_css_selector_list_destroy(lxb_css_selector_list_t *list) +{ + (void) list; +} diff --git a/experiments/css/crates/css-compiler/examples/compile_time.rs b/experiments/css/crates/css-compiler/examples/compile_time.rs new file mode 100644 index 0000000..bae63ea --- /dev/null +++ b/experiments/css/crates/css-compiler/examples/compile_time.rs @@ -0,0 +1,31 @@ +//! Compile-throughput probe for the bench corpus shape. + +use std::time::Instant; + +use bombshell_css_compiler::{CompileOptions, compile}; +use bombshell_css_core::Origin; + +fn main() { + let css = std::fs::read_to_string( + std::env::args().nth(1).expect("corpus path argument"), + ) + .expect("corpus file"); + + for _ in 0..5 { + let _ = compile(&css, Origin::Author, CompileOptions::default()); + } + let mut times = Vec::new(); + for _ in 0..30 { + let start = Instant::now(); + let out = compile(&css, Origin::Author, CompileOptions::default()); + times.push(start.elapsed()); + let _ = out; + } + times.sort(); + let median = times[times.len() / 2]; + println!( + "native compile: median {:.2?} → {:.1} MB/s", + median, + css.len() as f64 / median.as_secs_f64() / 1_048_576.0 + ); +} diff --git a/experiments/css/crates/css-compiler/examples/events.rs b/experiments/css/crates/css-compiler/examples/events.rs new file mode 100644 index 0000000..9728dc6 --- /dev/null +++ b/experiments/css/crates/css-compiler/examples/events.rs @@ -0,0 +1,60 @@ +use bombshell_css_compiler::{CompileOptions, compile}; +use bombshell_css_core::Origin; + +fn main() { + if let Some(path) = std::env::args().nth(2) { + let css = std::fs::read_to_string(&path).unwrap(); + let out = compile(&css, Origin::Author, Default::default()); + let sheet = out.sheet.unwrap(); + for rule in &sheet.rules { + println!("{} media={:#?}", rule.selector, rule.media); + } + if !sheet.warnings.is_empty() { + println!("warnings: {:#?}", sheet.warnings); + } + return; + } + let skip: usize = std::env::args() + .nth(1) + .and_then(|a| a.parse().ok()) + .unwrap_or(0); + for css in [ + ".a { color: red }", + "@layer base;", + "@layer base.type { .a { color: red } }", + "@media (min-width: 24em) { .a { color: red } }", + "@media (min-width: 24em) { @container panel (inline-size > 45em) { @supports (color: oklch(70% 0.2 40)) { .b { color: blue } } } }", + ".card { color: red; & > .title { font-weight: bold } .body { color: blue } }", + "@layer base;\n@layer base.type { .a { color: red } }", + "@keyframes pulse { from { opacity: 1 } to { opacity: 0 } }\n@font-face { font-family: X; src: url(x.woff2) }", + ".a { color: red } .a:hover { color: blue }", + ".card { color: oklch(70% 0.2 40); & > .title { font-weight: bold; &:hover { text-decoration: underline; } } }", + "@media (prefers-color-scheme: dark) { .a { color: green } }", + "@media (prefers-reduced-motion: reduce) { .a { color: blue } }", + "@media screen and (not (hover)) { .a { color: orange } }", + ".btn { color: gray }\n.btn:hover { color: white }\n.btn:active { color: black }\n.btn:focus { outline: 1px }\n.btn:focus-within { border-color: cyan }", + ".item:first-child { color: blue }\n.root .item { color: green }", + ".item:nth-child(2n + 1 of .tagged) { color: yellow }\n.item:not(.skip):not(.list > *) { color: blue }", + ":root { --brand: oklch(70% .2 40); --gap: 8px; color: var(--brand) }\n.box { border-color: var(--brand); margin: var(--gap) }\n.box { --gap: 4px }", + ] + .into_iter() + .enumerate() + .skip(skip) + { + let (i, css) = css; + println!("[case {i}]"); + let out = compile(css, Origin::Author, CompileOptions::default()); + match &out.sheet { + Some(sheet) => { + println!("--- {:?}\n rules={} layers={:?} keyframes={} opaque={}", css, sheet.rules.len(), sheet.layer_order, sheet.keyframes.len(), sheet.opaque.len()); + for rule in &sheet.rules { + println!(" {} sp={:#x} decls={:?}", rule.selector, rule.specificity, rule.declarations); + } + } + None => println!("--- {:?}\n FAILED {:?}", css, out.diagnostics), + } + if !out.diagnostics.is_empty() { + println!(" diags: {:?}", out.diagnostics); + } + } +} diff --git a/experiments/css/crates/css-compiler/src/alloc_shim.rs b/experiments/css/crates/css-compiler/src/alloc_shim.rs new file mode 100644 index 0000000..ae98167 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/alloc_shim.rs @@ -0,0 +1,100 @@ +//! C allocator for freestanding wasm32. +//! +//! lexbor's allocator calls `malloc`/`free`/`calloc`/`realloc`; on +//! `wasm32-unknown-unknown` there is no libc, so these are backed by the +//! Rust global allocator. Every allocation carries a size header so `free` +//! can reconstruct the layout (alignment is fixed at the header's). + +#![cfg(target_arch = "wasm32")] + +use std::alloc::{Layout, alloc, alloc_zeroed, dealloc}; + +#[repr(C)] +struct Header { + size: usize, +} + +const HEADER_ALIGN: usize = core::mem::align_of::
(); + +fn padded(size: usize) -> usize { + (size + HEADER_ALIGN - 1) & !(HEADER_ALIGN - 1) +} + +#[unsafe(no_mangle)] +pub extern "C" fn malloc(size: usize) -> *mut u8 { + let size = size.max(1); + let Ok(layout) = Layout::from_size_align(size_of::
() + padded(size), HEADER_ALIGN) + else { + return std::ptr::null_mut(); + }; + + unsafe { + let base = alloc(layout); + if base.is_null() { + return std::ptr::null_mut(); + } + *(base as *mut Header) = Header { size }; + base.add(size_of::
()) + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn free(pointer: *mut u8) { + if pointer.is_null() { + return; + } + + unsafe { + let header = pointer.sub(size_of::
()) as *mut Header; + let size = (*header).size; + if let Ok(layout) = Layout::from_size_align( + size_of::
() + padded(size), + HEADER_ALIGN, + ) { + dealloc(pointer.sub(size_of::
()), layout); + } + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn calloc(count: usize, size: usize) -> *mut u8 { + let Some(total) = count.checked_mul(size) else { + return std::ptr::null_mut(); + }; + let total = total.max(1); + let Ok(layout) = Layout::from_size_align(size_of::
() + padded(total), HEADER_ALIGN) + else { + return std::ptr::null_mut(); + }; + + unsafe { + let base = alloc_zeroed(layout); + if base.is_null() { + return std::ptr::null_mut(); + } + *(base as *mut Header) = Header { size: total }; + base.add(size_of::
()) + } +} + +#[unsafe(no_mangle)] +pub extern "C" fn realloc(pointer: *mut u8, size: usize) -> *mut u8 { + if pointer.is_null() { + return malloc(size); + } + + let old_size = unsafe { (*(pointer.sub(size_of::
()) as *const Header)).size }; + + let new = malloc(size); + if new.is_null() { + return std::ptr::null_mut(); + } + + unsafe { + std::ptr::copy_nonoverlapping(pointer, new, old_size.min(size)); + } + + free(pointer); + + new +} \ No newline at end of file diff --git a/experiments/css/crates/css-compiler/src/canonical.rs b/experiments/css/crates/css-compiler/src/canonical.rs new file mode 100644 index 0000000..fcc5883 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/canonical.rs @@ -0,0 +1,284 @@ +//! Canonical declaration values. +//! +//! The previous lightningcss-backed front-end serialized every value through +//! its printer with `minify: true`. This module reproduces the observable +//! contract with token-level re-serialization: numbers lose redundant +//! leading/trailing zeros (`0.2` → `.2`), and color-property values are +//! validated (a color is a single component: keyword, hash, or function) +//! so invalid declarations report through the recovery paths like they used +//! to. `light-dark(a, b)` is preserved (branches canonicalized) for the +//! runtime, which resolves it against the color scheme at computed-value +//! time. + +use bombshell_css_core::Diagnostic; +use bombshell_css_core::tokens::write_token; +use cssparser::{Parser as CssParser, ParserInput, Token}; + +use crate::colors::named_color; + +/// Canonicalize a declaration value; `Err` marks the declaration invalid. +pub(crate) fn canonicalize(name: &str, value: &str) -> Result { + // Custom properties keep their value verbatim (substituted text is + // resolved at computed-value time). + if name.starts_with("--") { + return Ok(value.to_string()); + } + + // CSS-wide keywords are valid for every property. + match value.trim() { + "inherit" | "initial" | "unset" | "revert" | "revert-layer" => { + return Ok(value.trim().to_string()); + } + _ => {} + } + + if bombshell_css_core::is_color_property(name) { + // `light-dark(a, b)` survives to the runtime, which resolves it + // against the environment's color scheme at computed-value time. + // Both branches are validated and canonicalized here so the IR only + // ever carries canonical color text. + if is_light_dark_value(value) { + let Some((light, dark)) = split_light_dark(value) else { + return Err(invalid_color(value)); + }; + validate_color(light.trim())?; + validate_color(dark.trim())?; + return Ok(minify_value(&format!( + "light-dark({}, {})", + canonical_color(light.trim()), + canonical_color(dark.trim()), + ))); + } + + validate_color(value)?; + return Ok(canonical_color(value)); + } + + if name == "font-weight" { + return Ok(match value.trim() { + "bold" => "700".to_string(), + "normal" => "400".to_string(), + other => other.to_string(), + }); + } + + Ok(minify_value(value)) +} + +/// Canonical color text: the shortest representation wins and ties go to +/// hex (the previous front-end's printer behavior: `red` stays, `yellow` → +/// `#ff0`). +fn canonical_color(value: &str) -> String { + let trimmed = value.trim(); + if let Some(hex) = named_color(trimmed.to_ascii_lowercase().as_str()) { + return if trimmed.len() < hex.len() { + trimmed.to_ascii_lowercase() + } else { + hex.to_string() + }; + } + minify_value(trimmed) +} + +/// The shared diagnostic for a color value that does not parse. +fn invalid_color(value: &str) -> Diagnostic { + Diagnostic::warning( + "declaration", + { + let mut message = String::from("invalid color value `"); + message.push_str(value); + message.push('`'); + message + }, + ) +} + +/// `light-dark(a, b)` → its two branches, split at the top-level comma. +/// Function names are case-insensitive; anything that is not exactly the +/// two-argument form returns `None` (the caller reports it invalid). +fn split_light_dark(value: &str) -> Option<(String, String)> { + let trimmed = value.trim(); + if !trimmed[..trimmed.len().min("light-dark(".len())] + .eq_ignore_ascii_case("light-dark(") + { + return None; + } + let rest = &trimmed["light-dark(".len()..]; + if !rest.ends_with(')') { + return None; + } + let rest = &rest[..rest.len() - 1]; + + let mut split: Option = None; + let mut depth = 0usize; + let mut quote: Option = None; + for (i, &b) in rest.as_bytes().iter().enumerate() { + match quote { + Some(q) if b == q => quote = None, + Some(_) => {} + None => match b { + b'"' | b'\'' => quote = Some(b), + b'(' => depth += 1, + b')' => depth = depth.saturating_sub(1), + b',' if depth == 0 => { + if split.is_some() { + // A second top-level comma is not the two-argument + // form. + return None; + } + split = Some(i); + } + _ => {} + }, + } + } + + let comma = split?; + let (light, dark) = (&rest[..comma], &rest[comma + 1..]); + Some((light.trim().to_string(), dark.trim().to_string())) +} + +/// Whether the value is a `light-dark(...)` function call (case-insensitive +/// name, balanced parens). +fn is_light_dark_value(value: &str) -> bool { + let trimmed = value.trim(); + let lower = trimmed.to_ascii_lowercase(); + lower.starts_with("light-dark(") && trimmed.ends_with(')') +} + +/// A color value is one component: a keyword, a hash, or a balanced +/// function call. +/// +/// Hex payloads may be 3, 4, 6, or 8 hex digits (`#abc`, `#abcd`, +/// `#aabbcc`, `#aabbccdd`). +fn is_valid_hex(hash: &str) -> bool { + let bytes = hash.as_bytes(); + matches!(bytes.len(), 3 | 4 | 6 | 8) + && bytes.iter().all(|b| b.is_ascii_hexdigit()) +} + +fn validate_color(value: &str) -> Result<(), Diagnostic> { + let mut input = ParserInput::new(value); + let mut parser = CssParser::new(&mut input); + + let valid = parser + .try_parse(|parser| -> Result<(), cssparser::ParseError<'_, ()>> { + match parser.next_including_whitespace() { + // Hex colors tokenize as `Hash` when the payload starts with a + // digit (`#333`) and as `IDHash` when it reads as an + // identifier (`#fff`); both are the same value grammar, + // and both still require hex-digit syntax. + Ok(Token::Hash(hash) | Token::IDHash(hash)) => { + if !is_valid_hex(hash) { + return Err(cssparser::ParseError { + kind: cssparser::ParseErrorKind::Custom(()), + location: parser.current_source_location(), + }); + } + } + Ok(Token::Ident(ident)) => { + let name = ident.to_ascii_lowercase(); + if named_color(&name).is_none() + && name != "currentcolor" + && name != "transparent" + { + return Err(cssparser::ParseError { + kind: cssparser::ParseErrorKind::Custom(()), + location: parser.current_source_location(), + }); + } + } + Ok(Token::Function(_)) => { + // Modern spaces accept any balanced function here; the + // runtime evaluates the text. + parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + loop { + match parser.next_including_whitespace() { + Ok(_) => {} + Err(_) => break, + } + } + Ok(()) + }, + )?; + } + _ => { + return Err(cssparser::ParseError { + kind: cssparser::ParseErrorKind::Custom(()), + location: parser.current_source_location(), + }); + } + } + + // Nothing else may follow. + match parser.next_including_whitespace() { + Err(_) => Ok(()), + Ok(_) => Err(cssparser::ParseError { + kind: cssparser::ParseErrorKind::Custom(()), + location: parser.current_source_location(), + }), + } + }) + .is_ok(); + + if valid { + Ok(()) + } else { + Err(invalid_color(value)) + } +} + +/// Re-serialize a value: whitespace collapses to single spaces and numeric +/// tokens drop redundant zeros. +pub(crate) fn minify_value(value: &str) -> String { + let mut input = ParserInput::new(value); + let mut parser = CssParser::new(&mut input); + let mut out = String::with_capacity(value.len()); + write_value_tokens(&mut parser, &mut out); + out +} + +fn write_value_tokens(parser: &mut CssParser<'_, '_>, out: &mut String) { + let mut pending_space = false; + + loop { + match parser.next_including_whitespace_and_comments() { + Ok(token) => match token { + Token::Comment(_) => {} + Token::WhiteSpace(_) => pending_space = true, + Token::Function(_) + | Token::ParenthesisBlock + | Token::SquareBracketBlock + | Token::CurlyBracketBlock => { + if pending_space && !out.is_empty() { + out.push(' '); + } + pending_space = false; + write_token(out, &token); + let closer = match token { + Token::SquareBracketBlock => ']', + Token::CurlyBracketBlock => '}', + _ => ')', + }; + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_value_tokens(parser, out); + Ok(()) + }, + ); + out.push(closer); + } + other => { + if pending_space && !out.is_empty() { + out.push(' '); + } + pending_space = false; + write_token(out, &other); + } + }, + Err(_) => break, + } + } +} + diff --git a/experiments/css/crates/css-compiler/src/colors.rs b/experiments/css/crates/css-compiler/src/colors.rs new file mode 100644 index 0000000..c7e3203 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/colors.rs @@ -0,0 +1,54 @@ +//! Canonical color keyword table (CSS Color 3 named colors). +//! +//! lightningcss canonicalized named colors to hex at compile time; the +//! runtime consumes hex/functional colors directly, so this table keeps +//! the IR byte-for-byte compatible with the previous front-end. + +/// Shortest-hex form for every CSS named color (lowercase). +pub(crate) fn named_color(name: &str) -> Option<&'static str> { + // Packed storage: one blob plus u16 (name, hex) offsets. The binary + // search compares the same slices the old pointer-array table did; + // packing only changes how the strings live in linear memory. + OFFSETS + .binary_search_by(|&(name_off, hex_off)| { + let end = hex_off - 1; + BLOB[name_off as usize..end as usize].cmp(name) + }) + .ok() + .map(|index| { + let (_, hex_off) = OFFSETS[index]; + let end = OFFSETS + .get(index + 1) + .map(|&(next_name, _)| next_name - 1) + .unwrap_or(BLOB.len() as u16); + &BLOB[hex_off as usize..end as usize] + }) +} + +const BLOB: &str = "aliceblue\0#f0f8ff\0antiquewhite\0#faebd7\0aqua\0#0ff\0aquamarine\0#7fffd4\0azure\0#f0ffff\0beige\0#f5f5dc\0bisque\0#ffe4c4\0black\0#000\0blanchedalmond\0#ffebcd\0blue\0#00f\0blueviolet\0#8a2be2\0brown\0#a52a2a\0burlywood\0#deb887\0cadetblue\0#5f9ea0\0chartreuse\0#7fff00\0chocolate\0#d2691e\0coral\0#ff7f50\0cornflowerblue\0#6495ed\0cornsilk\0#fff8dc\0crimson\0#dc143c\0cyan\0#0ff\0darkblue\0#00008b\0darkcyan\0#008b8b\0darkgoldenrod\0#b8860b\0darkgray\0#a9a9a9\0darkgreen\0#006400\0darkgrey\0#a9a9a9\0darkkhaki\0#bdb76b\0darkmagenta\0#8b008b\0darkolivegreen\0#556b2f\0darkorange\0#ff8c00\0darkorchid\0#9932cc\0darkred\0#8b0000\0darksalmon\0#e9967a\0darkseagreen\0#8fbc8f\0darkslateblue\0#483d8b\0darkslategray\0#2f4f4f\0darkslategrey\0#2f4f4f\0darkturquoise\0#00ced1\0darkviolet\0#9400d3\0deeppink\0#ff1493\0deepskyblue\0#00bfff\0dimgray\0#696969\0dimgrey\0#696969\0dodgerblue\0#1e90ff\0firebrick\0#b22222\0floralwhite\0#fffaf0\0forestgreen\0#228b22\0fuchsia\0#f0f\0gainsboro\0#dcdcdc\0ghostwhite\0#f8f8ff\0gold\0#ffd700\0goldenrod\0#daa520\0gray\0#808080\0green\0#008000\0greenyellow\0#adff2f\0grey\0#808080\0honeydew\0#f0fff0\0hotpink\0#ff69b4\0indianred\0#cd5c5c\0indigo\0#4b0082\0ivory\0#fffff0\0khaki\0#f0e68c\0lavender\0#e6e6fa\0lavenderblush\0#fff0f5\0lawngreen\0#7cfc00\0lemonchiffon\0#fffacd\0lightblue\0#add8e6\0lightcoral\0#f08080\0lightcyan\0#e0ffff\0lightgoldenrodyellow\0#fafad2\0lightgray\0#d3d3d3\0lightgreen\0#90ee90\0lightgrey\0#d3d3d3\0lightpink\0#ffb6c1\0lightsalmon\0#ffa07a\0lightseagreen\0#20b2aa\0lightskyblue\0#87cefa\0lightslategray\0#778899\0lightslategrey\0#778899\0lightsteelblue\0#b0c4de\0lightyellow\0#ffffe0\0lime\0#0f0\0limegreen\0#32cd32\0linen\0#faf0e6\0magenta\0#f0f\0maroon\0#800000\0mediumaquamarine\0#66cdaa\0mediumblue\0#0000cd\0mediumorchid\0#ba55d3\0mediumpurple\0#9370db\0mediumseagreen\0#3cb371\0mediumslateblue\0#7b68ee\0mediumspringgreen\0#00fa9a\0mediumturquoise\0#48d1cc\0mediumvioletred\0#c71585\0midnightblue\0#191970\0mintcream\0#f5fffa\0mistyrose\0#ffe4e1\0moccasin\0#ffe4b5\0navajowhite\0#ffdead\0navy\0#000080\0oldlace\0#fdf5e6\0olive\0#808000\0olivedrab\0#6b8e23\0orange\0#ffa500\0orangered\0#ff4500\0orchid\0#da70d6\0palegoldenrod\0#eee8aa\0palegreen\0#98fb98\0paleturquoise\0#afeeee\0palevioletred\0#db7093\0papayawhip\0#ffefd5\0peachpuff\0#ffdab9\0peru\0#cd853f\0pink\0#ffc0cb\0plum\0#dda0dd\0powderblue\0#b0e0e6\0purple\0#800080\0rebeccapurple\0#663399\0red\0#f00\0rosybrown\0#bc8f8f\0royalblue\0#4169e1\0saddlebrown\0#8b4513\0salmon\0#fa8072\0sandybrown\0#f4a460\0seagreen\0#2e8b57\0seashell\0#fff5ee\0sienna\0#a0522d\0silver\0#c0c0c0\0skyblue\0#87ceeb\0slateblue\0#6a5acd\0slategray\0#708090\0slategrey\0#708090\0snow\0#fffafa\0springgreen\0#00ff7f\0steelblue\0#4682b4\0tan\0#d2b48c\0teal\0#008080\0thistle\0#d8bfd8\0tomato\0#ff6347\0turquoise\0#40e0d0\0violet\0#ee82ee\0wheat\0#f5deb3\0white\0#fff\0whitesmoke\0#f5f5f5\0yellow\0#ff0\0yellowgreen\0#9acd32\0"; + +/// (name offset, hex offset) into [`BLOB`], sorted by name; the hex runs +/// to the next entry's name (or the end). +const OFFSETS: &[(u16, u16)] = &[(0, 10), (18, 31), (39, 44), (49, 60), (68, 74), (82, 88), (96, 103), (111, 117), (122, 137), (145, 150), (155, 166), (174, 180), (188, 198), (206, 216), (224, 235), (243, 253), (261, 267), (275, 290), (298, 307), (315, 323), (331, 336), (341, 350), (358, 367), (375, 389), (397, 406), (414, 424), (432, 441), (449, 459), (467, 479), (487, 502), (510, 521), (529, 540), (548, 556), (564, 575), (583, 596), (604, 618), (626, 640), (648, 662), (670, 684), (692, 703), (711, 720), (728, 740), (748, 756), (764, 772), (780, 791), (799, 809), (817, 829), (837, 849), (857, 865), (870, 880), (888, 899), (907, 912), (920, 930), (938, 943), (951, 957), (965, 977), (985, 990), (998, 1007), (1015, 1023), (1031, 1041), (1049, 1056), (1064, 1070), (1078, 1084), (1092, 1101), (1109, 1123), (1131, 1141), (1149, 1162), (1170, 1180), (1188, 1199), (1207, 1217), (1225, 1246), (1254, 1264), (1272, 1283), (1291, 1301), (1309, 1319), (1327, 1339), (1347, 1361), (1369, 1382), (1390, 1405), (1413, 1428), (1436, 1451), (1459, 1471), (1479, 1484), (1489, 1499), (1507, 1513), (1521, 1529), (1534, 1541), (1549, 1566), (1574, 1585), (1593, 1606), (1614, 1627), (1635, 1650), (1658, 1674), (1682, 1700), (1708, 1724), (1732, 1748), (1756, 1769), (1777, 1787), (1795, 1805), (1813, 1822), (1830, 1842), (1850, 1855), (1863, 1871), (1879, 1885), (1893, 1903), (1911, 1918), (1926, 1936), (1944, 1951), (1959, 1973), (1981, 1991), (1999, 2013), (2021, 2035), (2043, 2054), (2062, 2072), (2080, 2085), (2093, 2098), (2106, 2111), (2119, 2130), (2138, 2145), (2153, 2167), (2175, 2179), (2184, 2194), (2202, 2212), (2220, 2232), (2240, 2247), (2255, 2266), (2274, 2283), (2291, 2300), (2308, 2315), (2323, 2330), (2338, 2346), (2354, 2364), (2372, 2382), (2390, 2400), (2408, 2413), (2421, 2433), (2441, 2451), (2459, 2463), (2471, 2476), (2484, 2492), (2500, 2507), (2515, 2525), (2533, 2540), (2548, 2554), (2562, 2568), (2573, 2584), (2592, 2599), (2604, 2616)]; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn table_is_sorted_and_complete() { + assert_eq!(named_color("aliceblue"), Some("#f0f8ff")); + assert_eq!(named_color("rebeccapurple"), Some("#663399")); + assert_eq!(named_color("yellow"), Some("#ff0")); + assert_eq!(named_color("black"), Some("#000")); + assert_eq!(named_color("teal"), Some("#008080")); + assert_eq!(named_color("missing"), None); + assert_eq!(named_color("zzz"), None); + assert_eq!(named_color("a"), None); + assert_eq!(OFFSETS.len(), 148); + for &(name_off, hex_off) in OFFSETS { + let hex = &BLOB[hex_off as usize..]; + assert!(hex.starts_with('#'), "{}", &BLOB[name_off as usize..hex_off as usize]); + } + } +} diff --git a/experiments/css/crates/css-compiler/src/conditions.rs b/experiments/css/crates/css-compiler/src/conditions.rs new file mode 100644 index 0000000..64ab600 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/conditions.rs @@ -0,0 +1,778 @@ +//! Parsing of raw at-rule preludes (`@media`, `@container`, `@supports`) +//! into the typed IR condition trees consumed by the runtime. +//! +//! The shim captures preludes as raw source text; this module re-tokenizes +//! them with `cssparser` and builds the same shapes lightningcss's typed AST +//! used to produce: legacy `min-*`/`max-*` names canonicalize into ranges, +//! interval comparisons stay as-written (the feature sits on the right of +//! the first operator), discrete feature values lowercase, and `@supports` +//! leaves are pre-evaluated at compile time. + +use bombshell_css_core::{ + Compare, ContainerCondition, Feature, FeatureKind, FeatureValue, MediaCondition, + SupportsCondition, +}; +use bombshell_css_core::tokens::write_token; +use cssparser::{Parser as CssParser, ParserInput, Token}; + +use bombshell_css_core::selectors::validate_and_specificity; +use crate::known_properties::is_known_property; + +// --------------------------------------------------------------------------- +// @media +// --------------------------------------------------------------------------- + +/// Parse a whole `@media` prelude. Comma-separated queries are ORs. +pub(crate) fn parse_media_prelude(text: &str) -> MediaCondition { + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + + let mut branches: Vec = Vec::new(); + let mut current: Vec = Vec::new(); + + loop { + match parser.next_including_whitespace() { + Ok(Token::Comma) => { + if !current.is_empty() { + branches.push(and_all(std::mem::take(&mut current))); + } + } + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + // A leading group is its own query (`(a) and (b)`, comma lists): + // dispatch it directly, then let the query parser read the rest. + Ok(Token::ParenthesisBlock) => { + current.push(parse_media_in_parens(&mut parser)); + } + Ok(_) => match parse_media_query(&mut parser) { + Some(condition) => current.push(condition), + None => current.push(MediaCondition::Unknown), + }, + Err(_) => break, + } + } + + if !current.is_empty() { + branches.push(and_all(current)); + } + + match branches.len() { + 0 => MediaCondition::And(vec![]), + 1 => branches.into_iter().next().unwrap(), + _ => MediaCondition::Or(branches), + } +} + +/// One comma-separated media query: `[only | not]? type? [and group]*`. +fn parse_media_query(parser: &mut CssParser<'_, '_>) -> Option { + let mut conjuncts: Vec = Vec::new(); + let mut qualifier_not = false; + + loop { + match parser.next_including_whitespace() { + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + Ok(Token::Comma) => break, + Ok(Token::Ident(name)) => { + let name = name.to_ascii_lowercase(); + match name.as_str() { + "only" => {} + "not" if conjuncts.is_empty() => qualifier_not = true, + "and" | "or" => {} + type_name => { + // Media type: the terminal target is a screen-like + // device. + let matches = matches!(type_name, "all" | "screen"); + if !matches { + conjuncts + .push(MediaCondition::Not(Box::new(MediaCondition::And(vec![])))); + } + } + } + } + Ok(Token::ParenthesisBlock) => { + conjuncts.push(parse_media_in_parens(parser)); + } + Ok(_) => return None, + Err(_) => break, + } + } + + let combined = match conjuncts.len() { + 0 => MediaCondition::And(vec![]), + 1 => conjuncts.into_iter().next().unwrap(), + _ => MediaCondition::And(conjuncts), + }; + Some(if qualifier_not { + MediaCondition::Not(Box::new(combined)) + } else { + combined + }) +} + +/// The contents of one `(...)` media group: either a single feature or +/// nested `and`/`or`/`not` algebra. +fn parse_media_in_parens(parser: &mut CssParser<'_, '_>) -> MediaCondition { + let text = capture_nested_text(parser); + + if let Some(feature) = parse_feature_text(&text) { + return MediaCondition::Feature(feature); + } + + let mut input = ParserInput::new(&text); + let mut inner = CssParser::new(&mut input); + + let mut operands: Vec = Vec::new(); + let mut operator: Option<&'static str> = None; + let mut negate = false; + + loop { + match inner.next_including_whitespace() { + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + Ok(Token::Ident(name)) => { + let name = name.to_ascii_lowercase(); + match name.as_str() { + "not" => negate = true, + "and" | "or" => { + let op: &'static str = if name == "and" { "and" } else { "or" }; + match operator { + None => operator = Some(op), + Some(existing) if existing == op => {} + // Mixed and/or at one level is invalid. + Some(_) => return MediaCondition::Unknown, + } + } + _ => return MediaCondition::Unknown, + } + } + Ok(Token::ParenthesisBlock) => { + operands.push(parse_media_in_parens(&mut inner)); + } + Ok(_) => return MediaCondition::Unknown, + Err(_) => break, + } + } + + let combined = match operands.len() { + 0 => MediaCondition::And(vec![]), + 1 => operands.into_iter().next().unwrap(), + _ => match operator { + Some("or") => MediaCondition::Or(operands), + _ => MediaCondition::And(operands), + }, + }; + + if negate { + MediaCondition::Not(Box::new(combined)) + } else { + combined + } +} + +// --------------------------------------------------------------------------- +// @container +// --------------------------------------------------------------------------- + +/// Parse a `@container` prelude: `[container-name]? condition`. +pub(crate) fn parse_container_prelude(text: &str) -> (Option, ContainerCondition) { + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + + let mut name: Option = None; + + loop { + match parser.next_including_whitespace() { + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + Ok(Token::Ident(ident)) => name = Some(ident.to_string()), + Ok(Token::ParenthesisBlock) => { + return (name, parse_container_in_parens(&mut parser)); + } + Ok(Token::Function(fn_name)) => { + let lower = fn_name.to_ascii_lowercase(); + let condition = match lower.as_str() { + "style" => ContainerCondition::Style { + text: capture_nested_text(&mut parser), + }, + "scroll-state" => { + consume_nested(&mut parser); + ContainerCondition::Unknown + } + "not" => { + ContainerCondition::Not(Box::new(parse_container_in_parens(&mut parser))) + } + _ => ContainerCondition::Unknown, + }; + return (name, condition); + } + Ok(_) | Err(_) => return (name, ContainerCondition::And(vec![])), + } + } +} + +/// The contents of one `(...)` container group: a size feature, or nested +/// `and`/`or`/`not` algebra (including `style(...)` operands). +fn parse_container_in_parens(parser: &mut CssParser<'_, '_>) -> ContainerCondition { + let text = capture_nested_text(parser); + + if let Some(feature) = parse_feature_text(&text) { + return ContainerCondition::Size(feature); + } + + let mut input = ParserInput::new(&text); + let mut inner = CssParser::new(&mut input); + + let mut operands: Vec = Vec::new(); + let mut operator: Option<&'static str> = None; + let mut negate = false; + + loop { + match inner.next_including_whitespace() { + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + Ok(Token::Ident(name)) => { + let name = name.to_ascii_lowercase(); + match name.as_str() { + "not" => negate = true, + "and" | "or" => { + let op: &'static str = if name == "and" { "and" } else { "or" }; + match operator { + None => operator = Some(op), + Some(existing) if existing == op => {} + Some(_) => return ContainerCondition::Unknown, + } + } + _ => return ContainerCondition::Unknown, + } + } + Ok(Token::ParenthesisBlock) => { + operands.push(parse_container_in_parens(&mut inner)); + } + Ok(Token::Function(fn_name)) => { + let lower = fn_name.to_ascii_lowercase(); + match lower.as_str() { + "style" => operands.push(ContainerCondition::Style { + text: capture_nested_text(&mut inner), + }), + "scroll-state" => { + consume_nested(&mut inner); + operands.push(ContainerCondition::Unknown); + } + "not" => { + let inner_condition = parse_container_in_parens(&mut inner); + operands.push(ContainerCondition::Not(Box::new(inner_condition))); + } + _ => return ContainerCondition::Unknown, + } + } + Ok(_) => return ContainerCondition::Unknown, + Err(_) => break, + } + } + + let combined = match operands.len() { + 0 => ContainerCondition::And(vec![]), + 1 => operands.into_iter().next().unwrap(), + _ => match operator { + Some("or") => ContainerCondition::Or(operands), + _ => ContainerCondition::And(operands), + }, + }; + + if negate { + ContainerCondition::Not(Box::new(combined)) + } else { + combined + } +} + +// --------------------------------------------------------------------------- +// @supports +// --------------------------------------------------------------------------- + +/// Parse a `@supports` prelude. +pub(crate) fn parse_supports_prelude(text: &str) -> SupportsCondition { + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + + parse_supports_algebra(&mut parser) +} + +/// Boolean algebra at one level over supports operands. +fn parse_supports_algebra(parser: &mut CssParser<'_, '_>) -> SupportsCondition { + let mut operands: Vec = Vec::new(); + let mut operator: Option<&'static str> = None; + let mut negate = false; + + loop { + match parser.next_including_whitespace() { + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + Ok(Token::Ident(name)) => { + let name = name.to_ascii_lowercase(); + match name.as_str() { + "not" => negate = true, + "and" | "or" => { + let op: &'static str = if name == "and" { "and" } else { "or" }; + match operator { + None => operator = Some(op), + Some(existing) if existing == op => {} + Some(_) => return SupportsCondition::Unknown, + } + } + _ => return SupportsCondition::Unknown, + } + } + Ok(Token::ParenthesisBlock) => { + operands.push(parse_supports_in_parens(parser)); + } + Ok(Token::Function(fn_name)) => { + let lower = fn_name.to_ascii_lowercase(); + match lower.as_str() { + "selector" => { + let inner_text = capture_nested_text(parser); + let supported = + validate_and_specificity(inner_text.trim()).is_ok(); + operands.push(SupportsCondition::Selector { + text: inner_text, + supported, + }); + } + _ => return SupportsCondition::Unknown, + } + } + Ok(_) => return SupportsCondition::Unknown, + Err(_) => break, + } + } + + let combined = match operands.len() { + 0 => SupportsCondition::And(vec![]), + 1 => operands.into_iter().next().unwrap(), + _ => match operator { + Some("or") => SupportsCondition::Or(operands), + _ => SupportsCondition::And(operands), + }, + }; + + if negate { + SupportsCondition::Not(Box::new(combined)) + } else { + combined + } +} + +/// One `(...)` supports group: either a declaration test or nested algebra. +fn parse_supports_in_parens(parser: &mut CssParser<'_, '_>) -> SupportsCondition { + let text = capture_nested_text(parser); + let trimmed = text.trim(); + + // Declaration form: `name: value`. + let mut input = ParserInput::new(trimmed); + let mut inner = CssParser::new(&mut input); + let is_declaration = inner + .try_parse(|parser| -> Result<(), cssparser::ParseError<'_, ()>> { + match parser.next() { + Ok(Token::Ident(_)) => {} + Ok(_) => return Err(custom_err(parser)), + Err(_) => return Err(custom_err(parser)), + } + match parser.next() { + Ok(Token::Colon) => {} + Ok(_) => return Err(custom_err(parser)), + Err(_) => return Err(custom_err(parser)), + } + Ok(()) + }) + .is_ok(); + + if is_declaration { + if let Some((name, value)) = trimmed.split_once(':') { + let value = value.trim().to_string(); + let name = name.trim().to_ascii_lowercase(); + let supported = is_known_property(&name) || name.starts_with("--"); + return SupportsCondition::Declaration { + name, + value, + supported, + }; + } + } + + // Nested algebra. + let mut input = ParserInput::new(trimmed); + let mut inner = CssParser::new(&mut input); + parse_supports_algebra(&mut inner) +} + +// --------------------------------------------------------------------------- +// Features +// --------------------------------------------------------------------------- + +/// Try to read one captured `(...)` group as a media/container size feature. +fn parse_feature_text(text: &str) -> Option { + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + + parser.try_parse(parse_feature_block).ok() +} + +fn parse_feature_block<'i, 'tt>( + parser: &mut CssParser<'i, 'tt>, +) -> Result> { + let pieces = collect_feature_pieces(parser)?; + build_feature(pieces).map_err(|()| custom_err(parser)) +} + +#[derive(Debug, Clone)] +enum Piece { + Name(String), + Op(Compare), + Colon, + Value(FeatureValue), +} + +fn collect_feature_pieces<'i, 'tt>( + parser: &mut CssParser<'i, 'tt>, +) -> Result, cssparser::ParseError<'i, ()>> { + let mut pieces: Vec = Vec::new(); + let mut name_seen = false; + + // The captured group text is the inner content: read to the end. + loop { + match parser.next_including_whitespace() { + Ok(Token::Comment(_) | Token::WhiteSpace(_)) => {} + Ok(Token::Ident(name)) => { + // The feature name comes first; later identifiers are + // discrete values (`(prefers-color-scheme: dark)`). + if name_seen { + pieces.push(Piece::Value(FeatureValue::Ident(name.to_ascii_lowercase()))); + } else { + pieces.push(Piece::Name(name.to_string())); + name_seen = true; + } + } + Ok(Token::Delim(op @ ('<' | '>' | '='))) => { + let mut cmp = match op { + '<' => Compare::LessThan, + '>' => Compare::GreaterThan, + _ => Compare::Equal, + }; + // Optional `=`. + if let Ok(Token::Delim('=')) = parser.next_including_whitespace() { + if cmp != Compare::Equal { + cmp = match cmp { + Compare::LessThan => Compare::LessThanEqual, + Compare::GreaterThan => Compare::GreaterThanEqual, + _ => cmp, + }; + } + } + pieces.push(Piece::Op(cmp)); + } + Ok(Token::Colon) => pieces.push(Piece::Colon), + Ok( + token @ (Token::Number { .. } | Token::Percentage { .. } | Token::Dimension { .. }), + ) => { + pieces.push(Piece::Value(media_value(token))); + } + Ok(_) => return Err(custom_err(parser)), + Err(_) => break, + } + } + + Ok(pieces) +} + +/// Strictly validate the piece sequence into the IR feature shape. +fn build_feature(pieces: Vec) -> Result { + let names: Vec = pieces + .iter() + .enumerate() + .filter(|(_, p)| matches!(p, Piece::Name(_))) + .map(|(i, _)| i) + .collect(); + let ops: Vec = pieces + .iter() + .enumerate() + .filter(|(_, p)| matches!(p, Piece::Op(_))) + .map(|(i, _)| i) + .collect(); + + match (names.len(), ops.len()) { + // Boolean presence test: `(hover)`. + (1, 0) if pieces.len() == 1 => Ok(Feature { + name: canonical_name(&pieces, names[0]), + kind: FeatureKind::Boolean, + }), + // Plain with colon: `(min-width: 24em)`, `(prefers-color-scheme: dark)`, + // `(aspect-ratio: 16/9)`. + (1, 0) if pieces.len() >= 3 && matches!(&pieces[1], Piece::Colon) => { + let value = take_value(&pieces[2..]).ok_or(())?; + normalize(Feature { + name: canonical_name(&pieces, names[0]), + kind: FeatureKind::Plain { value }, + }) + } + // Range with the feature on the left: `(width > 400px)`. + (1, 1) if names[0] == 0 && ops[0] == 1 && pieces.len() == 3 => { + let Piece::Op(cmp) = pieces[ops[0]].clone() else { + return Err(()); + }; + let value = take_value(&pieces[2..]).ok_or(())?; + normalize(Feature { + name: canonical_name(&pieces, names[0]), + kind: FeatureKind::Range { cmp, value }, + }) + } + // Range with the feature on the right: `(400px < width)`. + (1, 1) if ops[0] == 1 && pieces.len() == 3 => { + let Piece::Op(cmp) = pieces[ops[0]].clone() else { + return Err(()); + }; + let value = take_value(&pieces[..1]).ok_or(())?; + normalize(Feature { + name: canonical_name(&pieces, names[0]), + kind: FeatureKind::Range { + cmp: mirror(cmp), + value, + }, + }) + } + // Interval: `(400px < width < 800px)`. Comparisons stay as-written; + // the runtime evaluates `start op dimension`, then `dimension op end`. + (1, 2) if ops[0] == 1 && names[0] == 2 && ops[1] == 3 && pieces.len() == 5 => { + let (Piece::Op(start_cmp), Piece::Op(end_cmp)) = + (pieces[ops[0]].clone(), pieces[ops[1]].clone()) + else { + return Err(()); + }; + let start = take_value(&pieces[..1]).ok_or(())?; + let end = take_value(&pieces[4..]).ok_or(())?; + Ok(Feature { + name: canonical_name(&pieces, names[0]), + kind: FeatureKind::Interval { + start, + start_cmp, + end, + end_cmp, + }, + }) + } + _ => Err(()), + } +} + +/// Consume one value (with an optional ratio slash) from the pieces. +fn take_value(pieces: &[Piece]) -> Option { + let mut iter = pieces.iter(); + let first = match iter.next()? { + Piece::Value(v) => v.clone(), + _ => return None, + }; + + match iter.next() { + None => Some(first), + Some(Piece::Value(second)) => ratio_of(first, second.clone()), + Some(_) => None, + } +} + +fn ratio_of(first: FeatureValue, second: FeatureValue) -> Option { + let numerator = match first { + FeatureValue::Integer(a) => a as f32, + FeatureValue::Number(a) => a, + _ => return None, + }; + let denominator = match second { + FeatureValue::Integer(b) => b as f32, + FeatureValue::Number(b) => b, + _ => return None, + }; + Some(FeatureValue::Ratio(numerator, denominator)) +} + +fn canonical_name(pieces: &[Piece], index: usize) -> String { + match &pieces[index] { + Piece::Name(name) => name.to_ascii_lowercase(), + _ => String::new(), + } +} + +/// Legacy `min-*`/`max-*` names become equivalent range shapes. +fn normalize(feature: Feature) -> Result { + if let FeatureKind::Plain { value } = &feature.kind { + if let Some(base) = feature.name.strip_prefix("min-") { + return Ok(Feature { + name: base.to_string(), + kind: FeatureKind::Range { + cmp: Compare::GreaterThanEqual, + value: value.clone(), + }, + }); + } + if let Some(base) = feature.name.strip_prefix("max-") { + return Ok(Feature { + name: base.to_string(), + kind: FeatureKind::Range { + cmp: Compare::LessThanEqual, + value: value.clone(), + }, + }); + } + } + Ok(feature) +} + +fn mirror(cmp: Compare) -> Compare { + match cmp { + Compare::LessThan => Compare::GreaterThan, + Compare::LessThanEqual => Compare::GreaterThanEqual, + Compare::GreaterThan => Compare::LessThan, + Compare::GreaterThanEqual => Compare::LessThanEqual, + Compare::Equal => Compare::Equal, + } +} + +/// Convert a value token into the IR feature value. +fn media_value(token: &Token<'_>) -> FeatureValue { + match token { + Token::Number { + value, int_value, .. + } => match int_value { + Some(int) => FeatureValue::Integer(*int), + None => FeatureValue::Number(*value), + }, + Token::Percentage { .. } => FeatureValue::Unknown, + Token::Dimension { value, unit, .. } => { + let unit_lower = unit.to_ascii_lowercase(); + match unit_lower.as_str() { + "px" => FeatureValue::Px(*value), + "dpi" | "dpcm" | "dppx" | "x" => { + let v = *value; + FeatureValue::Dppx(match unit_lower.as_str() { + "dpi" => v / 96.0, + "dpcm" => v * 2.54 / 96.0, + _ => v, + }) + } + other => FeatureValue::RelativeLength { + value: *value, + unit: other.to_string(), + }, + } + } + Token::Ident(ident) => FeatureValue::Ident(ident.to_ascii_lowercase()), + _ => FeatureValue::Unknown, + } +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Consume the current nested block and return its text, recursing into +/// nested blocks so nothing is lost to the block-skipping tokenizer. +fn capture_nested_text(parser: &mut CssParser<'_, '_>) -> String { + let mut out = String::new(); + let _ = parser.parse_nested_block(|parser| -> Result<(), cssparser::ParseError<'_, ()>> { + capture_tokens(parser, &mut out); + Ok(()) + }); + out +} + +fn capture_tokens(parser: &mut CssParser<'_, '_>, out: &mut String) { + loop { + match parser.next_including_whitespace() { + Ok(Token::Comment(_)) => {} + Ok(Token::WhiteSpace(_)) => { + if !out.is_empty() { + out.push(' '); + } + } + Ok(Token::Function(name)) => { + out.push_str(name); + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + capture_tokens(parser, out); + Ok(()) + }, + ); + out.push(')'); + } + Ok(Token::ParenthesisBlock) => { + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + capture_tokens(parser, out); + Ok(()) + }, + ); + out.push(')'); + } + Ok(Token::SquareBracketBlock) => { + out.push('['); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + capture_tokens(parser, out); + Ok(()) + }, + ); + out.push(']'); + } + Ok(Token::CurlyBracketBlock) => { + out.push('{'); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + capture_tokens(parser, out); + Ok(()) + }, + ); + out.push('}'); + } + Ok(token) => write_token(out, &token), + Err(_) => break, + } + } +} + +fn consume_nested(parser: &mut CssParser<'_, '_>) { + let _ = parser + .parse_nested_block(|_parser| -> Result<(), cssparser::ParseError<'_, ()>> { Ok(()) }); +} + +fn and_all(conditions: Vec) -> MediaCondition { + match conditions.len() { + 0 => MediaCondition::And(vec![]), + 1 => conditions.into_iter().next().unwrap(), + _ => MediaCondition::And(conditions), + } +} + +fn custom_err<'i>(parser: &CssParser<'i, '_>) -> cssparser::ParseError<'i, ()> { + cssparser::ParseError { + kind: cssparser::ParseErrorKind::Custom(()), + location: parser.current_source_location(), + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn parses_plain_feature() { + let c = parse_media_prelude("(min-width: 24em)"); + let MediaCondition::Feature(f) = c else { + panic!("expected feature, got {c:?}"); + }; + assert_eq!(f.name, "width"); + } + + #[test] + fn parses_not_hover() { + let c = parse_media_prelude("screen and (not (hover))"); + let MediaCondition::Not(inner) = c else { + panic!("expected a negated condition, got {c:?}"); + }; + // `(hover)` is a single feature; the group collapses to it. + assert!(matches!(*inner, MediaCondition::Feature(_))); + } +} diff --git a/experiments/css/crates/css-compiler/src/expand.rs b/experiments/css/crates/css-compiler/src/expand.rs new file mode 100644 index 0000000..617f7f7 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/expand.rs @@ -0,0 +1,338 @@ +//! Nesting expansion and selector normalization. +//! +//! Style-rule preludes arrive from the shim as raw source text. The compiler +//! tokenizes them with `cssparser`, rewrites every `&` (nesting selector) +//! into the parent selector — a single parent inlines directly +//! (browser-canonical, keeps specificity exact), a parent list wraps in +//! `:is()` — and re-serializes with canonical whitespace: combinators lose +//! their surrounding spaces, descendant relationships keep exactly one space +//! when the source had one, and `nth-*` arguments keep only the `of` clause +//! spacing. + +use bombshell_css_core::tokens::write_token; +use cssparser::{Parser as CssParser, ParserInput, Token}; + +/// Expand a raw selector prelude against the enclosing parent selectors. +/// +/// Every `&` token (including inside functional arguments such as `:is(&, .b)` +/// and `:has(&)`) is replaced by the parent selectors. A nested selector +/// without an explicit `&` gets an implicit descendant prefix. +/// +/// `parents` are already-expanded parent selector texts (one complex selector +/// each). With no parents (top level) the text is only normalized. +pub(crate) fn expand_selector_list(text: &str, parents: &[String]) -> String { + let mut s = Serializer { + parents, + out: String::with_capacity(text.len() + 16), + segments: Vec::new(), + depth: 0, + bracket_depth: 0, + closed: false, + gap: false, + first: true, + saw_nesting: false, + after_of: false, + }; + + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + + loop { + match parser.next_including_whitespace_and_comments() { + Ok(token) => match token { + Token::Comment(_) => {} + Token::WhiteSpace(_) => s.gap = true, + Token::Comma => s.comma(), + Token::Delim('&') => s.substitute(), + Token::Delim('*') => s.universal(), + Token::Delim(d @ ('>' | '+' | '~')) => s.combinator(*d), + Token::Delim(d @ ('.' | '#')) => s.attach(*d), + Token::Delim(d) => s.other_delim(*d), + Token::Colon => s.colon(), + Token::Ident(_) | Token::Hash(_) => s.simple(token), + Token::Function(name) => { + s.space(); + s.out.push_str(name); + s.out.push('('); + s.enter_block(false, &mut parser); + s.out.push(')'); + s.closed = true; + s.gap = false; + } + Token::ParenthesisBlock => { + s.space(); + s.out.push('('); + s.enter_block(false, &mut parser); + s.out.push(')'); + s.closed = true; + s.gap = false; + } + Token::SquareBracketBlock => { + s.space(); + s.out.push('['); + s.enter_block(true, &mut parser); + s.out.push(']'); + s.closed = true; + s.gap = false; + } + other => s.other(other), + }, + Err(_) => break, + } + } + + s.finish_segment(); + + let joined = if s.segments.len() == 1 { + s.segments.pop().unwrap_or_default() + } else { + s.segments.join(",") + }; + + canonicalize_nth(&joined) +} + +fn substitution_text(parents: &[String]) -> String { + if parents.len() == 1 { + parents[0].clone() + } else { + { + let mut out = String::from(":is("); + for (i, parent) in parents.iter().enumerate() { + if i > 0 { + out.push_str(", "); + } + out.push_str(parent); + } + out.push(')'); + out + } + } +} + +struct Serializer<'a> { + parents: &'a [String], + out: String, + segments: Vec, + depth: usize, + bracket_depth: usize, + closed: bool, + gap: bool, + first: bool, + saw_nesting: bool, + after_of: bool, +} + +impl<'a> Serializer<'a> { + fn comma(&mut self) { + self.finish_segment(); + self.closed = false; + self.gap = false; + self.first = true; + self.saw_nesting = false; + } + + fn universal(&mut self) { + self.space(); + self.out.push('*'); + self.closed = true; + self.gap = false; + self.first = false; + } + + fn combinator(&mut self, d: char) { + self.out.push(d); + self.closed = false; + self.gap = false; + self.first = false; + } + + fn attach(&mut self, d: char) { + self.space(); + self.out.push(d); + self.closed = false; + self.gap = false; + self.first = false; + } + + fn other_delim(&mut self, d: char) { + self.space(); + self.out.push(d); + self.closed = true; + self.gap = false; + self.first = false; + } + + fn colon(&mut self) { + self.space(); + self.out.push(':'); + self.closed = false; + self.gap = false; + self.first = false; + } + + fn simple<'i>(&mut self, token: &Token<'i>) { + self.space(); + write_token(&mut self.out, token); + self.closed = true; + self.gap = false; + self.first = false; + } + + fn other<'i>(&mut self, token: &Token<'i>) { + self.space(); + write_token(&mut self.out, token); + self.closed = true; + self.gap = false; + self.first = false; + } + + fn enter_block(&mut self, bracket: bool, parser: &mut CssParser<'_, '_>) { + if bracket { + self.bracket_depth += 1; + } else { + self.depth += 1; + } + self.gap = false; + self.after_of = false; + self.first = false; + self.descend(parser); + if bracket { + self.bracket_depth -= 1; + } else { + self.depth -= 1; + } + } + + /// Emit one space when source whitespace separated a completed compound + /// from a new one (a descendant relationship). + fn space(&mut self) { + if self.depth == 0 && self.bracket_depth == 0 && self.gap && !self.first && self.closed { + self.out.push(' '); + } + self.gap = false; + } + + fn substitute(&mut self) { + if self.depth == 0 && self.bracket_depth == 0 { + self.space(); + } else if self.gap && self.after_of { + self.out.push(' '); + } + self.gap = false; + self.after_of = false; + self.out.push_str(&substitution_text(self.parents)); + self.closed = true; + self.gap = false; + self.first = false; + self.saw_nesting = true; + } + + /// Serialize the tokens inside a nested block (function arguments, + /// attribute blocks), replacing `&`. Argument blocks keep only the + /// spacing around the An+B `of` clause; attribute blocks keep single + /// spaces verbatim. + fn descend(&mut self, parser: &mut CssParser<'_, '_>) { + let _ = parser.parse_nested_block(|parser| -> Result<(), cssparser::ParseError<'_, ()>> { + loop { + match parser.next_including_whitespace_and_comments() { + Ok(token) => match token { + Token::Comment(_) => {} + Token::WhiteSpace(_) => { + if self.bracket_depth > 0 && !self.out.ends_with(' ') { + self.out.push(' '); + } else { + self.gap = true; + } + } + Token::Delim('&') => { + self.substitute(); + } + token => { + // Inside argument blocks whitespace is + // insignificant, except around the An+B `of` + // keyword. + let is_of = matches!(token, Token::Ident(name) if name.eq_ignore_ascii_case("of")); + if self.gap && (self.after_of || is_of) { + self.out.push(' '); + } + self.gap = false; + write_token(&mut self.out, token); + self.after_of = is_of; + } + }, + Err(_) => break, + } + } + Ok(()) + }); + } + + fn finish_segment(&mut self) { + let segment = std::mem::take(&mut self.out); + let segment = segment.trim(); + + if !self.saw_nesting && !self.parents.is_empty() { + self.segments + .push({ + let mut out = substitution_text(self.parents); + out.push(' '); + out.push_str(&segment); + out + }); + } else { + self.segments.push(segment.to_string()); + } + } +} + +/// `2n+1` → `odd`, `2n` → `even` inside `nth-*` arguments. +fn canonicalize_nth(text: &str) -> String { + let mut out = String::with_capacity(text.len()); + let mut rest = text; + + while let Some(index) = rest.find("nth-") { + let (before, after) = rest.split_at(index); + out.push_str(before); + rest = after; + + let Some(open) = rest.find('(') else { + out.push_str(rest); + return out; + }; + out.push_str(&rest[..=open]); + rest = &rest[open + 1..]; + + // Canonicalize the leading An+B term of the argument. + if let Some(tail) = rest.strip_prefix("2n+1") { + out.push_str("odd"); + rest = tail; + } else if let Some(tail) = rest.strip_prefix("2n") { + if matches!(tail.as_bytes().first(), Some(b')' | b',' | b' ')) { + out.push_str("even"); + rest = tail; + } + } + + // Copy until the argument ends (or the next `nth-` may start). + let mut consumed = 0usize; + let mut depth = 0usize; + for (i, c) in rest.char_indices() { + match c { + '(' => depth += 1, + ')' if depth == 0 => { + consumed = i; + break; + } + ')' => depth -= 1, + _ => {} + } + consumed = i + c.len_utf8(); + } + out.push_str(&rest[..consumed]); + rest = &rest[consumed..]; + } + + out.push_str(rest); + out +} diff --git a/experiments/css/crates/css-compiler/src/ffi.rs b/experiments/css/crates/css-compiler/src/ffi.rs new file mode 100644 index 0000000..0f79495 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/ffi.rs @@ -0,0 +1,83 @@ +//! FFI boundary to the lexbor shim (`c/shim.c`). + +use std::os::raw::c_int; +use std::sync::{Mutex, MutexGuard, OnceLock}; + +/// Event kinds emitted by the shim. Spans are byte offsets into the original +/// stylesheet text. +pub const STYLE_BEGIN: u8 = 0; +pub const STYLE_END: u8 = 1; +pub const AT_BEGIN: u8 = 2; +pub const AT_PRELUDE: u8 = 3; +pub const AT_END: u8 = 4; +pub const DECL: u8 = 5; + +pub const FLAG_IMPORTANT: u8 = 0x01; +pub const FLAG_FAILED: u8 = 0x02; + +/// One shim event. `a`/`b` are `[start, end)` byte ranges into the source. +#[repr(C)] +#[derive(Clone, Copy)] +pub struct LbxEvent { + pub kind: u8, + pub flags: u8, + pub a0: u32, + pub a1: u32, + pub b0: u32, + pub b1: u32, +} + +impl LbxEvent { + pub fn span_a<'t>(&self, text: &'t str) -> &'t str { + &text[self.a0 as usize..self.a1 as usize] + } + + pub fn span_b<'t>(&self, text: &'t str) -> &'t str { + &text[self.b0 as usize..self.b1 as usize] + } +} + +unsafe extern "C" { + /// Parse a stylesheet into the event stream. Returns 0 on success. The + /// event array is allocated by the shim and must be released with + /// `lbx_free_events`. + fn lbx_parse( + css: *const u8, + css_len: usize, + out_events: *mut *mut LbxEvent, + out_len: *mut usize, + ) -> c_int; + + fn lbx_free_events(events: *mut LbxEvent, len: usize); +} + +/// The shim keeps one global context per process; guard the C boundary. +fn shim_lock() -> MutexGuard<'static, ()> { + static LOCK: OnceLock> = OnceLock::new(); + let _ = LOCK.get_or_init(|| Mutex::new(())); + LOCK.get() + .unwrap() + .lock() + .unwrap_or_else(|poisoned| poisoned.into_inner()) +} + +/// Parse a stylesheet into the shim event stream. +pub(crate) fn parse_events(css: &str) -> Option> { + let _guard = shim_lock(); + + let bytes = css.as_bytes(); + let mut events: *mut LbxEvent = std::ptr::null_mut(); + let mut len: usize = 0; + + let status = unsafe { lbx_parse(bytes.as_ptr(), bytes.len(), &mut events, &mut len) }; + + if status != 0 { + return None; + } + + let slice = unsafe { std::slice::from_raw_parts(events, len) }; + let owned = slice.to_vec(); + unsafe { lbx_free_events(events, len) }; + + Some(owned) +} diff --git a/experiments/css/crates/css-compiler/src/known_properties.rs b/experiments/css/crates/css-compiler/src/known_properties.rs new file mode 100644 index 0000000..75dc756 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/known_properties.rs @@ -0,0 +1,43 @@ +//! Property-name knowledge for `@supports` pre-evaluation. +//! +//! lightningcss's typed parser decided `@supports (prop: value)` leaves by +//! whether it recognized the property. This list carries the same job: it is +//! a curated set of properties the runtime understands or that are broadly +//! implemented in modern engines. Unknown names report unsupported, matching +//! browser behavior. + +/// Whether `@supports (name: value)` should report supported at compile time. +pub(crate) fn is_known_property(name: &str) -> bool { + // Packed storage: one NUL-joined blob plus u16 entry offsets, searched + // like the sorted pointer-array table it replaced (same compares, + // smaller footprint in linear memory). + OFFSETS + .binary_search_by(|&off| { + let rest = &BLOB[off as usize..]; + let end = rest.find('\0').unwrap_or(rest.len()); + rest[..end].cmp(name) + }) + .is_ok() +} + +const BLOB: &str = "align-content\0align-items\0align-self\0all\0appearance\0aspect-ratio\0backdrop-filter\0background\0background-attachment\0background-blend-mode\0background-clip\0background-color\0background-image\0background-origin\0background-position\0background-repeat\0background-size\0block-size\0border\0border-block\0border-block-color\0border-block-end\0border-block-end-color\0border-block-end-style\0border-block-end-width\0border-block-start\0border-block-start-color\0border-block-start-style\0border-block-start-width\0border-block-style\0border-block-width\0border-bottom\0border-bottom-color\0border-bottom-left-radius\0border-bottom-right-radius\0border-bottom-style\0border-bottom-width\0border-collapse\0border-color\0border-end-end-radius\0border-end-start-radius\0border-image\0border-image-outset\0border-image-repeat\0border-image-slice\0border-image-source\0border-image-width\0border-inline\0border-inline-color\0border-inline-end\0border-inline-end-color\0border-inline-end-style\0border-inline-end-width\0border-inline-start\0border-inline-start-color\0border-inline-start-style\0border-inline-start-width\0border-inline-style\0border-inline-width\0border-left\0border-left-color\0border-left-style\0border-left-width\0border-radius\0border-right\0border-right-color\0border-right-style\0border-right-width\0border-spacing\0border-start-end-radius\0border-start-start-radius\0border-style\0border-top\0border-top-color\0border-top-left-radius\0border-top-right-radius\0border-top-style\0border-top-width\0border-width\0bottom\0box-decoration-break\0box-shadow\0box-sizing\0break-after\0break-before\0break-inside\0caption-side\0caret-color\0clear\0clip-path\0color\0color-interpolation-method\0color-scheme\0column-count\0column-fill\0column-gap\0column-rule\0column-rule-color\0column-rule-style\0column-rule-width\0column-span\0column-width\0columns\0contain\0container\0container-name\0container-position\0container-type\0content\0cursor\0direction\0display\0empty-cells\0filter\0flex\0flex-basis\0flex-direction\0flex-flow\0flex-grow\0flex-shrink\0flex-wrap\0float\0font\0font-family\0font-feature-settings\0font-kerning\0font-language-override\0font-optical-sizing\0font-size\0font-size-adjust\0font-stretch\0font-style\0font-synthesis\0font-variant\0font-variant-caps\0font-variant-east-asian\0font-variant-ligatures\0font-variant-numeric\0font-variant-position\0font-variation-settings\0font-weight\0forced-color-adjust\0gap\0grid\0grid-area\0grid-auto-columns\0grid-auto-flow\0grid-auto-rows\0grid-column\0grid-column-end\0grid-column-gap\0grid-column-start\0grid-gap\0grid-row\0grid-row-end\0grid-row-gap\0grid-row-start\0grid-template\0grid-template-areas\0grid-template-columns\0grid-template-rows\0height\0hyphens\0image-orientation\0image-rendering\0inline-size\0inset\0inset-block\0inset-block-end\0inset-block-start\0inset-inline\0inset-inline-end\0inset-inline-start\0isolation\0justify-content\0justify-items\0justify-self\0left\0letter-spacing\0line-break\0line-height\0list-style\0list-style-image\0list-style-position\0list-style-type\0margin\0margin-block\0margin-block-end\0margin-block-start\0margin-bottom\0margin-inline\0margin-inline-end\0margin-inline-start\0margin-left\0margin-right\0margin-top\0marker-end\0marker-mid\0marker-start\0mask\0mask-border\0mask-border-mode\0mask-border-outset\0mask-border-repeat\0mask-border-slice\0mask-border-source\0mask-border-width\0mask-clip\0mask-composite\0mask-image\0mask-mode\0mask-origin\0mask-position\0mask-repeat\0mask-size\0max-block-size\0max-height\0max-inline-size\0max-width\0min-block-size\0min-height\0min-inline-size\0min-width\0mix-blend-mode\0object-fit\0object-position\0offset\0offset-anchor\0offset-distance\0offset-path\0offset-rotate\0opacity\0order\0outline\0outline-color\0outline-offset\0outline-style\0outline-width\0overflow\0overflow-anchor\0overflow-block\0overflow-clip-margin\0overflow-inline\0overflow-wrap\0overflow-x\0overflow-y\0overscroll-behavior\0overscroll-behavior-block\0overscroll-behavior-inline\0overscroll-behavior-x\0overscroll-behavior-y\0padding\0padding-block\0padding-block-end\0padding-block-start\0padding-bottom\0padding-inline\0padding-inline-end\0padding-inline-start\0padding-left\0padding-right\0padding-top\0page-break-after\0page-break-before\0page-break-inside\0paint-order\0perspective\0perspective-origin\0place-content\0place-items\0place-self\0pointer-events\0position\0print-color-adjust\0quotes\0resize\0right\0rotate\0row-gap\0scale\0scroll-behavior\0scroll-margin\0scroll-margin-block\0scroll-margin-block-end\0scroll-margin-block-start\0scroll-margin-bottom\0scroll-margin-inline\0scroll-margin-inline-end\0scroll-margin-inline-start\0scroll-margin-left\0scroll-margin-right\0scroll-margin-top\0scroll-padding\0scroll-padding-block\0scroll-padding-block-end\0scroll-padding-block-start\0scroll-padding-bottom\0scroll-padding-inline\0scroll-padding-inline-end\0scroll-padding-inline-start\0scroll-padding-left\0scroll-padding-right\0scroll-padding-top\0scroll-snap-align\0scroll-snap-stop\0scroll-snap-type\0shape-image-threshold\0shape-margin\0shape-outside\0table-layout\0tab-size\0text-align\0text-align-all\0text-align-last\0text-combine-upright\0text-decoration\0text-decoration-color\0text-decoration-line\0text-decoration-skip-ink\0text-decoration-style\0text-decoration-thickness\0text-emphasis\0text-emphasis-color\0text-emphasis-position\0text-emphasis-style\0text-indent\0text-justify\0text-orientation\0text-overflow\0text-rendering\0text-shadow\0text-size-adjust\0text-transform\0text-underline-offset\0text-underline-position\0top\0touch-action\0transform\0transform-box\0transform-origin\0transform-style\0transition\0transition-behavior\0transition-delay\0transition-duration\0transition-property\0transition-timing-function\0translate\0unicode-bidi\0user-select\0vertical-align\0visibility\0white-space\0widows\0width\0will-change\0word-break\0word-spacing\0word-wrap\0writing-mode\0z-index\0"; + +/// Offsets of each property name into [`BLOB`], sorted; each entry runs to +/// the next offset (or the trailing NUL). +const OFFSETS: &[u16] = &[0, 14, 26, 37, 41, 52, 65, 81, 92, 114, 136, 152, 169, 186, 204, 224, 242, 258, 269, 276, 289, 308, 325, 348, 371, 394, 413, 438, 463, 488, 507, 526, 540, 560, 586, 613, 633, 653, 669, 682, 704, 728, 741, 761, 781, 800, 820, 839, 853, 873, 891, 915, 939, 963, 983, 1009, 1035, 1061, 1081, 1101, 1113, 1131, 1149, 1167, 1181, 1194, 1213, 1232, 1251, 1266, 1290, 1316, 1329, 1340, 1357, 1380, 1404, 1421, 1438, 1451, 1458, 1479, 1490, 1501, 1513, 1526, 1539, 1552, 1564, 1570, 1580, 1586, 1613, 1626, 1639, 1651, 1662, 1674, 1692, 1710, 1728, 1740, 1753, 1761, 1769, 1779, 1794, 1813, 1828, 1836, 1843, 1853, 1861, 1873, 1880, 1885, 1896, 1911, 1921, 1931, 1943, 1953, 1959, 1964, 1976, 1998, 2011, 2034, 2054, 2064, 2081, 2094, 2105, 2120, 2133, 2151, 2175, 2198, 2219, 2241, 2265, 2277, 2297, 2301, 2306, 2316, 2334, 2349, 2364, 2376, 2392, 2408, 2426, 2435, 2444, 2457, 2470, 2485, 2499, 2519, 2541, 2560, 2567, 2575, 2593, 2609, 2621, 2627, 2639, 2655, 2673, 2686, 2703, 2722, 2732, 2748, 2762, 2775, 2780, 2795, 2806, 2818, 2829, 2846, 2866, 2882, 2889, 2902, 2919, 2938, 2952, 2966, 2984, 3004, 3016, 3029, 3040, 3051, 3062, 3075, 3080, 3092, 3109, 3128, 3147, 3165, 3184, 3202, 3212, 3227, 3238, 3248, 3260, 3274, 3286, 3296, 3311, 3322, 3338, 3348, 3363, 3374, 3390, 3400, 3415, 3426, 3442, 3449, 3463, 3479, 3491, 3505, 3513, 3519, 3527, 3541, 3556, 3570, 3584, 3593, 3609, 3624, 3645, 3661, 3675, 3686, 3697, 3717, 3743, 3770, 3792, 3814, 3822, 3836, 3854, 3874, 3889, 3904, 3923, 3944, 3957, 3971, 3983, 4000, 4018, 4036, 4048, 4060, 4079, 4093, 4105, 4116, 4131, 4140, 4159, 4166, 4173, 4179, 4186, 4194, 4200, 4216, 4230, 4250, 4274, 4300, 4321, 4342, 4367, 4394, 4413, 4433, 4451, 4466, 4487, 4512, 4539, 4561, 4583, 4609, 4637, 4657, 4678, 4697, 4715, 4732, 4749, 4771, 4784, 4798, 4811, 4820, 4831, 4846, 4862, 4883, 4899, 4921, 4942, 4967, 4989, 5015, 5029, 5049, 5072, 5092, 5104, 5117, 5134, 5148, 5163, 5175, 5192, 5207, 5229, 5253, 5257, 5270, 5280, 5294, 5311, 5327, 5338, 5358, 5375, 5395, 5415, 5442, 5452, 5465, 5477, 5492, 5503, 5515, 5522, 5528, 5540, 5551, 5564, 5574, 5587]; + +#[cfg(test)] +mod tests { + use super::is_known_property; + + #[test] + fn table_is_sorted_and_complete() { + assert!(is_known_property("align-content")); + assert!(is_known_property("z-index")); + assert!(is_known_property("width")); + assert!(!is_known_property("align-contentt")); + assert!(!is_known_property("unknown-property")); + assert!(!is_known_property("")); + assert_eq!(super::OFFSETS.len(), 361); + } +} diff --git a/experiments/css/crates/css-compiler/src/lib.rs b/experiments/css/crates/css-compiler/src/lib.rs new file mode 100644 index 0000000..463c0f9 --- /dev/null +++ b/experiments/css/crates/css-compiler/src/lib.rs @@ -0,0 +1,706 @@ +//! Lexbor-backed compiler for the Bombshell CSS pipeline. +//! +//! `compile` parses full modern CSS (Syntax Level 3/4, nesting, media, +//! container, supports, layers) with lexbor's syntax parser via a thin C +//! shim, then performs all semantic work in Rust: nesting expansion against +//! the CSS Nesting spec, typed condition trees, canonicalization, and +//! emission of the versioned [`CompiledStylesheet`] IR consumed by the +//! runtime. Selectors, declaration values, and keyframes cross the boundary +//! as canonical CSS text; conditions cross as typed IR trees. + +mod alloc_shim; +mod canonical; +mod colors; +mod conditions; +mod expand; +mod ffi; +mod known_properties; + +use bombshell_css_core::selectors::validate_and_specificity; +use bombshell_css_core::{ + CompiledRule, CompiledStylesheet, ContainerQuery, Declaration, Diagnostic, IR_VERSION, Origin, +}; +use std::string::String; +use std::vec::Vec; + +/// Append `value` in decimal, without pulling `core::fmt`'s integer +/// formatting machinery into the module. +fn push_u32(out: &mut String, mut value: u32) { + let mut buf = [0u8; 10]; + let mut len = 0; + loop { + buf[len] = b'0' + (value % 10) as u8; + len += 1; + value /= 10; + if value == 0 { + break; + } + } + let bytes = &buf[..len]; + let reversed: Vec = bytes.iter().rev().copied().collect(); + // SAFETY: digits and `/`-free ASCII. + out.push_str(core::str::from_utf8(&reversed).unwrap_or("")); +} + +/// Options for [`compile`]. +#[derive(Debug, Clone)] +pub struct CompileOptions { + /// Keep parsing after errors, reporting diagnostics and preserving the + /// recoverable portion of the stylesheet. + pub error_recovery: bool, + /// Accepted for API compatibility; output is always canonical. + pub minify: bool, +} + +impl Default for CompileOptions { + fn default() -> Self { + CompileOptions { + error_recovery: true, + minify: true, + } + } +} + +/// The result of compiling a stylesheet. +#[derive(Debug, Clone, Default)] +pub struct CompileOutput { + /// The compiled IR, or `None` when compilation failed without recovery. + pub sheet: Option, + /// Errors and warnings collected during compilation. + pub diagnostics: Vec, +} + +/// Parse and compile CSS into the versioned stylesheet IR. +pub fn compile(css: &str, origin: Origin, options: CompileOptions) -> CompileOutput { + let Some(events) = ffi::parse_events(css) else { + return CompileOutput { + sheet: None, + diagnostics: vec![Diagnostic::error("parse", "stylesheet parse failed")], + }; + }; + + let mut walker = Walker { + options, + css, + warnings: Vec::new(), + out: CompiledStylesheet { + version: IR_VERSION, + origin, + rules: Vec::new(), + layer_order: Vec::new(), + keyframes: Vec::new(), + opaque: Vec::new(), + warnings: Vec::new(), + }, + stack: vec![Frame::Root], + next_order: 0, + anonymous_layers: 0, + last_at_name: None, + hard_error: None, + }; + + walker.run(&events); + walker.out.warnings = walker.warnings.clone(); + + if let Some(message) = walker.hard_error { + // Recovery warnings observed before the fatal error still matter to + // the host. + let mut diagnostics = Vec::with_capacity(walker.warnings.len() + 1); + diagnostics.extend(walker.warnings.clone()); + diagnostics.push(Diagnostic::error("parse", message)); + return CompileOutput { + sheet: None, + diagnostics, + }; + } + + // Warnings ride both the sheet (IR round-trip) and the compile output, + // so hosts that never decode the IR still see them. + CompileOutput { + sheet: Some(walker.out), + diagnostics: walker.warnings.clone(), + } +} + +/// Walk frames: the event stream is processed with an explicit stack. +enum Frame { + Root, + /// A style rule (or `@nest` rule) with its expanded selector context. + Style(StyleFrame), + /// A grouping at-rule whose context applies to nested rules. + At(AtFrame), + /// A subtree whose events are ignored (inside `@keyframes`/opaque + /// at-rules, or under a failed rule). + Skipper, +} + +#[derive(Clone)] +struct StyleFrame { + /// Expanded, validated selector text (comma-separated segments). + selector: String, + specificity: u32, + declarations: Vec, + /// The rule already emitted (before nested children walked). + emitted: bool, +} + +#[derive(Clone)] +enum AtFrame { + Media(bombshell_css_core::MediaCondition), + Container(ContainerQuery), + Supports(bombshell_css_core::SupportsCondition), + Layer(Vec), + Keyframes { name: String }, + Opaque, +} + +struct Walker<'t> { + options: CompileOptions, + css: &'t str, + warnings: Vec, + out: CompiledStylesheet, + stack: Vec, + next_order: u32, + anonymous_layers: u32, + last_at_name: Option, + hard_error: Option, +} + +impl<'t> Walker<'t> { + fn run(&mut self, events: &[ffi::LbxEvent]) { + for event in events { + self.event(event); + } + } + + fn event(&mut self, event: &ffi::LbxEvent) { + match event.kind { + ffi::AT_BEGIN => { + self.last_at_name = Some( + event + .span_a(self.css) + .trim() + .trim_start_matches('@') + .to_ascii_lowercase(), + ); + if self.in_keyframes() || self.in_opaque() { + self.stack.push(Frame::Skipper); + } + } + ffi::STYLE_BEGIN => self.style_begin(event), + ffi::STYLE_END => self.style_end(), + ffi::AT_PRELUDE => self.at_prelude(event), + ffi::AT_END => self.at_end(event), + ffi::DECL => self.declaration(event), + _ => {} + } + } + + fn fail(&mut self, message: impl Into) { + if self.hard_error.is_none() { + self.hard_error = Some(message.into()); + } + } + + fn warn(&mut self, code: &str, message: impl Into) { + self.warnings + .push(Diagnostic::warning(code, message.into())); + } + + /// The enclosing style frame's parent segments (for `&` expansion). + fn parent_segments(&self) -> Vec { + for frame in self.stack.iter().rev() { + if let Frame::Style(style) = frame { + return style + .selector + .split(',') + .map(|s| s.trim().to_string()) + .collect(); + } + } + Vec::new() + } + + fn in_keyframes(&self) -> bool { + self.stack + .iter() + .any(|frame| matches!(frame, Frame::At(AtFrame::Keyframes { .. }))) + } + + fn in_opaque(&self) -> bool { + self.stack + .iter() + .any(|frame| matches!(frame, Frame::At(AtFrame::Opaque))) + } + + fn style_begin(&mut self, event: &ffi::LbxEvent) { + self.flush_top_style(); + + if self.in_keyframes() || self.in_opaque() { + self.stack.push(Frame::Skipper); + return; + } + + let prelude = event.span_a(self.css); + let parents = self.parent_segments(); + + if event.flags & ffi::FLAG_FAILED != 0 { + if !self.options.error_recovery { + self.fail("invalid selector list"); + } else { + self.warn("selector", "a style rule has an invalid selector list"); + } + self.stack.push(Frame::Skipper); + return; + } + + if parents.is_empty() && prelude.contains('&') { + self.warn( + "nesting-orphan", + "a top-level selector contains `&` with no parent selector", + ); + } + + let expanded = expand::expand_selector_list(prelude, &parents); + + if let Some(frame) = self.build_style_frame(&expanded) { + self.stack.push(frame); + } else { + self.stack.push(Frame::Skipper); + } + } + + fn build_style_frame(&mut self, expanded: &str) -> Option { + let specificity = match validate_and_specificity(expanded) { + Ok(specificity) => specificity, + Err(()) => { + if !self.options.error_recovery { + self.fail({ + let mut message = String::from("invalid selector list `"); + message.push_str(expanded); + message.push('`'); + message + }); + } else { + self.warn( + "selector", + { + let mut message = String::from( + "a style rule has an invalid selector list `", + ); + message.push_str(expanded); + message.push('`'); + message + }, + ); + } + return None; + } + }; + + Some(Frame::Style(StyleFrame { + selector: expanded.to_string(), + specificity, + declarations: Vec::new(), + emitted: false, + })) + } + + fn style_end(&mut self) { + let Some(frame) = self.stack.pop() else { + return; + }; + + if let Frame::Style(style) = frame { + if !style.emitted { + self.emit_style(style); + } + } + } + + /// Emit the top style frame's rule before nested children walk, keeping + /// source order. Trailing declarations (after nested rules) are emitted + /// as their own rule against the parent selector, per the old + /// NestedDeclarations behavior. + fn flush_top_style(&mut self) { + let Some(Frame::Style(_)) = self.stack.last() else { + return; + }; + + let emitted; + if let Frame::Style(style) = self.stack.last_mut().unwrap() { + if style.declarations.is_empty() || style.emitted { + return; + } + style.emitted = true; + emitted = style.clone(); + } else { + return; + } + + self.emit_style(emitted); + } + + fn emit_style(&mut self, style: StyleFrame) { + if style.declarations.is_empty() { + return; + } + + let order = self.next_order; + self.next_order += 1; + + let (media, containers, supports, layer) = self.context(); + + self.out.rules.push(CompiledRule { + selector: style.selector, + specificity: style.specificity, + layer, + media, + containers, + supports, + declarations: style.declarations, + order, + }); + } + + /// Emit a rule carrying only the given declarations (used for trailing + /// declarations after nested rules; specificity 0 per the old + /// NestedDeclarations behavior). + fn emit_trailing(&mut self, selector: String, declarations: Vec) { + if declarations.is_empty() { + return; + } + + let order = self.next_order; + self.next_order += 1; + + let (media, containers, supports, layer) = self.context(); + + self.out.rules.push(CompiledRule { + selector, + specificity: 0, + layer, + media, + containers, + supports, + declarations, + order, + }); + } + + fn at_prelude(&mut self, event: &ffi::LbxEvent) { + if matches!(self.stack.last(), Some(Frame::Skipper)) { + return; + } + + self.flush_top_style(); + + let failed = event.flags & ffi::FLAG_FAILED != 0; + let raw = event.span_a(self.css).trim(); + // The shim may reconstruct the prelude span from the at-keyword; + // strip a leading `@name` when present. + let prelude = match raw.strip_prefix('@') { + Some(rest) => rest + .split_once(char::is_whitespace) + .map(|(_, rest)| rest.trim()) + .unwrap_or(""), + None => raw, + } + .to_string(); + let name = self.last_at_name.clone().unwrap_or_default(); + + match name.as_str() { + "media" => { + if std::env::var("LBX_DEBUG").is_ok() { + eprintln!("[at-prelude media] failed={failed} prelude={prelude:?}"); + } + let condition = if failed { + self.condition_failure("media"); + bombshell_css_core::MediaCondition::Unknown + } else { + let parsed = conditions::parse_media_prelude(&prelude); + if std::env::var("LBX_DEBUG").is_ok() { + eprintln!("[media-parsed] {parsed:#?}"); + } + parsed + }; + self.stack.push(Frame::At(AtFrame::Media(condition))); + } + "container" => { + if failed { + self.condition_failure("container"); + } + let (name, condition) = conditions::parse_container_prelude(&prelude); + self.stack + .push(Frame::At(AtFrame::Container(ContainerQuery { + name, + condition, + }))); + } + "supports" => { + let condition = if failed { + self.condition_failure("supports"); + bombshell_css_core::SupportsCondition::Unknown + } else { + conditions::parse_supports_prelude(&prelude) + }; + self.stack.push(Frame::At(AtFrame::Supports(condition))); + } + "layer" => { + let mut paths: Vec> = Vec::new(); + if prelude.is_empty() { + self.anonymous_layers += 1; + paths.push(vec![{ + let mut name = String::from("_anonymous-layer-"); + push_u32(&mut name, self.anonymous_layers); + name + }]); + } else { + for name in prelude.split(',') { + let path: Vec = + name.trim().split('.').map(str::to_string).collect(); + paths.push(path); + } + } + for path in &paths { + self.ensure_layer_path(path); + } + let path = paths.first().cloned().unwrap_or_default(); + self.stack.push(Frame::At(AtFrame::Layer(path))); + } + "keyframes" => { + self.stack.push(Frame::At(AtFrame::Keyframes { + name: unquote(&prelude), + })); + } + "nest" => { + let parents = self.parent_segments(); + if parents.is_empty() { + self.warn("nesting-orphan", "@nest rule has no enclosing style rule"); + self.stack.push(Frame::Skipper); + return; + } + let expanded = expand::expand_selector_list(&prelude, &parents); + if let Some(frame) = self.build_style_frame(&expanded) { + self.stack.push(frame); + } else { + self.stack.push(Frame::Skipper); + } + } + "import" => { + self.warn( + "unresolved-import", + "@import is not resolved by this pipeline; the rule is preserved verbatim", + ); + self.stack.push(Frame::At(AtFrame::Opaque)); + } + _ => { + self.stack.push(Frame::At(AtFrame::Opaque)); + } + } + } + + fn condition_failure(&mut self, kind: &str) { + if !self.options.error_recovery { + self.fail({ + let mut message = String::from("invalid "); + message.push_str(kind); + message.push_str(" prelude"); + message + }); + } else { + self.warn(kind, { + let mut message = String::from("an @"); + message.push_str(kind); + message.push_str(" prelude failed to parse"); + message + }); + } + } + + fn at_end(&mut self, event: &ffi::LbxEvent) { + let Some(frame) = self.stack.pop() else { + return; + }; + + match frame { + Frame::At(AtFrame::Opaque) => { + let text = event.span_a(self.css).trim().to_string(); + if !text.is_empty() { + self.out + .opaque + .push(bombshell_css_core::OpaqueRule { text }); + } + } + Frame::At(AtFrame::Keyframes { name }) => { + let body = event.span_a(self.css).trim().to_string(); + self.out + .keyframes + .push(bombshell_css_core::KeyframesRule { name, body }); + } + // Media, container, supports, and layer frames just pop; nested + // events already consumed the context. A `@nest` frame carries a + // style rule and emits like any other. + Frame::Style(style) => self.emit_style(style), + _ => {} + } + } + + fn declaration(&mut self, event: &ffi::LbxEvent) { + // Find the frame that owns this declaration. + let mut target: Option = None; + for (index, frame) in self.stack.iter().enumerate().rev() { + match frame { + Frame::Style(_) => { + target = Some(index); + break; + } + Frame::Skipper | Frame::At(AtFrame::Keyframes { .. } | AtFrame::Opaque) => return, + Frame::At(_) | Frame::Root => continue, + } + } + + let Some(index) = target else { + return; + }; + + let name = event.span_a(self.css).trim().to_string(); + let value = event.span_b(self.css).trim().to_string(); + + if event.flags & ffi::FLAG_FAILED != 0 { + if !self.options.error_recovery { + self.fail({ + let mut message = String::from("invalid declaration `"); + message.push_str(&name); + message.push('`'); + message + }); + } else { + self.warn("declaration", { + let mut message = String::from("invalid value for `"); + message.push_str(&name); + message.push('`'); + message + }); + } + return; + } + + if name.is_empty() { + return; + } + + let important = event.flags & ffi::FLAG_IMPORTANT != 0; + + let value = match canonical::canonicalize(&name, &value) { + Ok(value) => value, + Err(diagnostic) => { + if !self.options.error_recovery { + self.fail({ + let mut message = String::from("invalid declaration `"); + message.push_str(&name); + message.push_str(": "); + message.push_str(&value); + message.push('`'); + message + }); + } else { + self.warnings.push(diagnostic); + } + return; + } + }; + + let (already_emitted, selector) = match &self.stack[index] { + Frame::Style(style) => (style.emitted, style.selector.clone()), + _ => return, + }; + + if already_emitted { + let selector = selector + .split(',') + .map(|s| s.trim().to_string()) + .collect::>() + .join(","); + self.emit_trailing( + selector, + vec![Declaration { + name, + value, + important, + }], + ); + return; + } + + let Frame::Style(style) = &mut self.stack[index] else { + return; + }; + + // Canonicalized per rule: each property at most once, last value wins. + match style.declarations.iter_mut().find(|d| d.name == name) { + Some(existing) => { + existing.value = value; + existing.important = important; + } + None => style.declarations.push(Declaration { + name, + value, + important, + }), + } + } + + /// Cascade context carried by the at-rule frames enclosing the rule. + fn context( + &self, + ) -> ( + Vec, + Vec, + Vec, + Option>, + ) { + let mut media = Vec::new(); + let mut containers = Vec::new(); + let mut supports = Vec::new(); + let mut layer = None; + + for frame in &self.stack { + match frame { + Frame::At(AtFrame::Media(condition)) => media.push(condition.clone()), + Frame::At(AtFrame::Container(query)) => containers.push(query.clone()), + Frame::At(AtFrame::Supports(condition)) => supports.push(condition.clone()), + Frame::At(AtFrame::Layer(path)) => { + let mut joined: Vec = layer.clone().unwrap_or_default(); + joined.extend(path.clone()); + layer = Some(joined); + } + _ => {} + } + } + + (media, containers, supports, layer) + } + + fn ensure_layer_path(&mut self, path: &[String]) { + // Register the path and every ancestor prefix in first-appearance order. + for end in 1..=path.len() { + let prefix = &path[..end]; + if !self.out.layer_order.iter().any(|p| p == prefix) { + self.out.layer_order.push(prefix.to_vec()); + } + } + } +} + +fn unquote(text: &str) -> String { + let text = text.trim(); + if text.len() >= 2 + && (text.starts_with('"') && text.ends_with('"') + || text.starts_with('\'') && text.ends_with('\'')) + { + text[1..text.len() - 1].to_string() + } else { + text.to_string() + } +} diff --git a/experiments/css/crates/css-compiler/tests/compiler.rs b/experiments/css/crates/css-compiler/tests/compiler.rs new file mode 100644 index 0000000..90b38c2 --- /dev/null +++ b/experiments/css/crates/css-compiler/tests/compiler.rs @@ -0,0 +1,168 @@ +use bombshell_css_compiler::compile; +use bombshell_css_core::{FeatureKind, FeatureValue, IR_VERSION, Origin, decode_ir, encode_ir}; + +fn compile_ok(css: &str) -> bombshell_css_core::CompiledStylesheet { + let out = compile(css, Origin::Author, Default::default()); + assert!( + out.diagnostics.is_empty(), + "unexpected diagnostics: {:?}", + out.diagnostics + ); + let sheet = out.sheet.expect("sheet should compile"); + assert_eq!(sheet.version, IR_VERSION); + sheet +} + +#[test] +fn compiles_nesting_expansion() { + let sheet = compile_ok( + r" + .card { + color: oklch(70% 0.2 40); + + & > .title { + font-weight: bold; + + &:hover { text-decoration: underline; } + } + } + ", + ); + let selectors: Vec<&str> = sheet.rules.iter().map(|r| r.selector.as_str()).collect(); + assert_eq!( + selectors, + vec![".card", ".card>.title", ".card>.title:hover"] + ); + assert_eq!(sheet.rules[0].declarations[0].name, "color"); + assert_eq!(sheet.rules[0].declarations[0].value, "oklch(70% .2 40)"); +} + +#[test] +fn compiles_conditions_and_layers() { + let sheet = compile_ok( + r" + @layer base; + @layer base.type { .a { color: red } } + @media (min-width: 24em) { + @container panel (inline-size > 45em) { + @supports (color: oklch(70% 0.2 40)) { + .b { color: blue } + } + } + } + ", + ); + assert_eq!(sheet.layer_order, vec![vec!["base"], vec!["base", "type"]]); + assert_eq!(sheet.rules.len(), 2); + assert_eq!( + sheet.rules[0].layer.as_deref(), + Some(["base".to_string(), "type".to_string()].as_slice()) + ); + let rule = &sheet.rules[1]; + assert_eq!(rule.layer, None); + assert_eq!(rule.media.len(), 1); + assert_eq!(rule.containers.len(), 1); + assert_eq!(rule.containers[0].name.as_deref(), Some("panel")); + assert_eq!(rule.supports.len(), 1); + + // min-width: 24em canonicalizes to width >= 384px (16px base em). + let bombshell_css_core::MediaCondition::Feature(feature) = &rule.media[0] else { + panic!("expected media feature"); + }; + assert_eq!(feature.name, "width"); + match &feature.kind { + FeatureKind::Range { + cmp: bombshell_css_core::Compare::GreaterThanEqual, + value: FeatureValue::RelativeLength { value: 24.0, unit }, + } => assert_eq!(unit, "em"), + other => panic!("unexpected feature kind: {other:?}"), + } +} + +#[test] +fn compiles_keyframes_and_preserves_opaque_rules() { + let sheet = compile_ok( + r" + @keyframes pulse { from { opacity: 1 } to { opacity: 0 } } + @font-face { font-family: X; src: url(x.woff2) } + @property --brand { syntax: ''; initial-value: red; inherits: true } + ", + ); + assert_eq!(sheet.keyframes.len(), 1); + assert_eq!(sheet.keyframes[0].name, "pulse"); + assert!(sheet.keyframes[0].body.starts_with("@keyframes pulse")); + assert_eq!(sheet.opaque.len(), 2); + assert!(sheet.opaque[0].text.starts_with("@font-face")); + assert!(sheet.opaque[1].text.starts_with("@property")); +} + +#[test] +fn reports_parse_errors() { + let out = compile( + ".a { color: this is not a color !! }", + Origin::Author, + bombshell_css_compiler::CompileOptions { + error_recovery: false, + ..Default::default() + }, + ); + assert!(out.sheet.is_none()); + assert!(!out.diagnostics.is_empty()); + assert_eq!( + out.diagnostics[0].severity, + bombshell_css_core::Severity::Error + ); +} + +#[test] +fn ir_round_trips_through_compiler() { + let sheet = compile_ok(".a { color: red; &:hover { color: blue } }"); + let bytes = encode_ir(&sheet); + let decoded = decode_ir(&bytes).unwrap(); + assert_eq!(decoded, sheet); + assert_eq!(decoded.rules.len(), 2); + assert_eq!(decoded.rules[1].selector, ".a:hover"); +} + +#[test] +fn preserves_light_dark_for_the_runtime() { + // The compiler no longer folds to the light branch: both branches are + // validated and canonicalized, and resolution happens against the + // environment's color scheme at computed-value time. + let sheet = compile_ok(".card { color: light-dark(white, black) }"); + assert_eq!(sheet.rules[0].declarations[0].value, "light-dark(#fff, #000)"); +} + +#[test] +fn canonicalizes_light_dark_branches_independently() { + // Case-insensitive function name; each branch canonicalizes like a + // standalone color value. + let sheet = compile_ok(".card { border-color: LIGHT-DARK( #ffffff , yellow ) }"); + assert_eq!( + sheet.rules[0].declarations[0].value, + "light-dark(#ffffff, #ff0)" + ); +} + +#[test] +fn rejects_malformed_light_dark() { + for css in [ + ".card { color: light-dark(#fff) }", + ".card { color: light-dark(#fff, #000, #888) }", + ".card { color: light-dark(#fff, nope) }", + ] { + let out = compile(css, Origin::Author, Default::default()); + let sheet = out.sheet.expect("recovered sheet"); + assert!( + out.diagnostics + .iter() + .any(|d| d.message.contains("invalid color value")), + "missing diagnostic for {css}: {:?}", + out.diagnostics + ); + assert!( + sheet.rules.iter().all(|rule| rule.declarations.is_empty()), + "declaration survived for {css}" + ); + } +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/LICENSE b/experiments/css/crates/css-compiler/vendor/lexbor/LICENSE new file mode 100644 index 0000000..8b95d81 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/LICENSE @@ -0,0 +1,223 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +Lexbor SUBCOMPONENTS: + +The Lexbor includes a number of subcomponents with +separate copyright notices and license terms. Your use of the source +code for the these subcomponents is subject to the terms and +conditions of the following licenses. Paths are relative to the lexbor +folder. + +Portions of source/lexbor/core/dtoa.h, source/lexbor/core/dtoa.c, +source/lexbor/core/strtod.h, source/lexbor/core/strtod.c, +source/lexbor/core/diyfp.h, source/lexbor/core/diyfp.c is based on +NGINX NJS project (https://github.com/nginx/njs/) which is +available under BSD 2-clause "Simplified" License. + +BSD-2-Clause license. + +Copyright (C) 2015-2019 NGINX, Inc. +Copyright (C) 2019-2025 F5, Inc. +Copyright (C) 2015-2021 Igor Sysoev +Copyright (C) 2017-2025 Dmitry Volyntsev +Copyright (C) 2019-2022 Alexander Borisov +Copyright (C) 2022-2025 Vadim Zhestikov +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array.c new file mode 100644 index 0000000..ccf3005 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array.c @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/array.h" + + +lexbor_array_t * +lexbor_array_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_array_t)); +} + +lxb_status_t +lexbor_array_init(lexbor_array_t *array, size_t size) +{ + if (array == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (size == 0) { + return LXB_STATUS_ERROR_TOO_SMALL_SIZE; + } + + array->length = 0; + array->size = size; + + array->list = lexbor_malloc(sizeof(void *) * size); + if (array->list == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + return LXB_STATUS_OK; +} + +void +lexbor_array_clean(lexbor_array_t *array) +{ + if (array != NULL) { + array->length = 0; + } +} + +lexbor_array_t * +lexbor_array_destroy(lexbor_array_t *array, bool self_destroy) +{ + if (array == NULL) + return NULL; + + if (array->list) { + array->length = 0; + array->size = 0; + array->list = lexbor_free(array->list); + } + + if (self_destroy) { + return lexbor_free(array); + } + + return array; +} + +void ** +lexbor_array_expand(lexbor_array_t *array, size_t up_to) +{ + void **list; + size_t new_size; + + if (array->length > (SIZE_MAX - up_to)) + return NULL; + + new_size = array->length + up_to; + list = lexbor_realloc(array->list, sizeof(void *) * new_size); + + if (list == NULL) + return NULL; + + array->list = list; + array->size = new_size; + + return list; +} + +lxb_status_t +lexbor_array_push(lexbor_array_t *array, void *value) +{ + if (array->length >= array->size) { + if ((lexbor_array_expand(array, 128) == NULL)) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + array->list[ array->length ] = value; + array->length++; + + return LXB_STATUS_OK; +} + +void * +lexbor_array_pop(lexbor_array_t *array) +{ + if (array->length == 0) { + return NULL; + } + + array->length--; + return array->list[ array->length ]; +} + +lxb_status_t +lexbor_array_insert(lexbor_array_t *array, size_t idx, void *value) +{ + if (idx >= array->length) { + size_t up_to = (idx - array->length) + 1; + + if (idx >= array->size) { + if ((lexbor_array_expand(array, up_to) == NULL)) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + memset(&array->list[array->length], 0, sizeof(void *) * up_to); + + array->list[ idx ] = value; + array->length += up_to; + + return LXB_STATUS_OK; + } + + if (array->length >= array->size) { + if ((lexbor_array_expand(array, 32) == NULL)) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + memmove(&array->list[idx + 1], &array->list[idx], + sizeof(void *) * (array->length - idx)); + + array->list[ idx ] = value; + array->length++; + + return LXB_STATUS_OK; +} + +lxb_status_t +lexbor_array_set(lexbor_array_t *array, size_t idx, void *value) +{ + if (idx >= array->length) { + size_t up_to = (idx - array->length) + 1; + + if (idx >= array->size) { + if ((lexbor_array_expand(array, up_to) == NULL)) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + memset(&array->list[array->length], 0, sizeof(void *) * up_to); + + array->length += up_to; + } + + array->list[idx] = value; + + return LXB_STATUS_OK; +} + +void +lexbor_array_delete(lexbor_array_t *array, size_t begin, size_t length) +{ + if (begin >= array->length || length == 0) { + return; + } + + size_t end_len = begin + length; + + if (end_len >= array->length) { + array->length = begin; + return; + } + + memmove(&array->list[begin], &array->list[end_len], + sizeof(void *) * (array->length - end_len)); + + array->length -= length; +} + +/* + * No inline functions. + */ +void * +lexbor_array_get_noi(lexbor_array_t *array, size_t idx) +{ + return lexbor_array_get(array, idx); +} + +size_t +lexbor_array_length_noi(lexbor_array_t *array) +{ + return lexbor_array_length(array); +} + +size_t +lexbor_array_size_noi(lexbor_array_t *array) +{ + return lexbor_array_size(array); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array.h new file mode 100644 index 0000000..5dbdac7 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_ARRAY_H +#define LEXBOR_ARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +typedef struct { + void **list; + size_t size; + size_t length; +} +lexbor_array_t; + + +LXB_API lexbor_array_t * +lexbor_array_create(void); + +LXB_API lxb_status_t +lexbor_array_init(lexbor_array_t *array, size_t size); + +LXB_API void +lexbor_array_clean(lexbor_array_t *array); + +LXB_API lexbor_array_t * +lexbor_array_destroy(lexbor_array_t *array, bool self_destroy); + + +LXB_API void ** +lexbor_array_expand(lexbor_array_t *array, size_t up_to); + + +LXB_API lxb_status_t +lexbor_array_push(lexbor_array_t *array, void *value); + +LXB_API void * +lexbor_array_pop(lexbor_array_t *array); + +LXB_API lxb_status_t +lexbor_array_insert(lexbor_array_t *array, size_t idx, void *value); + +LXB_API lxb_status_t +lexbor_array_set(lexbor_array_t *array, size_t idx, void *value); + +LXB_API void +lexbor_array_delete(lexbor_array_t *array, size_t begin, size_t length); + + +/* + * Inline functions + */ +lxb_inline void * +lexbor_array_get(lexbor_array_t *array, size_t idx) +{ + if (idx >= array->length) { + return NULL; + } + + return array->list[idx]; +} + +lxb_inline size_t +lexbor_array_length(lexbor_array_t *array) +{ + return array->length; +} + +lxb_inline size_t +lexbor_array_size(lexbor_array_t *array) +{ + return array->size; +} + +/* + * No inline functions for ABI. + */ +LXB_API void * +lexbor_array_get_noi(lexbor_array_t *array, size_t idx); + +LXB_API size_t +lexbor_array_length_noi(lexbor_array_t *array); + +LXB_API size_t +lexbor_array_size_noi(lexbor_array_t *array); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_ARRAY_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array_obj.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array_obj.c new file mode 100644 index 0000000..79a4c3a --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array_obj.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/array_obj.h" + + +lexbor_array_obj_t * +lexbor_array_obj_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_array_obj_t)); +} + +lxb_status_t +lexbor_array_obj_init(lexbor_array_obj_t *array, + size_t size, size_t struct_size) +{ + if (array == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (size == 0 || struct_size == 0) { + return LXB_STATUS_ERROR_TOO_SMALL_SIZE; + } + + array->length = 0; + array->size = size; + array->struct_size = struct_size; + + array->list = lexbor_malloc(sizeof(uint8_t *) + * (array->size * struct_size)); + if (array->list == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + return LXB_STATUS_OK; +} + +void +lexbor_array_obj_clean(lexbor_array_obj_t *array) +{ + if (array != NULL) { + array->length = 0; + } +} + +lexbor_array_obj_t * +lexbor_array_obj_destroy(lexbor_array_obj_t *array, bool self_destroy) +{ + if (array == NULL) + return NULL; + + if (array->list) { + array->length = 0; + array->size = 0; + array->list = lexbor_free(array->list); + } + + if (self_destroy) { + return lexbor_free(array); + } + + return array; +} + +uint8_t * +lexbor_array_obj_expand(lexbor_array_obj_t *array, size_t up_to) +{ + uint8_t *list; + size_t new_size; + + if (array->length > (SIZE_MAX - up_to)) { + return NULL; + } + + new_size = array->length + up_to; + + list = lexbor_realloc(array->list, sizeof(uint8_t *) + * (new_size * array->struct_size)); + if (list == NULL) { + return NULL; + } + + array->list = list; + array->size = new_size; + + return list; +} + +void * +lexbor_array_obj_push(lexbor_array_obj_t *array) +{ + void *entry; + + if (array->length >= array->size) + { + if ((lexbor_array_obj_expand(array, 128) == NULL)) { + return NULL; + } + } + + entry = array->list + (array->length * array->struct_size); + array->length++; + + memset(entry, 0, array->struct_size); + + return entry; +} + +void * +lexbor_array_obj_push_wo_cls(lexbor_array_obj_t *array) +{ + void *entry; + + if (array->length >= array->size) { + if ((lexbor_array_obj_expand(array, 128) == NULL)) { + return NULL; + } + } + + entry = array->list + (array->length * array->struct_size); + array->length++; + + return entry; +} + +void * +lexbor_array_obj_push_n(lexbor_array_obj_t *array, size_t count) +{ + void *entry; + + if ((array->length + count) > array->size) { + if ((lexbor_array_obj_expand(array, count + 128) == NULL)) { + return NULL; + } + } + + entry = array->list + (array->length * array->struct_size); + array->length += count; + + return entry; +} + +void * +lexbor_array_obj_pop(lexbor_array_obj_t *array) +{ + if (array->length == 0) { + return NULL; + } + + array->length--; + return array->list + (array->length * array->struct_size); +} + +void +lexbor_array_obj_delete(lexbor_array_obj_t *array, size_t begin, size_t length) +{ + if (begin >= array->length || length == 0) { + return; + } + + size_t end_len = begin + length; + + if (end_len >= array->length) { + array->length = begin; + return; + } + + memmove(&array->list[ begin * array->struct_size ], + &array->list[ end_len * array->struct_size ], + sizeof(uint8_t *) + * ((array->length - end_len) * array->struct_size)); + + array->length -= length; +} + +/* + * No inline functions. + */ +void +lexbor_array_obj_erase_noi(lexbor_array_obj_t *array) +{ + lexbor_array_obj_erase(array); +} + +void * +lexbor_array_obj_get_noi(lexbor_array_obj_t *array, size_t idx) +{ + return lexbor_array_obj_get(array, idx); +} + +size_t +lexbor_array_obj_length_noi(lexbor_array_obj_t *array) +{ + return lexbor_array_obj_length(array); +} + +size_t +lexbor_array_obj_size_noi(lexbor_array_obj_t *array) +{ + return lexbor_array_obj_size(array); +} + +size_t +lexbor_array_obj_struct_size_noi(lexbor_array_obj_t *array) +{ + return lexbor_array_obj_struct_size(array); +} + +void * +lexbor_array_obj_last_noi(lexbor_array_obj_t *array) +{ + return lexbor_array_obj_last(array); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array_obj.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array_obj.h new file mode 100644 index 0000000..de6202b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/array_obj.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_ARRAY_OBJ_H +#define LEXBOR_ARRAY_OBJ_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +typedef struct { + uint8_t *list; + size_t size; + size_t length; + size_t struct_size; +} +lexbor_array_obj_t; + + +LXB_API lexbor_array_obj_t * +lexbor_array_obj_create(void); + +LXB_API lxb_status_t +lexbor_array_obj_init(lexbor_array_obj_t *array, + size_t size, size_t struct_size); + +LXB_API void +lexbor_array_obj_clean(lexbor_array_obj_t *array); + +LXB_API lexbor_array_obj_t * +lexbor_array_obj_destroy(lexbor_array_obj_t *array, bool self_destroy); + + +LXB_API uint8_t * +lexbor_array_obj_expand(lexbor_array_obj_t *array, size_t up_to); + + +LXB_API void * +lexbor_array_obj_push(lexbor_array_obj_t *array); + +LXB_API void * +lexbor_array_obj_push_wo_cls(lexbor_array_obj_t *array); + +LXB_API void * +lexbor_array_obj_push_n(lexbor_array_obj_t *array, size_t count); + +LXB_API void * +lexbor_array_obj_pop(lexbor_array_obj_t *array); + +LXB_API void +lexbor_array_obj_delete(lexbor_array_obj_t *array, size_t begin, size_t length); + + +/* + * Inline functions + */ +lxb_inline void +lexbor_array_obj_erase(lexbor_array_obj_t *array) +{ + memset(array, 0, sizeof(lexbor_array_obj_t)); +} + +lxb_inline void * +lexbor_array_obj_get(const lexbor_array_obj_t *array, size_t idx) +{ + if (idx >= array->length) { + return NULL; + } + + return array->list + (idx * array->struct_size); +} + +lxb_inline size_t +lexbor_array_obj_length(lexbor_array_obj_t *array) +{ + return array->length; +} + +lxb_inline size_t +lexbor_array_obj_size(lexbor_array_obj_t *array) +{ + return array->size; +} + +lxb_inline size_t +lexbor_array_obj_struct_size(lexbor_array_obj_t *array) +{ + return array->struct_size; +} + +lxb_inline void * +lexbor_array_obj_last(lexbor_array_obj_t *array) +{ + if (array->length == 0) { + return NULL; + } + + return array->list + ((array->length - 1) * array->struct_size); +} + + +/* + * No inline functions for ABI. + */ +LXB_API void +lexbor_array_obj_erase_noi(lexbor_array_obj_t *array); + +LXB_API void * +lexbor_array_obj_get_noi(lexbor_array_obj_t *array, size_t idx); + +LXB_API size_t +lexbor_array_obj_length_noi(lexbor_array_obj_t *array); + +LXB_API size_t +lexbor_array_obj_size_noi(lexbor_array_obj_t *array); + +LXB_API size_t +lexbor_array_obj_struct_size_noi(lexbor_array_obj_t *array); + +LXB_API void * +lexbor_array_obj_last_noi(lexbor_array_obj_t *array); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_ARRAY_OBJ_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/avl.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/avl.c new file mode 100644 index 0000000..a180d14 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/avl.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2018-2022 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/avl.h" + + +lxb_inline short +lexbor_avl_node_height(lexbor_avl_node_t *node); + +lxb_inline short +lexbor_avl_node_balance_factor(lexbor_avl_node_t *node); + +lxb_inline void +lexbor_avl_node_set_height(lexbor_avl_node_t *node); + +static lexbor_avl_node_t * +lexbor_avl_node_rotate_right(lexbor_avl_node_t *pos); + +static lexbor_avl_node_t * +lexbor_avl_node_rotate_left(lexbor_avl_node_t *pos); + +static lexbor_avl_node_t * +lexbor_avl_node_balance(lexbor_avl_node_t *node, + lexbor_avl_node_t **scope); + +lxb_inline lexbor_avl_node_t * +lexbor_avl_find_min(lexbor_avl_node_t *node); + +lxb_inline void +lexbor_avl_rotate_for_delete(lexbor_avl_node_t *delete_node, + lexbor_avl_node_t *node, + lexbor_avl_node_t **root); + + +lexbor_avl_t * +lexbor_avl_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_avl_t)); +} + +lxb_status_t +lexbor_avl_init(lexbor_avl_t *avl, size_t chunk_len, size_t struct_size) +{ + if (avl == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (chunk_len == 0 + || (struct_size != 0 && struct_size < sizeof(lexbor_avl_node_t))) + { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + if (struct_size == 0) { + struct_size = sizeof(lexbor_avl_node_t); + } + + avl->last_right = NULL; + + avl->nodes = lexbor_dobject_create(); + return lexbor_dobject_init(avl->nodes, chunk_len, struct_size); +} + +void +lexbor_avl_clean(lexbor_avl_t *avl) +{ + avl->last_right = NULL; + + lexbor_dobject_clean(avl->nodes); +} + +lexbor_avl_t * +lexbor_avl_destroy(lexbor_avl_t *avl, bool self_destroy) +{ + if (avl == NULL) + return NULL; + + avl->nodes = lexbor_dobject_destroy(avl->nodes, true); + + if (self_destroy) { + return lexbor_free(avl); + } + + return avl; +} + +lexbor_avl_node_t * +lexbor_avl_node_make(lexbor_avl_t *avl, size_t type, void *value) +{ + lexbor_avl_node_t *node = lexbor_dobject_calloc(avl->nodes); + if (node == NULL) { + return NULL; + } + + node->type = type; + node->value = value; + + return node; +} + +void +lexbor_avl_node_clean(lexbor_avl_node_t *node) +{ + memset(node, 0, sizeof(lexbor_avl_node_t)); +} + +lexbor_avl_node_t * +lexbor_avl_node_destroy(lexbor_avl_t *avl, + lexbor_avl_node_t *node, bool self_destroy) +{ + if (node == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_dobject_free(avl->nodes, node); + } + + return node; +} + +lxb_inline short +lexbor_avl_node_height(lexbor_avl_node_t *node) +{ + return (node) ? node->height : 0; +} + +lxb_inline short +lexbor_avl_node_balance_factor(lexbor_avl_node_t *node) +{ + return (lexbor_avl_node_height(node->right) + - lexbor_avl_node_height(node->left)); +} + +lxb_inline void +lexbor_avl_node_set_height(lexbor_avl_node_t *node) +{ + short left_height = lexbor_avl_node_height(node->left); + short right_height = lexbor_avl_node_height(node->right); + + node->height = ((left_height > right_height) + ? left_height : right_height) + 1; +} + +static lexbor_avl_node_t * +lexbor_avl_node_rotate_right(lexbor_avl_node_t *pos) +{ + lexbor_avl_node_t *node = pos->left; + + node->parent = pos->parent; + + if (node->right) { + node->right->parent = pos; + } + + pos->left = node->right; + pos->parent = node; + + node->right = pos; + + lexbor_avl_node_set_height(pos); + lexbor_avl_node_set_height(node); + + return node; +} + +static lexbor_avl_node_t * +lexbor_avl_node_rotate_left(lexbor_avl_node_t *pos) +{ + lexbor_avl_node_t *node = pos->right; + + node->parent = pos->parent; + + if (node->left) { + node->left->parent = pos; + } + + pos->right = node->left; + pos->parent = node; + + node->left = pos; + + lexbor_avl_node_set_height(pos); + lexbor_avl_node_set_height(node); + + return node; +} + +static lexbor_avl_node_t * +lexbor_avl_node_balance(lexbor_avl_node_t *node, lexbor_avl_node_t **scope) +{ + /* Set height */ + lexbor_avl_node_t *parent; + + short left_height = lexbor_avl_node_height(node->left); + short right_height = lexbor_avl_node_height(node->right); + + node->height = ((left_height > right_height) + ? left_height : right_height) + 1; + + /* Check balance */ + switch ((right_height - left_height)) { + case 2: { + if (lexbor_avl_node_balance_factor(node->right) < 0) { + node->right = lexbor_avl_node_rotate_right(node->right); + } + + parent = node->parent; + + if (parent != NULL) { + if (parent->right == node) { + parent->right = lexbor_avl_node_rotate_left(node); + return parent->right; + } + else { + parent->left = lexbor_avl_node_rotate_left(node); + return parent->left; + } + } + + return lexbor_avl_node_rotate_left(node); + } + case -2: { + if (lexbor_avl_node_balance_factor(node->left) > 0) { + node->left = lexbor_avl_node_rotate_left(node->left); + } + + parent = node->parent; + + if (parent != NULL) { + if (parent->right == node) { + parent->right = lexbor_avl_node_rotate_right(node); + return parent->right; + } + else { + parent->left = lexbor_avl_node_rotate_right(node); + return parent->left; + } + } + + return lexbor_avl_node_rotate_right(node); + } + default: + break; + } + + if (node->parent == NULL) { + *scope = node; + } + + return node->parent; +} + +lexbor_avl_node_t * +lexbor_avl_insert(lexbor_avl_t *avl, lexbor_avl_node_t **scope, + size_t type, void *value) +{ + lexbor_avl_node_t *node, *new_node; + + if (*scope == NULL) { + *scope = lexbor_avl_node_make(avl, type, value); + return *scope; + } + + node = *scope; + new_node = lexbor_dobject_calloc(avl->nodes); + + for (;;) { + if (type == node->type) { + node->value = value; + return node; + } + else if (type < node->type) { + if (node->left == NULL) { + node->left = new_node; + + new_node->parent = node; + new_node->type = type; + new_node->value = value; + + node = new_node; + break; + } + + node = node->left; + } + else { + if (node->right == NULL) { + node->right = new_node; + + new_node->parent = node; + new_node->type = type; + new_node->value = value; + + node = new_node; + break; + } + + node = node->right; + } + } + + while (node != NULL) { + node = lexbor_avl_node_balance(node, scope); + } + + return new_node; +} + +lxb_inline lexbor_avl_node_t * +lexbor_avl_find_min(lexbor_avl_node_t *node) +{ + if (node == NULL) { + return NULL; + } + + while (node->right != NULL) { + node = node->right; + } + + return node; +} + +lxb_inline void +lexbor_avl_rotate_for_delete(lexbor_avl_node_t *delete_node, + lexbor_avl_node_t *node, lexbor_avl_node_t **scope) +{ + lexbor_avl_node_t *balance_node; + + if (node) { + if (delete_node->left == node) { + balance_node = (node->left) ? node->left : node; + + node->parent = delete_node->parent; + node->right = delete_node->right; + + if (delete_node->right) + delete_node->right->parent = node; + } + else { + balance_node = node; + + node->parent->right = NULL; + + node->parent = delete_node->parent; + node->right = delete_node->right; + node->left = delete_node->left; + + if (delete_node->left != NULL) { + delete_node->left->parent = node; + } + + if (delete_node->right != NULL) { + delete_node->right->parent = node; + } + } + + if (delete_node->parent != NULL) { + if (delete_node->parent->left == delete_node) { + delete_node->parent->left = node; + } + else { + delete_node->parent->right = node; + } + } + else { + *scope = node; + } + } + else { + balance_node = delete_node->parent; + + if (balance_node != NULL) { + if (balance_node->left == delete_node) { + balance_node->left = delete_node->right; + } + else { + balance_node->right = delete_node->right; + } + } + else { + *scope = delete_node->right; + } + + if (delete_node->right != NULL) { + delete_node->right->parent = balance_node; + } + } + + while (balance_node != NULL) { + balance_node = lexbor_avl_node_balance(balance_node, scope); + } +} + +void * +lexbor_avl_remove(lexbor_avl_t *avl, lexbor_avl_node_t **scope, size_t type) +{ + void *value; + lexbor_avl_node_t *node = *scope; + + while (node != NULL) { + if (type == node->type) { + avl->last_right = lexbor_avl_find_min(node->left); + lexbor_avl_rotate_for_delete(node, avl->last_right, scope); + + value = node->value; + lexbor_dobject_free(avl->nodes, node); + + return value; + } + else if (type < node->type) { + node = node->left; + } + else { + node = node->right; + } + } + + return NULL; +} + +void +lexbor_avl_remove_by_node(lexbor_avl_t *avl, lexbor_avl_node_t **root, + lexbor_avl_node_t *node) +{ + avl->last_right = lexbor_avl_find_min(node->left); + + lexbor_avl_rotate_for_delete(node, avl->last_right, root); + + (void) lexbor_dobject_free(avl->nodes, node); +} + +lexbor_avl_node_t * +lexbor_avl_search(lexbor_avl_t *avl, lexbor_avl_node_t *node, size_t type) +{ + while (node != NULL) { + if (type == node->type) { + return node; + } + else if (type < node->type) { + node = node->left; + } + else { + node = node->right; + } + } + + return NULL; +} + +lxb_inline lexbor_avl_node_t * +lexbor_avl_search_ge(lexbor_avl_node_t *root, size_t type) +{ + lexbor_avl_node_t *result = NULL; + + while (root != NULL) { + if (type == root->type) { + return root; + } + else if (type < root->type) { + result = root; + root = root->left; + } + else { + root = root->right; + } + } + + return result; +} + +lxb_status_t +lexbor_avl_foreach(lexbor_avl_t *avl, lexbor_avl_node_t **scope, + lexbor_avl_node_f cb, void *ctx) +{ + size_t next_type; + lxb_status_t status; + lexbor_avl_node_t *node; + + if (scope == NULL || *scope == NULL) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + /* Find the leftmost (smallest) node. */ + + node = *scope; + + while (node->left != NULL) { + node = node->left; + } + + while (node != NULL) { + next_type = node->type + 1; + + status = cb(avl, scope, node, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (*scope == NULL) { + return LXB_STATUS_OK; + } + + node = lexbor_avl_search_ge(*scope, next_type); + } + + return LXB_STATUS_OK; +} + +void +lexbor_avl_foreach_recursion(lexbor_avl_t *avl, lexbor_avl_node_t *scope, + lexbor_avl_node_f callback, void *ctx) +{ + if (scope == NULL) { + return; + } + + callback(avl, NULL, scope, ctx); + + lexbor_avl_foreach_recursion(avl, scope->left, callback, ctx); + lexbor_avl_foreach_recursion(avl, scope->right, callback, ctx); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/avl.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/avl.h new file mode 100644 index 0000000..c1a61f6 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/avl.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_AVL_H +#define LEXBOR_AVL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" +#include "lexbor/core/dobject.h" + + +typedef struct lexbor_avl lexbor_avl_t; +typedef struct lexbor_avl_node lexbor_avl_node_t; + +typedef lxb_status_t +(*lexbor_avl_node_f)(lexbor_avl_t *avl, lexbor_avl_node_t **root, + lexbor_avl_node_t *node, void *ctx); + +struct lexbor_avl_node { + size_t type; + short height; + void *value; + + lexbor_avl_node_t *left; + lexbor_avl_node_t *right; + lexbor_avl_node_t *parent; +}; + +struct lexbor_avl { + lexbor_dobject_t *nodes; + lexbor_avl_node_t *last_right; +}; + + +LXB_API lexbor_avl_t * +lexbor_avl_create(void); + +LXB_API lxb_status_t +lexbor_avl_init(lexbor_avl_t *avl, size_t chunk_len, size_t struct_size); + +LXB_API void +lexbor_avl_clean(lexbor_avl_t *avl); + +LXB_API lexbor_avl_t * +lexbor_avl_destroy(lexbor_avl_t *avl, bool self_destroy); + + +LXB_API lexbor_avl_node_t * +lexbor_avl_node_make(lexbor_avl_t *avl, size_t type, void *value); + +LXB_API void +lexbor_avl_node_clean(lexbor_avl_node_t *node); + +LXB_API lexbor_avl_node_t * +lexbor_avl_node_destroy(lexbor_avl_t *avl, lexbor_avl_node_t *node, + bool self_destroy); + + +LXB_API lexbor_avl_node_t * +lexbor_avl_insert(lexbor_avl_t *avl, lexbor_avl_node_t **scope, + size_t type, void *value); + +LXB_API lexbor_avl_node_t * +lexbor_avl_search(lexbor_avl_t *avl, lexbor_avl_node_t *scope, size_t type); + +LXB_API void * +lexbor_avl_remove(lexbor_avl_t *avl, lexbor_avl_node_t **scope, size_t type); + +LXB_API void +lexbor_avl_remove_by_node(lexbor_avl_t *avl, lexbor_avl_node_t **root, + lexbor_avl_node_t *node); + +LXB_API lxb_status_t +lexbor_avl_foreach(lexbor_avl_t *avl, lexbor_avl_node_t **scope, + lexbor_avl_node_f cb, void *ctx); + +LXB_API void +lexbor_avl_foreach_recursion(lexbor_avl_t *avl, lexbor_avl_node_t *scope, + lexbor_avl_node_f callback, void *ctx); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_AVL_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/base.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/base.h new file mode 100644 index 0000000..4b30ab0 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/base.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_BASE_H +#define LEXBOR_BASE_H + +#ifdef __cplusplus +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "lexbor/core/def.h" +#include "lexbor/core/types.h" +#include "lexbor/core/lexbor.h" + +#define LEXBOR_VERSION_MAJOR 3 +#define LEXBOR_VERSION_MINOR 1 +#define LEXBOR_VERSION_PATCH 0 + +#define LEXBOR_VERSION_STRING LEXBOR_STRINGIZE(LEXBOR_VERSION_MAJOR) "." \ + LEXBOR_STRINGIZE(LEXBOR_VERSION_MINOR) "." \ + LEXBOR_STRINGIZE(LEXBOR_VERSION_PATCH) + +#define lexbor_assert(val) + +#define lexbor_max(val1, val2) ((val1) > (val2) ? (val1) : (val2)) +#define lexbor_min(val1, val2) ((val1) < (val2) ? (val1) : (val2)) + +#define LEXBOR_STR_RES_MAP_CHAR_OTHER 0x00 +#define LEXBOR_STR_RES_MAP_CHAR_A_Z_a_z 0x01 +#define LEXBOR_STR_RES_MAP_CHAR_WHITESPACE 0x02 +#define LEXBOR_STR_RES_SLIP 0xFF + +/* + * Very important!!! + * + * for lexbor 0..00AFFF; LXB_STATUS_OK == 0x000000 + */ +typedef enum { + LXB_STATUS_OK = 0x0000, + LXB_STATUS_ERROR = 0x0001, + LXB_STATUS_ERROR_MEMORY_ALLOCATION, + LXB_STATUS_ERROR_OBJECT_IS_NULL, + LXB_STATUS_ERROR_SMALL_BUFFER, + LXB_STATUS_ERROR_INCOMPLETE_OBJECT, + LXB_STATUS_ERROR_NO_FREE_SLOT, + LXB_STATUS_ERROR_TOO_SMALL_SIZE, + LXB_STATUS_ERROR_NOT_EXISTS, + LXB_STATUS_ERROR_WRONG_ARGS, + LXB_STATUS_ERROR_WRONG_STAGE, + LXB_STATUS_ERROR_UNEXPECTED_RESULT, + LXB_STATUS_ERROR_UNEXPECTED_DATA, + LXB_STATUS_ERROR_OVERFLOW, + LXB_STATUS_CONTINUE, + LXB_STATUS_SMALL_BUFFER, + LXB_STATUS_ABORTED, + LXB_STATUS_STOPPED, + LXB_STATUS_NEXT, + LXB_STATUS_STOP, + LXB_STATUS_WARNING, + LXB_STATUS_SKIPPED +} +lexbor_status_t; + +typedef enum { + LEXBOR_ACTION_OK = 0x00, + LEXBOR_ACTION_STOP = 0x01, + LEXBOR_ACTION_NEXT = 0x02 +} +lexbor_action_t; + + +typedef lxb_status_t +(*lexbor_serialize_cb_f)(const lxb_char_t *data, size_t len, void *ctx); + +typedef lxb_status_t +(*lexbor_serialize_cb_cp_f)(const lxb_codepoint_t *cps, size_t len, void *ctx); + + +typedef struct { + lexbor_serialize_cb_f cb; + void *ctx; + + intptr_t opt; + size_t count; +} +lexbor_serialize_ctx_t; + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_BASE_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst.c new file mode 100644 index 0000000..60e79cf --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst.c @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/bst.h" +#include "lexbor/core/conv.h" + + +lexbor_bst_t * +lexbor_bst_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_bst_t)); +} + +lxb_status_t +lexbor_bst_init(lexbor_bst_t *bst, size_t size) +{ + lxb_status_t status; + + if (bst == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (size == 0) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + bst->dobject = lexbor_dobject_create(); + status = lexbor_dobject_init(bst->dobject, size, + sizeof(lexbor_bst_entry_t)); + if (status != LXB_STATUS_OK) { + return status; + } + + bst->root = 0; + bst->tree_length = 0; + + return LXB_STATUS_OK; +} + +void +lexbor_bst_clean(lexbor_bst_t *bst) +{ + if (bst != NULL) { + lexbor_dobject_clean(bst->dobject); + + bst->root = 0; + bst->tree_length = 0; + } +} + +lexbor_bst_t * +lexbor_bst_destroy(lexbor_bst_t *bst, bool self_destroy) +{ + if (bst == NULL) { + return NULL; + } + + bst->dobject = lexbor_dobject_destroy(bst->dobject, true); + + if (self_destroy) { + return lexbor_free(bst); + } + + return bst; +} + +lexbor_bst_entry_t * +lexbor_bst_entry_make(lexbor_bst_t *bst, size_t size) +{ + lexbor_bst_entry_t *new_entry = lexbor_dobject_calloc(bst->dobject); + if (new_entry == NULL) { + return NULL; + } + + new_entry->size = size; + + bst->tree_length++; + + return new_entry; +} + +lexbor_bst_entry_t * +lexbor_bst_insert(lexbor_bst_t *bst, lexbor_bst_entry_t **scope, + size_t size, void *value) +{ + lexbor_bst_entry_t *new_entry, *entry; + + new_entry = lexbor_dobject_calloc(bst->dobject); + if (new_entry == NULL) { + return NULL; + } + + new_entry->size = size; + new_entry->value = value; + + bst->tree_length++; + + if (*scope == NULL) { + *scope = new_entry; + return new_entry; + } + + entry = *scope; + + while (entry != NULL) { + if (size == entry->size) { + if (entry->next) { + new_entry->next = entry->next; + } + + entry->next = new_entry; + new_entry->parent = entry->parent; + + return new_entry; + } + else if (size > entry->size) { + if (entry->right == NULL) { + entry->right = new_entry; + new_entry->parent = entry; + + return new_entry; + } + + entry = entry->right; + } + else { + if (entry->left == NULL) { + entry->left = new_entry; + new_entry->parent = entry; + + return new_entry; + } + + entry = entry->left; + } + } + + return NULL; +} + +lexbor_bst_entry_t * +lexbor_bst_insert_not_exists(lexbor_bst_t *bst, lexbor_bst_entry_t **scope, + size_t size) +{ + lexbor_bst_entry_t *entry; + + if (*scope == NULL) { + *scope = lexbor_bst_entry_make(bst, size); + + return *scope; + } + + entry = *scope; + + while (entry != NULL) { + if (size == entry->size) { + return entry; + } + else if (size > entry->size) { + if (entry->right == NULL) { + entry->right = lexbor_bst_entry_make(bst, size); + entry->right->parent = entry; + + return entry->right; + } + + entry = entry->right; + } + else { + if (entry->left == NULL) { + entry->left = lexbor_bst_entry_make(bst, size); + entry->left->parent = entry; + + return entry->left; + } + + entry = entry->left; + } + } + + return NULL; +} + +lexbor_bst_entry_t * +lexbor_bst_search(lexbor_bst_t *bst, lexbor_bst_entry_t *scope, size_t size) +{ + while (scope != NULL) { + if (scope->size == size) { + return scope; + } + else if (size > scope->size) { + scope = scope->right; + } + else { + scope = scope->left; + } + } + + return NULL; +} + +lexbor_bst_entry_t * +lexbor_bst_search_close(lexbor_bst_t *bst, lexbor_bst_entry_t *scope, + size_t size) +{ + lexbor_bst_entry_t *max = NULL; + + while (scope != NULL) { + if (scope->size == size) { + return scope; + } + else if (size > scope->size) { + scope = scope->right; + } + else { + max = scope; + scope = scope->left; + } + } + + return max; +} + +void * +lexbor_bst_remove(lexbor_bst_t *bst, lexbor_bst_entry_t **scope, size_t size) +{ + lexbor_bst_entry_t *entry = *scope; + + while (entry != NULL) { + if (entry->size == size) { + return lexbor_bst_remove_by_pointer(bst, entry, scope); + } + else if (size > entry->size) { + entry = entry->right; + } + else { + entry = entry->left; + } + } + + return NULL; +} + +void * +lexbor_bst_remove_close(lexbor_bst_t *bst, lexbor_bst_entry_t **scope, + size_t size, size_t *found_size) +{ + lexbor_bst_entry_t *entry = *scope; + lexbor_bst_entry_t *max = NULL; + + while (entry != NULL) { + if (entry->size == size) { + if (found_size) { + *found_size = entry->size; + } + + return lexbor_bst_remove_by_pointer(bst, entry, scope); + } + else if (size > entry->size) { + entry = entry->right; + } + else { + max = entry; + entry = entry->left; + } + } + + if (max != NULL) { + if (found_size != NULL) { + *found_size = max->size; + } + + return lexbor_bst_remove_by_pointer(bst, max, scope); + } + + if (found_size != NULL) { + *found_size = 0; + } + + return NULL; +} + +void * +lexbor_bst_remove_by_pointer(lexbor_bst_t *bst, lexbor_bst_entry_t *entry, + lexbor_bst_entry_t **root) +{ + void *value; + lexbor_bst_entry_t *next, *right, *left; + + bst->tree_length--; + + if (entry->next != NULL) { + next = entry->next; + entry->next = entry->next->next; + + value = next->value; + + lexbor_dobject_free(bst->dobject, next); + + return value; + } + + value = entry->value; + + if (entry->left == NULL && entry->right == NULL) { + if (entry->parent != NULL) { + if (entry->parent->left == entry) entry->parent->left = NULL; + if (entry->parent->right == entry) entry->parent->right = NULL; + } + else { + *root = NULL; + } + + lexbor_dobject_free(bst->dobject, entry); + } + else if (entry->left == NULL) { + if (entry->parent == NULL) { + entry->right->parent = NULL; + + *root = entry->right; + + lexbor_dobject_free(bst->dobject, entry); + + entry = *root; + } + else { + right = entry->right; + right->parent = entry->parent; + + memcpy(entry, right, sizeof(lexbor_bst_entry_t)); + + lexbor_dobject_free(bst->dobject, right); + } + + if (entry->right != NULL) { + entry->right->parent = entry; + } + + if (entry->left != NULL) { + entry->left->parent = entry; + } + } + else if (entry->right == NULL) { + if (entry->parent == NULL) { + entry->left->parent = NULL; + + *root = entry->left; + + lexbor_dobject_free(bst->dobject, entry); + + entry = *root; + } + else { + left = entry->left; + left->parent = entry->parent; + + memcpy(entry, left, sizeof(lexbor_bst_entry_t)); + + lexbor_dobject_free(bst->dobject, left); + } + + if (entry->right != NULL) { + entry->right->parent = entry; + } + + if (entry->left != NULL) { + entry->left->parent = entry; + } + } + else { + left = entry->right; + + while (left->left != NULL) { + left = left->left; + } + + /* Swap */ + entry->size = left->size; + entry->next = left->next; + entry->value = left->value; + + /* Change parrent */ + if (entry->right == left) { + entry->right = left->right; + + if (entry->right != NULL) { + left->right->parent = entry; + } + } + else { + left->parent->left = left->right; + + if (left->right != NULL) { + left->right->parent = left->parent; + } + } + + lexbor_dobject_free(bst->dobject, left); + } + + return value; +} + +void +lexbor_bst_serialize(lexbor_bst_t *bst, lexbor_callback_f callback, void *ctx) +{ + lexbor_bst_serialize_entry(bst->root, callback, ctx, 0); +} + +void +lexbor_bst_serialize_entry(lexbor_bst_entry_t *entry, + lexbor_callback_f callback, void *ctx, size_t tabs) +{ + size_t len; + lxb_char_t buff[1024]; + + if (entry == NULL) { + return; + } + + /* Left */ + for (size_t i = 0; i < tabs; i++) { + callback((lxb_char_t *) "\t", 1, ctx); + } + callback((lxb_char_t *) "left) { + len = lexbor_conv_int64_to_data((int64_t) entry->left->size, + buff, sizeof(buff)); + callback(buff, len, ctx); + + callback((lxb_char_t *) ">\n", 2, ctx); + lexbor_bst_serialize_entry(entry->left, callback, ctx, (tabs + 1)); + + for (size_t i = 0; i < tabs; i++) { + callback((lxb_char_t *) "\t", 1, ctx); + } + } + else { + callback((lxb_char_t *) "NULL>", 5, ctx); + } + + callback((lxb_char_t *) "\n", 8, ctx); + + /* Right */ + for (size_t i = 0; i < tabs; i++) { + callback((lxb_char_t *) "\t", 1, ctx); + } + callback((lxb_char_t *) "right) { + len = lexbor_conv_int64_to_data((int64_t) entry->right->size, + buff, sizeof(buff)); + callback(buff, len, ctx); + + callback((lxb_char_t *) ">\n", 2, ctx); + lexbor_bst_serialize_entry(entry->right, callback, ctx, (tabs + 1)); + + for (size_t i = 0; i < tabs; i++) { + callback((lxb_char_t *) "\t", 1, ctx); + } + } + else { + callback((lxb_char_t *) "NULL>", 5, ctx); + } + + callback((lxb_char_t *) "\n", 9, ctx); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst.h new file mode 100644 index 0000000..3d7bf88 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_BST_H +#define LEXBOR_BST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lexbor/core/base.h" +#include "lexbor/core/dobject.h" + + +#define lexbor_bst_root(bst) (bst)->root +#define lexbor_bst_root_ref(bst) &((bst)->root) + + +typedef struct lexbor_bst_entry lexbor_bst_entry_t; +typedef struct lexbor_bst lexbor_bst_t; + +typedef bool (*lexbor_bst_entry_f)(lexbor_bst_t *bst, + lexbor_bst_entry_t *entry, void *ctx); + +struct lexbor_bst_entry { + void *value; + + lexbor_bst_entry_t *right; + lexbor_bst_entry_t *left; + lexbor_bst_entry_t *next; + lexbor_bst_entry_t *parent; + + size_t size; +}; + +struct lexbor_bst { + lexbor_dobject_t *dobject; + lexbor_bst_entry_t *root; + + size_t tree_length; +}; + + +LXB_API lexbor_bst_t * +lexbor_bst_create(void); + +LXB_API lxb_status_t +lexbor_bst_init(lexbor_bst_t *bst, size_t size); + +LXB_API void +lexbor_bst_clean(lexbor_bst_t *bst); + +LXB_API lexbor_bst_t * +lexbor_bst_destroy(lexbor_bst_t *bst, bool self_destroy); + +LXB_API lexbor_bst_entry_t * +lexbor_bst_entry_make(lexbor_bst_t *bst, size_t size); + +LXB_API lexbor_bst_entry_t * +lexbor_bst_insert(lexbor_bst_t *bst, lexbor_bst_entry_t **scope, + size_t size, void *value); + +LXB_API lexbor_bst_entry_t * +lexbor_bst_insert_not_exists(lexbor_bst_t *bst, lexbor_bst_entry_t **scope, + size_t size); + + +LXB_API lexbor_bst_entry_t * +lexbor_bst_search(lexbor_bst_t *bst, lexbor_bst_entry_t *scope, size_t size); + +LXB_API lexbor_bst_entry_t * +lexbor_bst_search_close(lexbor_bst_t *bst, lexbor_bst_entry_t *scope, + size_t size); + + +LXB_API void * +lexbor_bst_remove(lexbor_bst_t *bst, lexbor_bst_entry_t **root, size_t size); + +LXB_API void * +lexbor_bst_remove_close(lexbor_bst_t *bst, lexbor_bst_entry_t **root, + size_t size, size_t *found_size); + +LXB_API void * +lexbor_bst_remove_by_pointer(lexbor_bst_t *bst, lexbor_bst_entry_t *entry, + lexbor_bst_entry_t **root); + + +LXB_API void +lexbor_bst_serialize(lexbor_bst_t *bst, lexbor_callback_f callback, void *ctx); + +LXB_API void +lexbor_bst_serialize_entry(lexbor_bst_entry_t *entry, + lexbor_callback_f callback, void *ctx, size_t tabs); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_BST_H */ + + + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst_map.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst_map.c new file mode 100644 index 0000000..bc1c8bd --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst_map.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/bst_map.h" +#include "lexbor/core/utils.h" + + +lexbor_bst_map_t * +lexbor_bst_map_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_bst_map_t)); +} + +lxb_status_t +lexbor_bst_map_init(lexbor_bst_map_t *bst_map, size_t size) +{ + lxb_status_t status; + + if (bst_map == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (size == 0) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + /* bst */ + bst_map->bst = lexbor_bst_create(); + status = lexbor_bst_init(bst_map->bst, size); + if (status) { + return status; + } + + /* dobject */ + bst_map->entries = lexbor_dobject_create(); + status = lexbor_dobject_init(bst_map->entries, size, + sizeof(lexbor_bst_map_entry_t)); + if (status) { + return status; + } + + /* mraw */ + bst_map->mraw = lexbor_mraw_create(); + status = lexbor_mraw_init(bst_map->mraw, (size * 6)); + if (status) { + return status; + } + + return LXB_STATUS_OK; +} + +void +lexbor_bst_map_clean(lexbor_bst_map_t *bst_map) +{ + lexbor_bst_clean(bst_map->bst); + lexbor_mraw_clean(bst_map->mraw); + lexbor_dobject_clean(bst_map->entries); +} + +lexbor_bst_map_t * +lexbor_bst_map_destroy(lexbor_bst_map_t *bst_map, bool self_destroy) +{ + if (bst_map == NULL) { + return NULL; + } + + bst_map->bst = lexbor_bst_destroy(bst_map->bst, true); + bst_map->mraw = lexbor_mraw_destroy(bst_map->mraw, true); + bst_map->entries = lexbor_dobject_destroy(bst_map->entries, true); + + if (self_destroy) { + return lexbor_free(bst_map); + } + + return bst_map; +} + +lexbor_bst_map_entry_t * +lexbor_bst_map_search(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t *scope, + const lxb_char_t *key, size_t key_len) +{ + lexbor_bst_map_entry_t *entry; + lexbor_bst_entry_t *bst_entry; + + size_t hash_id = lexbor_utils_hash_hash(key, key_len); + + bst_entry = lexbor_bst_search(bst_map->bst, scope, hash_id); + if (bst_entry == NULL) { + return NULL; + } + + do { + entry = bst_entry->value; + + if (entry->str.length == key_len && + lexbor_str_data_cmp(entry->str.data, key)) + { + return entry; + } + + bst_entry = bst_entry->next; + } + while (bst_entry != NULL); + + return NULL; +} + +lexbor_bst_map_entry_t * +lexbor_bst_map_insert(lexbor_bst_map_t *bst_map, + lexbor_bst_entry_t **scope, + const lxb_char_t *key, size_t key_len, void *value) +{ + lexbor_bst_map_entry_t *entry; + + entry = lexbor_bst_map_insert_not_exists(bst_map, scope, key, key_len); + if (entry == NULL) { + return NULL; + } + + entry->value = value; + + return entry; +} + +lexbor_bst_map_entry_t * +lexbor_bst_map_insert_not_exists(lexbor_bst_map_t *bst_map, + lexbor_bst_entry_t **scope, + const lxb_char_t *key, size_t key_len) +{ + lexbor_bst_map_entry_t *entry; + lexbor_bst_entry_t *bst_entry; + + size_t hash_id = lexbor_utils_hash_hash(key, key_len); + + bst_entry = lexbor_bst_insert_not_exists(bst_map->bst, scope, hash_id); + if (bst_entry == NULL) { + return NULL; + } + + if (bst_entry->value == NULL) { + goto new_entry; + } + + do { + entry = bst_entry->value; + + if (entry->str.length == key_len && + lexbor_str_data_cmp(entry->str.data, key)) + { + return entry; + } + + if (bst_entry->next == NULL) { + bst_entry->next = lexbor_bst_entry_make(bst_map->bst, hash_id); + bst_entry = bst_entry->next; + + if (bst_entry == NULL) { + return NULL; + } + + goto new_entry; + } + + bst_entry = bst_entry->next; + } + while (1); + + return NULL; + +new_entry: + + entry = lexbor_dobject_calloc(bst_map->entries); + if (entry == NULL) { + return NULL; + } + + lexbor_str_init(&entry->str, bst_map->mraw, key_len); + if (entry->str.data == NULL) { + lexbor_dobject_free(bst_map->entries, entry); + + return NULL; + } + + lexbor_str_append(&entry->str, bst_map->mraw, key, key_len); + + bst_entry->value = entry; + + return entry; +} + +void * +lexbor_bst_map_remove(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t **scope, + const lxb_char_t *key, size_t key_len) +{ + lexbor_bst_map_entry_t *entry; + lexbor_bst_entry_t *bst_entry; + + size_t hash_id = lexbor_utils_hash_hash(key, key_len); + + bst_entry = lexbor_bst_search(bst_map->bst, *scope, hash_id); + if (bst_entry == NULL) { + return NULL; + } + + do { + entry = bst_entry->value; + + if (entry->str.length == key_len && + lexbor_str_data_cmp(entry->str.data, key)) + { + void *value = entry->value; + + lexbor_bst_remove_by_pointer(bst_map->bst, bst_entry, scope); + + lexbor_str_destroy(&entry->str, bst_map->mraw, false); + lexbor_dobject_free(bst_map->entries, entry); + + return value; + } + + bst_entry = bst_entry->next; + } + while (bst_entry != NULL); + + return NULL; +} + +/* + * No inline functions. + */ +lexbor_mraw_t * +lexbor_bst_map_mraw_noi(lexbor_bst_map_t *bst_map) +{ + return lexbor_bst_map_mraw(bst_map); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst_map.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst_map.h new file mode 100644 index 0000000..69b9faa --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/bst_map.h @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_BST_MAP_H +#define LEXBOR_BST_MAP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/bst.h" +#include "lexbor/core/str.h" +#include "lexbor/core/mraw.h" +#include "lexbor/core/dobject.h" + + +typedef struct { + lexbor_str_t str; + void *value; +} +lexbor_bst_map_entry_t; + +typedef struct { + lexbor_bst_t *bst; + lexbor_mraw_t *mraw; + lexbor_dobject_t *entries; + +} +lexbor_bst_map_t; + + +LXB_API lexbor_bst_map_t * +lexbor_bst_map_create(void); + +LXB_API lxb_status_t +lexbor_bst_map_init(lexbor_bst_map_t *bst_map, size_t size); + +LXB_API void +lexbor_bst_map_clean(lexbor_bst_map_t *bst_map); + +LXB_API lexbor_bst_map_t * +lexbor_bst_map_destroy(lexbor_bst_map_t *bst_map, bool self_destroy); + + +LXB_API lexbor_bst_map_entry_t * +lexbor_bst_map_search(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t *scope, + const lxb_char_t *key, size_t key_len); + +LXB_API lexbor_bst_map_entry_t * +lexbor_bst_map_insert(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t **scope, + const lxb_char_t *key, size_t key_len, void *value); + +LXB_API lexbor_bst_map_entry_t * +lexbor_bst_map_insert_not_exists(lexbor_bst_map_t *bst_map, + lexbor_bst_entry_t **scope, + const lxb_char_t *key, size_t key_len); + +LXB_API void * +lexbor_bst_map_remove(lexbor_bst_map_t *bst_map, lexbor_bst_entry_t **scope, + const lxb_char_t *key, size_t key_len); + + +/* + * Inline functions + */ +lxb_inline lexbor_mraw_t * +lexbor_bst_map_mraw(lexbor_bst_map_t *bst_map) +{ + return bst_map->mraw; +} + +/* + * No inline functions for ABI. + */ +LXB_API lexbor_mraw_t * +lexbor_bst_map_mraw_noi(lexbor_bst_map_t *bst_map); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_BST_MAP_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/conv.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/conv.c new file mode 100644 index 0000000..b694c5a --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/conv.c @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include +#include + +#include "lexbor/core/conv.h" +#include "lexbor/core/dtoa.h" +#include "lexbor/core/strtod.h" + + +size_t +lexbor_conv_float_to_data(double num, lxb_char_t *buf, size_t len) +{ + return lexbor_dtoa(num, buf, len); +} + +size_t +lexbor_conv_long_to_data(long num, lxb_char_t *buf, size_t len) +{ + return lexbor_conv_int64_to_data((int64_t) num, buf, len); +} + +size_t +lexbor_conv_int64_to_data(int64_t num, lxb_char_t *buf, size_t len) +{ + int64_t tmp; + size_t have_minus, i, length; + + static const lxb_char_t *digits = (const lxb_char_t *) "0123456789"; + + if (num != 0) { + tmp = num; + length = 0; + have_minus = 0; + + if (num < 0) { + length = 1; + num = -num; + have_minus = 1; + } + + while (tmp != 0) { + length += 1; + tmp /= 10; + } + + /* length += (size_t) floor(log10(labs((long) num))) + 1; */ + } + else { + if (len > 0) { + buf[0] = '0'; + return 1; + } + + return 0; + } + + if (len < length) { + i = (length + have_minus) - len; + + while (i != have_minus) { + i -= 1; + num /= 10; + } + + length = len; + } + + if (have_minus) { + buf[0] = '-'; + } + + i = length; + if (length < len) { + buf[length] = '\0'; + } + + while (i != have_minus) { + i -= 1; + buf[i] = digits[ num % 10 ]; + num /= 10; + } + + return length; +} + +double +lexbor_conv_data_to_double(const lxb_char_t **start, size_t len) +{ + int exponent, exp, insignf; + lxb_char_t c, *pos; + bool minus, ex_minus; + double num; + const lxb_char_t *e, *p, *last, *end; + lxb_char_t data[128]; + + end = *start + len; + + exponent = 0; + insignf = 0; + + pos = data; + last = data + sizeof(data); + + minus = false; + + switch (**start) { + case '-': + minus = true; + /* fall through */ + case '+': + (*start)++; + /* fall through */ + default: + break; + } + + for (p = *start; p < end; p++) { + /* Values less than '0' become >= 208. */ + c = *p - '0'; + + if (c > 9) { + break; + } + + if (pos < last) { + *pos++ = *p; + } + else { + insignf++; + } + } + + /* Do not emit a '.', but adjust the exponent instead. */ + if (p < end && *p == '.') { + + for (p++; p < end; p++) { + /* Values less than '0' become >= 208. */ + c = *p - '0'; + + if (c > 9) { + break; + } + + if (pos < last) { + *pos++ = *p; + exponent--; + } + else { + /* Ignore insignificant digits in the fractional part. */ + } + } + } + + e = p + 1; + + if (e < end && (*p == 'e' || *p == 'E')) { + ex_minus = 0; + + if (e + 1 < end) { + if (*e == '-') { + e++; + ex_minus = 1; + } + else if (*e == '+') { + e++; + } + } + + /* Values less than '0' become >= 208. */ + c = *e - '0'; + + if (c <= 9) { + exp = c; + + for (p = e + 1; p < end; p++) { + /* Values less than '0' become >= 208. */ + c = *p - '0'; + + if (c > 9) { + break; + } + + exp = exp * 10 + c; + } + + exponent += ex_minus ? -exp : exp; + } + } + + *start = p; + + exponent += insignf; + + num = lexbor_strtod_internal(data, pos - data, exponent); + + if (minus) { + num = -num; + } + + return num; +} + +unsigned long +lexbor_conv_data_to_ulong(const lxb_char_t **data, size_t length) +{ + const lxb_char_t *p = *data; + const lxb_char_t *end = p + length; + unsigned long last_number = 0, number = 0; + + for (; p < end; p++) { + if (*p < '0' || *p > '9') { + goto done; + } + + number = (*p - '0') + number * 10; + + if (last_number > number) { + *data = p - 1; + return last_number; + } + + last_number = number; + } + +done: + + *data = p; + + return number; +} + +long +lexbor_conv_data_to_long(const lxb_char_t **data, size_t length) +{ + bool minus; + const lxb_char_t *p; + const lxb_char_t *end; + unsigned long n = 0, number = 0; + + minus = false; + p = *data; + end = p + length; + + switch (*p) { + case '-': + minus = true; + /* fall through */ + case '+': + p++; + /* fall through */ + default: + break; + } + + for (; p < end; p++) { + if (*p < '0' || *p > '9') { + break; + } + + n = (*p - '0') + number * 10; + + if (n > LONG_MAX) { + p -= 1; + break; + } + + number = n; + } + + *data = p; + + return (minus) ? -number : number; +} + +unsigned +lexbor_conv_data_to_uint(const lxb_char_t **data, size_t length) +{ + const lxb_char_t *p = *data; + const lxb_char_t *end = p + length; + unsigned last_number = 0, number = 0; + + for (; p < end; p++) { + if (*p < '0' || *p > '9') { + goto done; + } + + number = (*p - '0') + number * 10; + + if (last_number > number) { + *data = p - 1; + return last_number; + } + + last_number = number; + } + +done: + + *data = p; + + return number; +} + +size_t +lexbor_conv_dec_to_hex(uint32_t number, lxb_char_t *out, size_t length, + bool upper) +{ + lxb_char_t c; + size_t len; + uint32_t tmp; + const lxb_char_t *map_str; + + static const lxb_char_t map_str_l[] = "0123456789abcdef"; + static const lxb_char_t map_str_u[] = "0123456789ABCDEF"; + + map_str = (upper) ? map_str_u : map_str_l; + + if (number != 0) { + tmp = number; + len = 0; + + while (tmp != 0) { + len += 1; + tmp /= 16; + } + } + else { + if (length > 0) { + out[0] = '0'; + return 1; + } + + return 0; + } + + while (len > length) { + number /= 16; + len -= 1; + } + + tmp = (uint32_t) len; + + while (tmp != 0) { + tmp -= 1; + c = number % 16; + number = number / 16; + out[tmp] = map_str[c]; + } + + return len; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/conv.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/conv.h new file mode 100644 index 0000000..df2bfca --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/conv.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CONV_H +#define LEXBOR_CONV_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "lexbor/core/base.h" + + +LXB_API size_t +lexbor_conv_float_to_data(double num, lxb_char_t *buf, size_t len); + +LXB_API size_t +lexbor_conv_long_to_data(long num, lxb_char_t *buf, size_t len); + +LXB_API size_t +lexbor_conv_int64_to_data(int64_t num, lxb_char_t *buf, size_t len); + +LXB_API double +lexbor_conv_data_to_double(const lxb_char_t **start, size_t len); + +LXB_API unsigned long +lexbor_conv_data_to_ulong(const lxb_char_t **data, size_t length); + +LXB_API long +lexbor_conv_data_to_long(const lxb_char_t **data, size_t length); + +LXB_API unsigned +lexbor_conv_data_to_uint(const lxb_char_t **data, size_t length); + +LXB_API size_t +lexbor_conv_dec_to_hex(uint32_t number, lxb_char_t *out, size_t length, + bool upper); + +lxb_inline long +lexbor_conv_double_to_long(double number) +{ + if (number > (double) LONG_MAX) { + return LONG_MAX; + } + + if (number < (double) LONG_MIN) { + return -LONG_MAX; + } + + return (long) number; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CONV_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/core.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/core.h new file mode 100644 index 0000000..047254e --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/core.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CORE_H +#define LEXBOR_CORE_H + +#include "lexbor/core/base.h" +#include "lexbor/core/def.h" +#include "lexbor/core/types.h" +#include "lexbor/core/array.h" +#include "lexbor/core/array_obj.h" +#include "lexbor/core/avl.h" +#include "lexbor/core/bst.h" +#include "lexbor/core/bst_map.h" +#include "lexbor/core/dobject.h" +#include "lexbor/core/fs.h" +#include "lexbor/core/in.h" +#include "lexbor/core/lexbor.h" +#include "lexbor/core/mem.h" +#include "lexbor/core/mraw.h" +#include "lexbor/core/perf.h" +#include "lexbor/core/sbst.h" +#include "lexbor/core/shs.h" +#include "lexbor/core/str.h" +#include "lexbor/core/conv.h" +#include "lexbor/core/utils.h" +#include "lexbor/core/diyfp.h" +#include "lexbor/core/dtoa.h" +#include "lexbor/core/strtod.h" +#include "lexbor/core/serialize.h" + +#endif /* LEXBOR_CORE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/def.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/def.h new file mode 100644 index 0000000..c8b9440 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/def.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_DEF_H +#define LEXBOR_DEF_H + +#define LEXBOR_STRINGIZE_HELPER(x) #x +#define LEXBOR_STRINGIZE(x) LEXBOR_STRINGIZE_HELPER(x) + +/* Format */ +#ifdef _WIN32 + #define LEXBOR_FORMAT_Z "%Iu" +#else + #define LEXBOR_FORMAT_Z "%zu" +#endif + +/* Deprecated */ +#ifdef _MSC_VER + #define LXB_DEPRECATED(func) __declspec(deprecated) func +#elif defined(__GNUC__) || defined(__INTEL_COMPILER) + #define LXB_DEPRECATED(func) func __attribute__((deprecated)) +#else + #define LXB_DEPRECATED(func) func +#endif + +/* Debug */ +//#define LEXBOR_DEBUG(...) do {} while (0) +//#define LEXBOR_DEBUG_ERROR(...) do {} while (0) + +#define LEXBOR_MEM_ALIGN_STEP sizeof(void *) + +#ifndef LEXBOR_STATIC + #ifdef _WIN32 + #ifdef LEXBOR_BUILDING + #define LXB_API __declspec(dllexport) + #else + #define LXB_API __declspec(dllimport) + #endif + #elif (defined(__SUNPRO_C) || defined(__SUNPRO_CC)) + #define LXB_API __global + #else + #if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__INTEL_COMPILER) + #define LXB_API __attribute__ ((visibility("default"))) + #else + #define LXB_API + #endif + #endif +#else + #define LXB_API +#endif + +#define LXB_EXTERN extern LXB_API + +#define lxb_size(_size) ((size_t) (_size)) + +#endif /* LEXBOR_DEF_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/diyfp.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/diyfp.c new file mode 100644 index 0000000..7bdbcbb --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/diyfp.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2015-2019 NGINX, Inc. + * Copyright (C) 2019-2025 F5, Inc. + * Copyright (C) 2015-2021 Igor Sysoev + * Copyright (C) 2017-2025 Dmitry Volyntsev + * Copyright (C) 2019-2022 Alexander Borisov + * Copyright (C) 2022-2025 Vadim Zhestikov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) Alexander Borisov + * + * Based on nxt_diyfp.h from NGINX NJS project + * An internal diy_fp implementation. + * For details, see Loitsch, Florian. "Printing floating-point numbers quickly + * and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243. + */ + + +#include "lexbor/core/diyfp.h" + + +typedef struct { + uint64_t significand; + int16_t bin_exp; + int16_t dec_exp; +} +lexbor_diyfp_cpe_t; + + +static const lexbor_diyfp_cpe_t lexbor_cached_powers[] = { + { lexbor_uint64_hl(0xfa8fd5a0, 0x081c0288), -1220, -348 }, + { lexbor_uint64_hl(0xbaaee17f, 0xa23ebf76), -1193, -340 }, + { lexbor_uint64_hl(0x8b16fb20, 0x3055ac76), -1166, -332 }, + { lexbor_uint64_hl(0xcf42894a, 0x5dce35ea), -1140, -324 }, + { lexbor_uint64_hl(0x9a6bb0aa, 0x55653b2d), -1113, -316 }, + { lexbor_uint64_hl(0xe61acf03, 0x3d1a45df), -1087, -308 }, + { lexbor_uint64_hl(0xab70fe17, 0xc79ac6ca), -1060, -300 }, + { lexbor_uint64_hl(0xff77b1fc, 0xbebcdc4f), -1034, -292 }, + { lexbor_uint64_hl(0xbe5691ef, 0x416bd60c), -1007, -284 }, + { lexbor_uint64_hl(0x8dd01fad, 0x907ffc3c), -980, -276 }, + { lexbor_uint64_hl(0xd3515c28, 0x31559a83), -954, -268 }, + { lexbor_uint64_hl(0x9d71ac8f, 0xada6c9b5), -927, -260 }, + { lexbor_uint64_hl(0xea9c2277, 0x23ee8bcb), -901, -252 }, + { lexbor_uint64_hl(0xaecc4991, 0x4078536d), -874, -244 }, + { lexbor_uint64_hl(0x823c1279, 0x5db6ce57), -847, -236 }, + { lexbor_uint64_hl(0xc2109436, 0x4dfb5637), -821, -228 }, + { lexbor_uint64_hl(0x9096ea6f, 0x3848984f), -794, -220 }, + { lexbor_uint64_hl(0xd77485cb, 0x25823ac7), -768, -212 }, + { lexbor_uint64_hl(0xa086cfcd, 0x97bf97f4), -741, -204 }, + { lexbor_uint64_hl(0xef340a98, 0x172aace5), -715, -196 }, + { lexbor_uint64_hl(0xb23867fb, 0x2a35b28e), -688, -188 }, + { lexbor_uint64_hl(0x84c8d4df, 0xd2c63f3b), -661, -180 }, + { lexbor_uint64_hl(0xc5dd4427, 0x1ad3cdba), -635, -172 }, + { lexbor_uint64_hl(0x936b9fce, 0xbb25c996), -608, -164 }, + { lexbor_uint64_hl(0xdbac6c24, 0x7d62a584), -582, -156 }, + { lexbor_uint64_hl(0xa3ab6658, 0x0d5fdaf6), -555, -148 }, + { lexbor_uint64_hl(0xf3e2f893, 0xdec3f126), -529, -140 }, + { lexbor_uint64_hl(0xb5b5ada8, 0xaaff80b8), -502, -132 }, + { lexbor_uint64_hl(0x87625f05, 0x6c7c4a8b), -475, -124 }, + { lexbor_uint64_hl(0xc9bcff60, 0x34c13053), -449, -116 }, + { lexbor_uint64_hl(0x964e858c, 0x91ba2655), -422, -108 }, + { lexbor_uint64_hl(0xdff97724, 0x70297ebd), -396, -100 }, + { lexbor_uint64_hl(0xa6dfbd9f, 0xb8e5b88f), -369, -92 }, + { lexbor_uint64_hl(0xf8a95fcf, 0x88747d94), -343, -84 }, + { lexbor_uint64_hl(0xb9447093, 0x8fa89bcf), -316, -76 }, + { lexbor_uint64_hl(0x8a08f0f8, 0xbf0f156b), -289, -68 }, + { lexbor_uint64_hl(0xcdb02555, 0x653131b6), -263, -60 }, + { lexbor_uint64_hl(0x993fe2c6, 0xd07b7fac), -236, -52 }, + { lexbor_uint64_hl(0xe45c10c4, 0x2a2b3b06), -210, -44 }, + { lexbor_uint64_hl(0xaa242499, 0x697392d3), -183, -36 }, + { lexbor_uint64_hl(0xfd87b5f2, 0x8300ca0e), -157, -28 }, + { lexbor_uint64_hl(0xbce50864, 0x92111aeb), -130, -20 }, + { lexbor_uint64_hl(0x8cbccc09, 0x6f5088cc), -103, -12 }, + { lexbor_uint64_hl(0xd1b71758, 0xe219652c), -77, -4 }, + { lexbor_uint64_hl(0x9c400000, 0x00000000), -50, 4 }, + { lexbor_uint64_hl(0xe8d4a510, 0x00000000), -24, 12 }, + { lexbor_uint64_hl(0xad78ebc5, 0xac620000), 3, 20 }, + { lexbor_uint64_hl(0x813f3978, 0xf8940984), 30, 28 }, + { lexbor_uint64_hl(0xc097ce7b, 0xc90715b3), 56, 36 }, + { lexbor_uint64_hl(0x8f7e32ce, 0x7bea5c70), 83, 44 }, + { lexbor_uint64_hl(0xd5d238a4, 0xabe98068), 109, 52 }, + { lexbor_uint64_hl(0x9f4f2726, 0x179a2245), 136, 60 }, + { lexbor_uint64_hl(0xed63a231, 0xd4c4fb27), 162, 68 }, + { lexbor_uint64_hl(0xb0de6538, 0x8cc8ada8), 189, 76 }, + { lexbor_uint64_hl(0x83c7088e, 0x1aab65db), 216, 84 }, + { lexbor_uint64_hl(0xc45d1df9, 0x42711d9a), 242, 92 }, + { lexbor_uint64_hl(0x924d692c, 0xa61be758), 269, 100 }, + { lexbor_uint64_hl(0xda01ee64, 0x1a708dea), 295, 108 }, + { lexbor_uint64_hl(0xa26da399, 0x9aef774a), 322, 116 }, + { lexbor_uint64_hl(0xf209787b, 0xb47d6b85), 348, 124 }, + { lexbor_uint64_hl(0xb454e4a1, 0x79dd1877), 375, 132 }, + { lexbor_uint64_hl(0x865b8692, 0x5b9bc5c2), 402, 140 }, + { lexbor_uint64_hl(0xc83553c5, 0xc8965d3d), 428, 148 }, + { lexbor_uint64_hl(0x952ab45c, 0xfa97a0b3), 455, 156 }, + { lexbor_uint64_hl(0xde469fbd, 0x99a05fe3), 481, 164 }, + { lexbor_uint64_hl(0xa59bc234, 0xdb398c25), 508, 172 }, + { lexbor_uint64_hl(0xf6c69a72, 0xa3989f5c), 534, 180 }, + { lexbor_uint64_hl(0xb7dcbf53, 0x54e9bece), 561, 188 }, + { lexbor_uint64_hl(0x88fcf317, 0xf22241e2), 588, 196 }, + { lexbor_uint64_hl(0xcc20ce9b, 0xd35c78a5), 614, 204 }, + { lexbor_uint64_hl(0x98165af3, 0x7b2153df), 641, 212 }, + { lexbor_uint64_hl(0xe2a0b5dc, 0x971f303a), 667, 220 }, + { lexbor_uint64_hl(0xa8d9d153, 0x5ce3b396), 694, 228 }, + { lexbor_uint64_hl(0xfb9b7cd9, 0xa4a7443c), 720, 236 }, + { lexbor_uint64_hl(0xbb764c4c, 0xa7a44410), 747, 244 }, + { lexbor_uint64_hl(0x8bab8eef, 0xb6409c1a), 774, 252 }, + { lexbor_uint64_hl(0xd01fef10, 0xa657842c), 800, 260 }, + { lexbor_uint64_hl(0x9b10a4e5, 0xe9913129), 827, 268 }, + { lexbor_uint64_hl(0xe7109bfb, 0xa19c0c9d), 853, 276 }, + { lexbor_uint64_hl(0xac2820d9, 0x623bf429), 880, 284 }, + { lexbor_uint64_hl(0x80444b5e, 0x7aa7cf85), 907, 292 }, + { lexbor_uint64_hl(0xbf21e440, 0x03acdd2d), 933, 300 }, + { lexbor_uint64_hl(0x8e679c2f, 0x5e44ff8f), 960, 308 }, + { lexbor_uint64_hl(0xd433179d, 0x9c8cb841), 986, 316 }, + { lexbor_uint64_hl(0x9e19db92, 0xb4e31ba9), 1013, 324 }, + { lexbor_uint64_hl(0xeb96bf6e, 0xbadf77d9), 1039, 332 }, + { lexbor_uint64_hl(0xaf87023b, 0x9bf0ee6b), 1066, 340 }, +}; + + +#define LEXBOR_DIYFP_D_1_LOG2_10 0.30102999566398114 /* 1 / log2(10). */ + + +lexbor_diyfp_t +lexbor_cached_power_dec(int exp, int *dec_exp) +{ + unsigned int index; + const lexbor_diyfp_cpe_t *cp; + + index = (exp + LEXBOR_DECIMAL_EXPONENT_OFF) / LEXBOR_DECIMAL_EXPONENT_DIST; + cp = &lexbor_cached_powers[index]; + + *dec_exp = cp->dec_exp; + + return lexbor_diyfp(cp->significand, cp->bin_exp); +} + +lexbor_diyfp_t +lexbor_cached_power_bin(int exp, int *dec_exp) +{ + int k; + unsigned int index; + const lexbor_diyfp_cpe_t *cp; + + k = (int) ceil((-61 - exp) * LEXBOR_DIYFP_D_1_LOG2_10) + + LEXBOR_DECIMAL_EXPONENT_OFF - 1; + + index = (unsigned) (k >> 3) + 1; + + cp = &lexbor_cached_powers[index]; + + *dec_exp = -(LEXBOR_DECIMAL_EXPONENT_MIN + (int) (index << 3)); + + return lexbor_diyfp(cp->significand, cp->bin_exp); +} + + +#undef LEXBOR_DIYFP_D_1_LOG2_10 diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/diyfp.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/diyfp.h new file mode 100644 index 0000000..86c5336 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/diyfp.h @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2015-2019 NGINX, Inc. + * Copyright (C) 2019-2025 F5, Inc. + * Copyright (C) 2015-2021 Igor Sysoev + * Copyright (C) 2017-2025 Dmitry Volyntsev + * Copyright (C) 2019-2022 Alexander Borisov + * Copyright (C) 2022-2025 Vadim Zhestikov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) Alexander Borisov + * + * Based on nxt_diyfp.h from NGINX NJS project + * An internal diy_fp implementation. + * For details, see Loitsch, Florian. "Printing floating-point numbers quickly + * and accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243. + */ + +#ifndef LEXBOR_DIYFP_H +#define LEXBOR_DIYFP_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + +#include + + +#ifdef __cplusplus +#define lexbor_diyfp(_s, _e) { .significand = (_s), .exp = (int) (_e) } +#else +#define lexbor_diyfp(_s, _e) (lexbor_diyfp_t) \ + { .significand = (_s), .exp = (int) (_e) } +#endif +#define lexbor_uint64_hl(h, l) (((uint64_t) (h) << 32) + (l)) + + +#define LEXBOR_DBL_SIGNIFICAND_SIZE 52 +#define LEXBOR_DBL_EXPONENT_BIAS (0x3FF + LEXBOR_DBL_SIGNIFICAND_SIZE) +#define LEXBOR_DBL_EXPONENT_MIN (-LEXBOR_DBL_EXPONENT_BIAS) +#define LEXBOR_DBL_EXPONENT_MAX (0x7FF - LEXBOR_DBL_EXPONENT_BIAS) +#define LEXBOR_DBL_EXPONENT_DENORMAL (-LEXBOR_DBL_EXPONENT_BIAS + 1) + +#define LEXBOR_DBL_SIGNIFICAND_MASK lexbor_uint64_hl(0x000FFFFF, 0xFFFFFFFF) +#define LEXBOR_DBL_HIDDEN_BIT lexbor_uint64_hl(0x00100000, 0x00000000) +#define LEXBOR_DBL_EXPONENT_MASK lexbor_uint64_hl(0x7FF00000, 0x00000000) + +#define LEXBOR_DIYFP_SIGNIFICAND_SIZE 64 + +#define LEXBOR_SIGNIFICAND_SIZE 53 +#define LEXBOR_SIGNIFICAND_SHIFT (LEXBOR_DIYFP_SIGNIFICAND_SIZE \ + - LEXBOR_DBL_SIGNIFICAND_SIZE) + +#define LEXBOR_DECIMAL_EXPONENT_OFF 348 +#define LEXBOR_DECIMAL_EXPONENT_MIN (-348) +#define LEXBOR_DECIMAL_EXPONENT_MAX 340 +#define LEXBOR_DECIMAL_EXPONENT_DIST 8 + + +typedef struct { + uint64_t significand; + int exp; +} +lexbor_diyfp_t; + + +LXB_API lexbor_diyfp_t +lexbor_cached_power_dec(int exp, int *dec_exp); + +LXB_API lexbor_diyfp_t +lexbor_cached_power_bin(int exp, int *dec_exp); + + +/* + * Inline functions + */ +#ifdef LEXBOR_HAVE_BUILTIN_CLZLL +#define nxt_leading_zeros64(x) (((x) == 0) ? 64 : __builtin_clzll(x)) + +#else + +lxb_inline uint64_t +lexbor_diyfp_leading_zeros64(uint64_t x) +{ + uint64_t n; + + if (x == 0) { + return 64; + } + + n = 0; + + while ((x & 0x8000000000000000) == 0) { + n++; + x <<= 1; + } + + return n; +} + +#endif + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_from_d2(double d) +{ + int biased_exp; + uint64_t significand; + lexbor_diyfp_t r; + + union { + double d; + uint64_t u64; + } + u; + + u.d = d; + + biased_exp = (u.u64 & LEXBOR_DBL_EXPONENT_MASK) + >> LEXBOR_DBL_SIGNIFICAND_SIZE; + significand = u.u64 & LEXBOR_DBL_SIGNIFICAND_MASK; + + if (biased_exp != 0) { + r.significand = significand + LEXBOR_DBL_HIDDEN_BIT; + r.exp = biased_exp - LEXBOR_DBL_EXPONENT_BIAS; + } + else { + r.significand = significand; + r.exp = LEXBOR_DBL_EXPONENT_MIN + 1; + } + + return r; +} + +lxb_inline double +lexbor_diyfp_2d(lexbor_diyfp_t v) +{ + int exp; + uint64_t significand, biased_exp; + + union { + double d; + uint64_t u64; + } + u; + + exp = v.exp; + significand = v.significand; + + while (significand > LEXBOR_DBL_HIDDEN_BIT + LEXBOR_DBL_SIGNIFICAND_MASK) { + significand >>= 1; + exp++; + } + + if (exp >= LEXBOR_DBL_EXPONENT_MAX) { + return INFINITY; + } + + if (exp < LEXBOR_DBL_EXPONENT_DENORMAL) { + return 0.0; + } + + while (exp > LEXBOR_DBL_EXPONENT_DENORMAL + && (significand & LEXBOR_DBL_HIDDEN_BIT) == 0) + { + significand <<= 1; + exp--; + } + + if (exp == LEXBOR_DBL_EXPONENT_DENORMAL + && (significand & LEXBOR_DBL_HIDDEN_BIT) == 0) + { + biased_exp = 0; + + } else { + biased_exp = (uint64_t) (exp + LEXBOR_DBL_EXPONENT_BIAS); + } + + u.u64 = (significand & LEXBOR_DBL_SIGNIFICAND_MASK) + | (biased_exp << LEXBOR_DBL_SIGNIFICAND_SIZE); + + return u.d; +} + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_shift_left(lexbor_diyfp_t v, unsigned shift) +{ + return lexbor_diyfp(v.significand << shift, v.exp - shift); +} + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_shift_right(lexbor_diyfp_t v, unsigned shift) +{ + return lexbor_diyfp(v.significand >> shift, v.exp + shift); +} + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_sub(lexbor_diyfp_t lhs, lexbor_diyfp_t rhs) +{ + return lexbor_diyfp(lhs.significand - rhs.significand, lhs.exp); +} + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_mul(lexbor_diyfp_t lhs, lexbor_diyfp_t rhs) +{ +#ifdef LEXBOR_HAVE_UNSIGNED_INT128 + + uint64_t l, h; + lxb_uint128_t u128; + + u128 = (lxb_uint128_t) (lhs.significand) + * (lxb_uint128_t) (rhs.significand); + + h = u128 >> 64; + l = (uint64_t) u128; + + /* rounding. */ + + if (l & ((uint64_t) 1 << 63)) { + h++; + } + + return lexbor_diyfp(h, lhs.exp + rhs.exp + 64); + +#else + + uint64_t a, b, c, d, ac, bc, ad, bd, tmp; + + a = lhs.significand >> 32; + b = lhs.significand & 0xffffffff; + c = rhs.significand >> 32; + d = rhs.significand & 0xffffffff; + + ac = a * c; + bc = b * c; + ad = a * d; + bd = b * d; + + tmp = (bd >> 32) + (ad & 0xffffffff) + (bc & 0xffffffff); + + /* mult_round. */ + + tmp += 1U << 31; + + return lexbor_diyfp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), + lhs.exp + rhs.exp + 64); +#endif +} + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_normalize(lexbor_diyfp_t v) +{ + return lexbor_diyfp_shift_left(v, + (unsigned) lexbor_diyfp_leading_zeros64(v.significand)); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_DIYFP_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dobject.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dobject.c new file mode 100644 index 0000000..0f5468f --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dobject.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2018-2019 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/dobject.h" + + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + #include +#endif + + +lexbor_dobject_t * +lexbor_dobject_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_dobject_t)); +} + +lxb_status_t +lexbor_dobject_init(lexbor_dobject_t *dobject, + size_t chunk_size, size_t struct_size) +{ + lxb_status_t status; + + if (dobject == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (chunk_size == 0 || struct_size == 0) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + /* Set params */ + dobject->allocated = 0UL; + dobject->struct_size = struct_size; + + /* Init memory */ + dobject->mem = lexbor_mem_create(); + + status = lexbor_mem_init(dobject->mem, + lexbor_mem_align(chunk_size * dobject->struct_size)); + if (status) { + return status; + } + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(dobject->mem->chunk->data, + dobject->mem->chunk->size); +#endif + + /* Array */ + dobject->cache = lexbor_array_create(); + + status = lexbor_array_init(dobject->cache, chunk_size); + if (status) + return status; + + return LXB_STATUS_OK; +} + +void +lexbor_dobject_clean(lexbor_dobject_t *dobject) +{ + if (dobject != NULL) { + dobject->allocated = 0UL; + + lexbor_mem_clean(dobject->mem); + lexbor_array_clean(dobject->cache); + } +} + +lexbor_dobject_t * +lexbor_dobject_destroy(lexbor_dobject_t *dobject, bool destroy_self) +{ + if (dobject == NULL) + return NULL; + + dobject->mem = lexbor_mem_destroy(dobject->mem, true); + dobject->cache = lexbor_array_destroy(dobject->cache, true); + + if (destroy_self == true) { + return lexbor_free(dobject); + } + + return dobject; +} + +void * +lexbor_dobject_alloc(lexbor_dobject_t *dobject) +{ + void *data; + + if (lexbor_array_length(dobject->cache) != 0) { + dobject->allocated++; + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + data = lexbor_array_pop(dobject->cache); + ASAN_UNPOISON_MEMORY_REGION(data, dobject->struct_size); + + return data; +#else + return lexbor_array_pop(dobject->cache); +#endif + } + + data = lexbor_mem_alloc(dobject->mem, dobject->struct_size); + if (data == NULL) { + return NULL; + } + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_UNPOISON_MEMORY_REGION(data, dobject->struct_size); +#endif + + dobject->allocated++; + + return data; +} + +void * +lexbor_dobject_calloc(lexbor_dobject_t *dobject) +{ + void *data = lexbor_dobject_alloc(dobject); + + if (data != NULL) { + memset(data, 0, dobject->struct_size); + } + + return data; +} + +void * +lexbor_dobject_free(lexbor_dobject_t *dobject, void *data) +{ + if (data == NULL) { + return NULL; + } + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(data, dobject->struct_size); +#endif + + if (lexbor_array_push(dobject->cache, data) == LXB_STATUS_OK) { + dobject->allocated--; + return NULL; + } + + return data; +} + +void * +lexbor_dobject_by_absolute_position(lexbor_dobject_t *dobject, size_t pos) +{ + size_t chunk_idx, chunk_pos, i; + lexbor_mem_chunk_t *chunk; + + if (pos >= dobject->allocated) { + return NULL; + } + + chunk = dobject->mem->chunk_first; + chunk_pos = pos * dobject->struct_size; + chunk_idx = chunk_pos / dobject->mem->chunk_min_size; + + for (i = 0; i < chunk_idx; i++) { + chunk = chunk->next; + } + + return &chunk->data[chunk_pos % chunk->size]; +} + +/* + * No inline functions for ABI. + */ +size_t +lexbor_dobject_allocated_noi(lexbor_dobject_t *dobject) +{ + return lexbor_dobject_allocated(dobject); +} + +size_t +lexbor_dobject_cache_length_noi(lexbor_dobject_t *dobject) +{ + return lexbor_dobject_cache_length(dobject); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dobject.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dobject.h new file mode 100644 index 0000000..69497fd --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dobject.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_DOBJECT_H +#define LEXBOR_DOBJECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" +#include "lexbor/core/mem.h" +#include "lexbor/core/array.h" + + +typedef struct { + lexbor_mem_t *mem; + lexbor_array_t *cache; + + size_t allocated; + size_t struct_size; +} +lexbor_dobject_t; + + +LXB_API lexbor_dobject_t * +lexbor_dobject_create(void); + +LXB_API lxb_status_t +lexbor_dobject_init(lexbor_dobject_t *dobject, + size_t chunk_size, size_t struct_size); + +LXB_API void +lexbor_dobject_clean(lexbor_dobject_t *dobject); + +LXB_API lexbor_dobject_t * +lexbor_dobject_destroy(lexbor_dobject_t *dobject, bool destroy_self); + + +LXB_API void * +lexbor_dobject_alloc(lexbor_dobject_t *dobject); + +LXB_API void * +lexbor_dobject_calloc(lexbor_dobject_t *dobject); + +LXB_API void * +lexbor_dobject_free(lexbor_dobject_t *dobject, void *data); + + +LXB_API void * +lexbor_dobject_by_absolute_position(lexbor_dobject_t *dobject, size_t pos); + + +/* + * Inline functions + */ +lxb_inline size_t +lexbor_dobject_allocated(lexbor_dobject_t *dobject) +{ + return dobject->allocated; +} + +lxb_inline size_t +lexbor_dobject_cache_length(lexbor_dobject_t *dobject) +{ + return lexbor_array_length(dobject->cache); +} + +/* + * No inline functions for ABI. + */ +LXB_API size_t +lexbor_dobject_allocated_noi(lexbor_dobject_t *dobject); + +LXB_API size_t +lexbor_dobject_cache_length_noi(lexbor_dobject_t *dobject); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_DOBJECT_H */ + + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dtoa.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dtoa.c new file mode 100644 index 0000000..7da7ce0 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dtoa.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2015-2019 NGINX, Inc. + * Copyright (C) 2019-2025 F5, Inc. + * Copyright (C) 2015-2021 Igor Sysoev + * Copyright (C) 2017-2025 Dmitry Volyntsev + * Copyright (C) 2019-2022 Alexander Borisov + * Copyright (C) 2022-2025 Vadim Zhestikov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) Alexander Borisov + */ + +#include "lexbor/core/str.h" +#include "lexbor/core/diyfp.h" +#include "lexbor/core/dtoa.h" + +#include +#include + + +lxb_inline void +lexbor_grisu2_round(lxb_char_t *start, size_t len, uint64_t delta, uint64_t rest, + uint64_t ten_kappa, uint64_t wp_w) +{ + while (rest < wp_w && delta - rest >= ten_kappa + && (rest + ten_kappa < wp_w || /* closer */ + wp_w - rest > rest + ten_kappa - wp_w)) + { + start[len - 1]--; + rest += ten_kappa; + } +} + +lxb_inline int +lexbor_dec_count(uint32_t n) +{ + if (n < 10) return 1; + if (n < 100) return 2; + if (n < 1000) return 3; + if (n < 10000) return 4; + if (n < 100000) return 5; + if (n < 1000000) return 6; + if (n < 10000000) return 7; + if (n < 100000000) return 8; + if (n < 1000000000) return 9; + + return 10; +} + +lxb_inline size_t +lexbor_grisu2_gen(lexbor_diyfp_t W, lexbor_diyfp_t Mp, uint64_t delta, + lxb_char_t *begin, lxb_char_t *end, int *dec_exp) +{ + int kappa; + lxb_char_t c, *p; + uint32_t p1, d; + uint64_t p2, tmp; + lexbor_diyfp_t one, wp_w; + + static const uint64_t pow10[] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000 + }; + + wp_w = lexbor_diyfp_sub(Mp, W); + + one = lexbor_diyfp((uint64_t) 1 << -Mp.exp, Mp.exp); + p1 = (uint32_t) (Mp.significand >> -one.exp); + p2 = Mp.significand & (one.significand - 1); + + p = begin; + + /* GCC 4.2 complains about uninitialized d. */ + d = 0; + + kappa = lexbor_dec_count(p1); + + while (kappa > 0) { + switch (kappa) { + case 10: d = p1 / 1000000000; p1 %= 1000000000; break; + case 9: d = p1 / 100000000; p1 %= 100000000; break; + case 8: d = p1 / 10000000; p1 %= 10000000; break; + case 7: d = p1 / 1000000; p1 %= 1000000; break; + case 6: d = p1 / 100000; p1 %= 100000; break; + case 5: d = p1 / 10000; p1 %= 10000; break; + case 4: d = p1 / 1000; p1 %= 1000; break; + case 3: d = p1 / 100; p1 %= 100; break; + case 2: d = p1 / 10; p1 %= 10; break; + case 1: d = p1; p1 = 0; break; + default: + /* Never go here. */ + return 0; + } + + if (d != 0 || p != begin) { + *p = '0' + d; + + p += 1; + if (p == end) { + return p - begin; + } + } + + kappa--; + + tmp = ((uint64_t) p1 << -one.exp) + p2; + + if (tmp <= delta) { + *dec_exp += kappa; + lexbor_grisu2_round(begin, p - begin, delta, tmp, + pow10[kappa] << -one.exp, wp_w.significand); + return p - begin; + } + } + + /* kappa = 0. */ + + for ( ;; ) { + p2 *= 10; + delta *= 10; + c = (char) (p2 >> -one.exp); + + if (c != 0 || p != begin) { + *p = '0' + c; + + p += 1; + if (p == end) { + return p - begin; + } + } + + p2 &= one.significand - 1; + kappa--; + + if (p2 < delta) { + *dec_exp += kappa; + tmp = (-kappa < 10) ? pow10[-kappa] : 0; + lexbor_grisu2_round(begin, p - begin, delta, p2, one.significand, + wp_w.significand * tmp); + break; + } + } + + return p - begin; +} + +lxb_inline lexbor_diyfp_t +lexbor_diyfp_normalize_boundary(lexbor_diyfp_t v) +{ + while ((v.significand & (LEXBOR_DBL_HIDDEN_BIT << 1)) == 0) { + v.significand <<= 1; + v.exp--; + } + + return lexbor_diyfp_shift_left(v, LEXBOR_SIGNIFICAND_SHIFT - 2); +} + +lxb_inline void +lexbor_diyfp_normalize_boundaries(lexbor_diyfp_t v, lexbor_diyfp_t* minus, + lexbor_diyfp_t* plus) +{ + lexbor_diyfp_t pl, mi; + + pl = lexbor_diyfp_normalize_boundary(lexbor_diyfp((v.significand << 1) + 1, + v.exp - 1)); + + if (v.significand == LEXBOR_DBL_HIDDEN_BIT) { + mi = lexbor_diyfp((v.significand << 2) - 1, v.exp - 2); + + } else { + mi = lexbor_diyfp((v.significand << 1) - 1, v.exp - 1); + } + + mi.significand <<= mi.exp - pl.exp; + mi.exp = pl.exp; + + *plus = pl; + *minus = mi; +} + +lxb_inline size_t +lexbor_grisu2(double value, lxb_char_t *begin, lxb_char_t *end, int *dec_exp) +{ + lexbor_diyfp_t v, w_m, w_p, c_mk, W, Wp, Wm; + + v = lexbor_diyfp_from_d2(value); + + lexbor_diyfp_normalize_boundaries(v, &w_m, &w_p); + + c_mk = lexbor_cached_power_bin(w_p.exp, dec_exp); + W = lexbor_diyfp_mul(lexbor_diyfp_normalize(v), c_mk); + + Wp = lexbor_diyfp_mul(w_p, c_mk); + Wm = lexbor_diyfp_mul(w_m, c_mk); + + Wm.significand++; + Wp.significand--; + + return lexbor_grisu2_gen(W, Wp, Wp.significand - Wm.significand, begin, end, + dec_exp); +} + +lxb_inline size_t +lexbor_write_exponent(int exp, lxb_char_t *begin, lxb_char_t *end) +{ + char *p; + size_t len; + uint32_t u32; + char buf[4]; + + /* -324 <= exp <= 308. */ + + if ((begin + (sizeof(buf) - 1) + 1) >= end) { + return 0; + } + + if (exp < 0) { + *begin = '-'; + begin += 1; + + exp = -exp; + } + else { + *begin++ = '+'; + } + + u32 = exp; + p = buf + (sizeof(buf) - 1); + + do { + *--p = u32 % 10 + '0'; + u32 /= 10; + } + while (u32 != 0); + + len = buf + (sizeof(buf) - 1) - p; + + memcpy(begin, p, len); + + return len + 1; +} + +lxb_inline size_t +lexbor_prettify(lxb_char_t *begin, lxb_char_t *end, size_t len, int dec_exp) +{ + int kk, offset, length; + size_t size; + + /* 10^(kk-1) <= v < 10^kk */ + + length = (int) len; + kk = length + dec_exp; + + if (length <= kk && kk <= 21) { + /* 1234e7 -> 12340000000 */ + + if (kk - length > 0) { + if ((&begin[length] + (kk - length)) < end) { + memset(&begin[length], '0', kk - length); + } + else { + memset(&begin[length], '0', (end - &begin[length])); + } + } + + return kk; + } + else if (0 < kk && kk <= 21) { + /* 1234e-2 -> 12.34 */ + + if ((&begin[kk + 1] + (length - kk)) >= end) { + return length; + } + + memmove(&begin[kk + 1], &begin[kk], length - kk); + begin[kk] = '.'; + + return (length + 1); + } + else if (-6 < kk && kk <= 0) { + /* 1234e-6 -> 0.001234 */ + + offset = 2 - kk; + if ((&begin[offset] + length) >= end + || (begin + 2) >= end) + { + return length; + } + + memmove(&begin[offset], begin, length); + begin[0] = '0'; + begin[1] = '.'; + + if (offset - 2 > 0) { + if ((&begin[2] + (offset - 2)) >= end) { + return length; + } + + memset(&begin[2], '0', offset - 2); + } + + return (length + offset); + } + else if (length == 1) { + /* 1e30 */ + + if ((begin + 1) >= end) { + return length; + } + + begin[1] = 'e'; + + size = lexbor_write_exponent(kk - 1, &begin[2], end); + + return (size + 2); + } + + /* 1234e30 -> 1.234e33 */ + + if ((&begin[2] + (length - 1)) >= end) { + return length; + } + + memmove(&begin[2], &begin[1], length - 1); + begin[1] = '.'; + begin[length + 1] = 'e'; + + size = lexbor_write_exponent(kk - 1, &begin[length + 2], end); + + return (size + length + 2); +} + +size_t +lexbor_dtoa(double value, lxb_char_t *begin, size_t len) +{ + int dec_exp, minus; + size_t length; + lxb_char_t *end = begin + len; + + if (len == 0) { + return 0; + } + + /* Not handling NaN and inf. */ + + minus = 0; + + if (value == 0) { + *begin = '0'; + + return 1; + } + + if (signbit(value)) { + *begin = '-'; + + begin += 1; + if (begin == end) { + return 1; + } + + value = -value; + minus = 1; + } + + length = lexbor_grisu2(value, begin, end, &dec_exp); + length = lexbor_prettify(begin, end, length, dec_exp); + + return (minus + length); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dtoa.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dtoa.h new file mode 100644 index 0000000..2d569cf --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/dtoa.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015-2019 NGINX, Inc. + * Copyright (C) 2019-2025 F5, Inc. + * Copyright (C) 2015-2021 Igor Sysoev + * Copyright (C) 2017-2025 Dmitry Volyntsev + * Copyright (C) 2019-2022 Alexander Borisov + * Copyright (C) 2022-2025 Vadim Zhestikov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) Alexander Borisov + */ + +#ifndef LEXBOR_DTOA_H +#define LEXBOR_DTOA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +LXB_API size_t +lexbor_dtoa(double value, lxb_char_t *begin, size_t len); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_DTOA_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/fs.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/fs.h new file mode 100644 index 0000000..1b64c6d --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/fs.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_FS_H +#define LEXBOR_FS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +typedef lexbor_action_t (*lexbor_fs_dir_file_f)(const lxb_char_t *fullpath, + size_t fullpath_len, + const lxb_char_t *filename, + size_t filename_len, void *ctx); + +typedef int lexbor_fs_dir_opt_t; + +enum lexbor_fs_dir_opt { + LEXBOR_FS_DIR_OPT_UNDEF = 0x00, + LEXBOR_FS_DIR_OPT_WITHOUT_DIR = 0x01, + LEXBOR_FS_DIR_OPT_WITHOUT_FILE = 0x02, + LEXBOR_FS_DIR_OPT_WITHOUT_HIDDEN = 0x04, +}; + +typedef enum { + LEXBOR_FS_FILE_TYPE_UNDEF = 0x00, + LEXBOR_FS_FILE_TYPE_FILE = 0x01, + LEXBOR_FS_FILE_TYPE_DIRECTORY = 0x02, + LEXBOR_FS_FILE_TYPE_BLOCK_DEVICE = 0x03, + LEXBOR_FS_FILE_TYPE_CHARACTER_DEVICE = 0x04, + LEXBOR_FS_FILE_TYPE_PIPE = 0x05, + LEXBOR_FS_FILE_TYPE_SYMLINK = 0x06, + LEXBOR_FS_FILE_TYPE_SOCKET = 0x07 +} +lexbor_fs_file_type_t; + + +LXB_API lxb_status_t +lexbor_fs_dir_read(const lxb_char_t *dirpath, lexbor_fs_dir_opt_t opt, + lexbor_fs_dir_file_f callback, void *ctx); + +LXB_API lexbor_fs_file_type_t +lexbor_fs_file_type(const lxb_char_t *full_path); + +LXB_API lxb_char_t * +lexbor_fs_file_easy_read(const lxb_char_t *full_path, size_t *len); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_FS_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/hash.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/hash.c new file mode 100644 index 0000000..c16466e --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/hash.c @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2019-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#define LEXBOR_HASH_EXTERN +#include "lexbor/core/hash.h" +#undef LEXBOR_HASH_EXTERN + +#include "lexbor/core/str.h" + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_map_lowercase[256]; + LXB_EXTERN const lxb_char_t lexbor_str_res_map_uppercase[256]; +#endif + + +/* Insert variable. */ +const lexbor_hash_insert_t lexbor_hash_insert_var = { + .hash = lexbor_hash_make_id, + .copy = lexbor_hash_copy, + .cmp = lexbor_str_data_ncmp +}; + +const lexbor_hash_insert_t lexbor_hash_insert_lower_var = { + .hash = lexbor_hash_make_id_lower, + .copy = lexbor_hash_copy_lower, + .cmp = lexbor_str_data_nlocmp_right +}; + +const lexbor_hash_insert_t lexbor_hash_insert_upper_var = { + .hash = lexbor_hash_make_id_upper, + .copy = lexbor_hash_copy_upper, + .cmp = lexbor_str_data_nupcmp_right +}; + +LXB_API const lexbor_hash_insert_t +*lexbor_hash_insert_raw = &lexbor_hash_insert_var; + +LXB_API const lexbor_hash_insert_t +*lexbor_hash_insert_lower = &lexbor_hash_insert_lower_var; + +LXB_API const lexbor_hash_insert_t +*lexbor_hash_insert_upper = &lexbor_hash_insert_upper_var; + +/* Search variable. */ +const lexbor_hash_search_t lexbor_hash_search_var = { + .hash = lexbor_hash_make_id, + .cmp = lexbor_str_data_ncmp +}; + +const lexbor_hash_search_t lexbor_hash_search_lower_var = { + .hash = lexbor_hash_make_id_lower, + .cmp = lexbor_str_data_nlocmp_right +}; + +const lexbor_hash_search_t lexbor_hash_search_upper_var = { + .hash = lexbor_hash_make_id_upper, + .cmp = lexbor_str_data_nupcmp_right +}; + +LXB_API const lexbor_hash_search_t +*lexbor_hash_search_raw = &lexbor_hash_search_var; + +LXB_API const lexbor_hash_search_t +*lexbor_hash_search_lower = &lexbor_hash_search_lower_var; + +LXB_API const lexbor_hash_search_t +*lexbor_hash_search_upper = &lexbor_hash_search_upper_var; + + +lxb_inline lexbor_hash_entry_t ** +lexbor_hash_table_create(lexbor_hash_t *hash) +{ + return lexbor_calloc(hash->table_size, sizeof(lexbor_hash_entry_t *)); +} + +lxb_inline void +lexbor_hash_table_clean(lexbor_hash_t *hash) +{ + memset(hash->table, 0, sizeof(lexbor_hash_t *) * hash->table_size); +} + +lxb_inline lexbor_hash_entry_t ** +lexbor_hash_table_destroy(lexbor_hash_t *hash) +{ + if (hash->table != NULL) { + return lexbor_free(hash->table); + } + + return NULL; +} + +lxb_inline lexbor_hash_entry_t * +_lexbor_hash_entry_create(lexbor_hash_t *hash, const lexbor_hash_copy_f copy_func, + const lxb_char_t *key, size_t length) +{ + lexbor_hash_entry_t *entry = lexbor_dobject_calloc(hash->entries); + if (entry == NULL) { + return NULL; + } + + entry->length = length; + + if (copy_func(hash, entry, key, length) != LXB_STATUS_OK) { + lexbor_dobject_free(hash->entries, entry); + return NULL; + } + + return entry; +} + +lexbor_hash_t * +lexbor_hash_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_hash_t)); +} + +lxb_status_t +lexbor_hash_init(lexbor_hash_t *hash, size_t table_size, size_t struct_size) +{ + lxb_status_t status; + size_t chunk_size; + + if (hash == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (table_size < LEXBOR_HASH_TABLE_MIN_SIZE) { + table_size = LEXBOR_HASH_TABLE_MIN_SIZE; + } + + chunk_size = table_size / 2; + + hash->table_size = table_size; + + hash->entries = lexbor_dobject_create(); + status = lexbor_dobject_init(hash->entries, chunk_size, struct_size); + if (status != LXB_STATUS_OK) { + return status; + } + + hash->mraw = lexbor_mraw_create(); + status = lexbor_mraw_init(hash->mraw, chunk_size * 12); + if (status != LXB_STATUS_OK) { + return status; + } + + hash->table = lexbor_hash_table_create(hash); + if (hash->table == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + hash->struct_size = struct_size; + + return LXB_STATUS_OK; +} + +void +lexbor_hash_clean(lexbor_hash_t *hash) +{ + lexbor_dobject_clean(hash->entries); + lexbor_mraw_clean(hash->mraw); + lexbor_hash_table_clean(hash); +} + +lexbor_hash_t * +lexbor_hash_destroy(lexbor_hash_t *hash, bool destroy_obj) +{ + if (hash == NULL) { + return NULL; + } + + hash->entries = lexbor_dobject_destroy(hash->entries, true); + hash->mraw = lexbor_mraw_destroy(hash->mraw, true); + hash->table = lexbor_hash_table_destroy(hash); + + if (destroy_obj) { + return lexbor_free(hash); + } + + return hash; +} + +void * +lexbor_hash_insert(lexbor_hash_t *hash, const lexbor_hash_insert_t *insert, + const lxb_char_t *key, size_t length) +{ + lxb_char_t *str; + uint32_t hash_id, table_idx; + lexbor_hash_entry_t *entry; + + hash_id = insert->hash(key, length); + table_idx = hash_id % hash->table_size; + + entry = hash->table[table_idx]; + + if (entry == NULL) { + entry = _lexbor_hash_entry_create(hash, insert->copy, key, length); + hash->table[table_idx] = entry; + + return entry; + } + + do { + str = lexbor_hash_entry_str(entry); + + if (entry->length == length && insert->cmp(str, key, length)) { + return entry; + } + + if (entry->next == NULL) { + break; + } + + entry = entry->next; + } + while (1); + + entry->next = _lexbor_hash_entry_create(hash, insert->copy, key, length); + + return entry->next; +} + +void * +lexbor_hash_insert_by_entry(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lexbor_hash_search_t *search, + const lxb_char_t *key, size_t length) +{ + lxb_char_t *str; + uint32_t hash_id, table_idx; + lexbor_hash_entry_t *item; + + hash_id = search->hash(key, length); + table_idx = hash_id % hash->table_size; + + item = hash->table[table_idx]; + + if (item == NULL) { + hash->table[table_idx] = entry; + + return entry; + } + + do { + str = lexbor_hash_entry_str(item); + + if (item->length == length && search->cmp(str, key, length)) { + return item; + } + + if (item->next == NULL) { + break; + } + + item = item->next; + } + while (1); + + item->next = entry; + + return entry; +} + +void +lexbor_hash_remove(lexbor_hash_t *hash, const lexbor_hash_search_t *search, + const lxb_char_t *key, size_t length) +{ + lexbor_hash_remove_by_hash_id(hash, search->hash(key, length), + key, length, search->cmp); +} + +void * +lexbor_hash_search(lexbor_hash_t *hash, const lexbor_hash_search_t *search, + const lxb_char_t *key, size_t length) +{ + return lexbor_hash_search_by_hash_id(hash, search->hash(key, length), + key, length, search->cmp); +} + +void +lexbor_hash_remove_by_hash_id(lexbor_hash_t *hash, uint32_t hash_id, + const lxb_char_t *key, size_t length, + const lexbor_hash_cmp_f cmp_func) +{ + uint32_t table_idx; + lxb_char_t *str; + lexbor_hash_entry_t *entry, *prev; + + table_idx = hash_id % hash->table_size; + entry = hash->table[table_idx]; + prev = NULL; + + while (entry != NULL) { + str = lexbor_hash_entry_str(entry); + + if (entry->length == length && cmp_func(str, key, length)) { + if (prev == NULL) { + hash->table[table_idx] = entry->next; + } + else { + prev->next = entry->next; + } + + if (length > LEXBOR_HASH_SHORT_SIZE) { + lexbor_mraw_free(hash->mraw, entry->u.long_str); + } + + lexbor_dobject_free(hash->entries, entry); + + return; + } + + prev = entry; + entry = entry->next; + } +} + +void * +lexbor_hash_search_by_hash_id(lexbor_hash_t *hash, uint32_t hash_id, + const lxb_char_t *key, size_t length, + const lexbor_hash_cmp_f cmp_func) +{ + lxb_char_t *str; + lexbor_hash_entry_t *entry; + + entry = hash->table[ hash_id % hash->table_size ]; + + while (entry != NULL) { + str = lexbor_hash_entry_str(entry); + + if (entry->length == length && cmp_func(str, key, length)) { + return entry; + } + + entry = entry->next; + } + + return NULL; +} + +uint32_t +lexbor_hash_make_id(const lxb_char_t *key, size_t length) +{ + size_t i; + uint32_t hash_id; + + for (i = hash_id = 0; i < length; i++) { + hash_id += key[i]; + hash_id += (hash_id << 10); + hash_id ^= (hash_id >> 6); + } + + hash_id += (hash_id << 3); + hash_id ^= (hash_id >> 11); + hash_id += (hash_id << 15); + + return hash_id; +} + +uint32_t +lexbor_hash_make_id_lower(const lxb_char_t *key, size_t length) +{ + size_t i; + uint32_t hash_id; + + for (i = hash_id = 0; i < length; i++) { + hash_id += lexbor_str_res_map_lowercase[ key[i] ]; + hash_id += (hash_id << 10); + hash_id ^= (hash_id >> 6); + } + + hash_id += (hash_id << 3); + hash_id ^= (hash_id >> 11); + hash_id += (hash_id << 15); + + return hash_id; +} + +uint32_t +lexbor_hash_make_id_upper(const lxb_char_t *key, size_t length) +{ + size_t i; + uint32_t hash_id; + + for (i = hash_id = 0; i < length; i++) { + hash_id += lexbor_str_res_map_uppercase[ key[i] ]; + hash_id += (hash_id << 10); + hash_id ^= (hash_id >> 6); + } + + hash_id += (hash_id << 3); + hash_id ^= (hash_id >> 11); + hash_id += (hash_id << 15); + + return hash_id; +} + +lxb_status_t +lexbor_hash_copy(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t length) +{ + lxb_char_t *to; + + if (length <= LEXBOR_HASH_SHORT_SIZE) { + to = entry->u.short_str; + } + else { + entry->u.long_str = lexbor_mraw_alloc(hash->mraw, length + 1); + if (entry->u.long_str == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + to = entry->u.long_str; + } + + memcpy(to, key, length); + + to[length] = '\0'; + + return LXB_STATUS_OK; +} + +lxb_status_t +lexbor_hash_copy_lower(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t length) +{ + lxb_char_t *to; + + if (length <= LEXBOR_HASH_SHORT_SIZE) { + to = entry->u.short_str; + } + else { + entry->u.long_str = lexbor_mraw_alloc(hash->mraw, length + 1); + if (entry->u.long_str == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + to = entry->u.long_str; + } + + for (size_t i = 0; i < length; i++) { + to[i] = lexbor_str_res_map_lowercase[ key[i] ]; + } + + to[length] = '\0'; + + return LXB_STATUS_OK; +} + +lxb_status_t +lexbor_hash_copy_upper(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t length) +{ + lxb_char_t *to; + + if (length <= LEXBOR_HASH_SHORT_SIZE) { + to = entry->u.short_str; + } + else { + entry->u.long_str = lexbor_mraw_alloc(hash->mraw, length + 1); + if (entry->u.long_str == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + to = entry->u.long_str; + } + + for (size_t i = 0; i < length; i++) { + to[i] = lexbor_str_res_map_uppercase[ key[i] ]; + } + + to[length] = '\0'; + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/hash.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/hash.h new file mode 100644 index 0000000..0647617 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/hash.h @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2019 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_HASH_H +#define LEXBOR_HASH_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/dobject.h" +#include "lexbor/core/mraw.h" + + +#define LEXBOR_HASH_SHORT_SIZE 16 +#define LEXBOR_HASH_TABLE_MIN_SIZE 32 + + +typedef struct lexbor_hash_search lexbor_hash_search_t; +typedef struct lexbor_hash_insert lexbor_hash_insert_t; + +#ifndef LEXBOR_HASH_EXTERN +LXB_EXTERN const lexbor_hash_insert_t *lexbor_hash_insert_raw; +LXB_EXTERN const lexbor_hash_insert_t *lexbor_hash_insert_lower; +LXB_EXTERN const lexbor_hash_insert_t *lexbor_hash_insert_upper; + +LXB_EXTERN const lexbor_hash_search_t *lexbor_hash_search_raw; +LXB_EXTERN const lexbor_hash_search_t *lexbor_hash_search_lower; +LXB_EXTERN const lexbor_hash_search_t *lexbor_hash_search_upper; +#endif + +/* + * FIXME: + * It is necessary to add the rebuild of a hash table + * and optimize collisions. + */ + +typedef struct lexbor_hash lexbor_hash_t; +typedef struct lexbor_hash_entry lexbor_hash_entry_t; + +typedef uint32_t +(*lexbor_hash_id_f)(const lxb_char_t *key, size_t size); + +typedef lxb_status_t +(*lexbor_hash_copy_f)(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t size); + +typedef bool +(*lexbor_hash_cmp_f)(const lxb_char_t *first, + const lxb_char_t *second, size_t size); + +struct lexbor_hash_entry { + union { + lxb_char_t *long_str; + lxb_char_t short_str[LEXBOR_HASH_SHORT_SIZE + 1]; + } u; + + size_t length; + + lexbor_hash_entry_t *next; +}; + +struct lexbor_hash { + lexbor_dobject_t *entries; + lexbor_mraw_t *mraw; + + lexbor_hash_entry_t **table; + size_t table_size; + + size_t struct_size; +}; + +struct lexbor_hash_insert { + lexbor_hash_id_f hash; /* For generate a hash id. */ + lexbor_hash_cmp_f cmp; /* For compare key. */ + lexbor_hash_copy_f copy; /* For copy key. */ +}; + +struct lexbor_hash_search { + lexbor_hash_id_f hash; /* For generate a hash id. */ + lexbor_hash_cmp_f cmp; /* For compare key. */ +}; + + +LXB_API lexbor_hash_t * +lexbor_hash_create(void); + +LXB_API lxb_status_t +lexbor_hash_init(lexbor_hash_t *hash, size_t table_size, size_t struct_size); + +LXB_API void +lexbor_hash_clean(lexbor_hash_t *hash); + +LXB_API lexbor_hash_t * +lexbor_hash_destroy(lexbor_hash_t *hash, bool destroy_obj); + + +LXB_API void * +lexbor_hash_insert(lexbor_hash_t *hash, const lexbor_hash_insert_t *insert, + const lxb_char_t *key, size_t length); + +LXB_API void * +lexbor_hash_insert_by_entry(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lexbor_hash_search_t *search, + const lxb_char_t *key, size_t length); + +LXB_API void +lexbor_hash_remove(lexbor_hash_t *hash, const lexbor_hash_search_t *search, + const lxb_char_t *key, size_t length); + +LXB_API void * +lexbor_hash_search(lexbor_hash_t *hash, const lexbor_hash_search_t *search, + const lxb_char_t *key, size_t length); + +LXB_API void +lexbor_hash_remove_by_hash_id(lexbor_hash_t *hash, uint32_t hash_id, + const lxb_char_t *key, size_t length, + const lexbor_hash_cmp_f cmp_func); + +LXB_API void * +lexbor_hash_search_by_hash_id(lexbor_hash_t *hash, uint32_t hash_id, + const lxb_char_t *key, size_t length, + const lexbor_hash_cmp_f cmp_func); + + +LXB_API uint32_t +lexbor_hash_make_id(const lxb_char_t *key, size_t length); + +LXB_API uint32_t +lexbor_hash_make_id_lower(const lxb_char_t *key, size_t length); + +LXB_API uint32_t +lexbor_hash_make_id_upper(const lxb_char_t *key, size_t length); + +LXB_API lxb_status_t +lexbor_hash_copy(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t length); + +LXB_API lxb_status_t +lexbor_hash_copy_lower(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t length); + +LXB_API lxb_status_t +lexbor_hash_copy_upper(lexbor_hash_t *hash, lexbor_hash_entry_t *entry, + const lxb_char_t *key, size_t length); + + +/* + * Inline functions + */ +lxb_inline lexbor_mraw_t * +lexbor_hash_mraw(const lexbor_hash_t *hash) +{ + return hash->mraw; +} + +lxb_inline lxb_char_t * +lexbor_hash_entry_str(const lexbor_hash_entry_t *entry) +{ + if (entry->length <= LEXBOR_HASH_SHORT_SIZE) { + return (lxb_char_t *) entry->u.short_str; + } + + return entry->u.long_str; +} + +lxb_inline lxb_char_t * +lexbor_hash_entry_str_set(lexbor_hash_entry_t *entry, + lxb_char_t *data, size_t length) +{ + entry->length = length; + + if (length <= LEXBOR_HASH_SHORT_SIZE) { + memcpy(entry->u.short_str, data, length); + return (lxb_char_t *) entry->u.short_str; + } + + entry->u.long_str = data; + return entry->u.long_str; +} + +lxb_inline void +lexbor_hash_entry_str_free(lexbor_hash_t *hash, lexbor_hash_entry_t *entry) +{ + if (entry->length > LEXBOR_HASH_SHORT_SIZE) { + lexbor_mraw_free(hash->mraw, entry->u.long_str); + } + + entry->length = 0; +} + +lxb_inline lexbor_hash_entry_t * +lexbor_hash_entry_create(lexbor_hash_t *hash) +{ + return (lexbor_hash_entry_t *) lexbor_dobject_calloc(hash->entries); +} + +lxb_inline lexbor_hash_entry_t * +lexbor_hash_entry_destroy(lexbor_hash_t *hash, lexbor_hash_entry_t *entry) +{ + return (lexbor_hash_entry_t *) lexbor_dobject_free(hash->entries, entry); +} + +lxb_inline size_t +lexbor_hash_entries_count(lexbor_hash_t *hash) +{ + return lexbor_dobject_allocated(hash->entries); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_HASH_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/in.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/in.c new file mode 100644 index 0000000..363256b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/in.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/in.h" + + +lexbor_in_t * +lexbor_in_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_in_t)); +} + +lxb_status_t +lexbor_in_init(lexbor_in_t *incoming, size_t chunk_size) +{ + if (incoming == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (chunk_size == 0) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + incoming->nodes = lexbor_dobject_create(); + + return lexbor_dobject_init(incoming->nodes, chunk_size, + sizeof(lexbor_in_node_t)); +} + +void +lexbor_in_clean(lexbor_in_t *incoming) +{ + lexbor_dobject_clean(incoming->nodes); +} + +lexbor_in_t * +lexbor_in_destroy(lexbor_in_t *incoming, bool self_destroy) +{ + if (incoming == NULL) { + return NULL; + } + + incoming->nodes = lexbor_dobject_destroy(incoming->nodes, true); + + if (self_destroy == true) { + return lexbor_free(incoming); + } + + return incoming; +} + +lexbor_in_node_t * +lexbor_in_node_make(lexbor_in_t *incoming, lexbor_in_node_t *last_node, + const lxb_char_t *buf, size_t buf_size) +{ + lexbor_in_node_t *node = lexbor_dobject_alloc(incoming->nodes); + + if (node == NULL) { + return NULL; + } + + node->opt = LEXBOR_IN_OPT_UNDEF; + node->begin = buf; + node->end = buf ? (buf + buf_size) : NULL; + node->use = buf; + + if (last_node != NULL) { + last_node->next = node; + node->offset = last_node->offset + (last_node->end - last_node->begin); + } + else { + node->offset = 0; + } + + node->prev = last_node; + node->next = NULL; + node->incoming = incoming; + + return node; +} + +void +lexbor_in_node_clean(lexbor_in_node_t *node) +{ + lexbor_in_t *incoming = node->incoming; + + memset(node, 0, sizeof(lexbor_in_node_t)); + + node->incoming = incoming; +} + +lexbor_in_node_t * +lexbor_in_node_destroy(lexbor_in_t *incoming, + lexbor_in_node_t *node, bool self_destroy) +{ + if (node == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_dobject_free(incoming->nodes, node); + } + + return node; +} + +lexbor_in_node_t * +lexbor_in_node_split(lexbor_in_node_t *node, const lxb_char_t *pos) +{ + lexbor_in_node_t *new_node; + + new_node = lexbor_dobject_alloc(node->incoming->nodes); + + if (new_node == NULL) { + return NULL; + } + + new_node->offset = node->offset + (pos - node->begin); + new_node->opt = LEXBOR_IN_OPT_UNDEF; + new_node->begin = pos; + new_node->end = node->end; + new_node->next = NULL; + new_node->prev = node; + new_node->incoming = node->incoming; + + node->end = pos; + node->next = new_node; + + if (node->use > pos) { + new_node->use = node->use; + node->use = pos; + } + else { + new_node->use = pos; + } + + return new_node; +} + +lexbor_in_node_t * +lexbor_in_node_find(lexbor_in_node_t *node, const lxb_char_t *pos) +{ + while (node->next) { + node = node->next; + } + + while (node && (node->begin > pos || node->end < pos)) { + node = node->prev; + } + + return node; +} + +const lxb_char_t * +lexbor_in_node_pos_up(lexbor_in_node_t *node, lexbor_in_node_t **return_node, + const lxb_char_t *pos, size_t offset) +{ + do { + pos = pos + offset; + + if (node->end >= pos) { + if (return_node != NULL && *return_node != node) { + *return_node = node; + } + + return pos; + } + + if (node->next == NULL) { + if (return_node != NULL && *return_node != node) { + *return_node = node; + } + + return node->end; + } + + offset = pos - node->end; + node = node->next; + pos = node->begin; + + } + while (1); + + return NULL; +} + +const lxb_char_t * +lexbor_in_node_pos_down(lexbor_in_node_t *node, lexbor_in_node_t **return_node, + const lxb_char_t *pos, size_t offset) +{ + do { + pos = pos - offset; + + if (node->begin <= pos) { + if (return_node != NULL && *return_node != node) { + *return_node = node; + } + + return pos; + } + + if (node->prev == NULL) { + if (return_node != NULL && *return_node != node) { + *return_node = node; + } + + return node->begin; + } + + offset = node->begin - pos; + node = node->prev; + pos = node->end; + + } + while (1); + + return NULL; +} + +/* +* No inline functions for ABI. +*/ +const lxb_char_t * +lexbor_in_node_begin_noi(const lexbor_in_node_t *node) +{ + return lexbor_in_node_begin(node); +} + +const lxb_char_t * +lexbor_in_node_end_noi(const lexbor_in_node_t *node) +{ + return lexbor_in_node_end(node); +} + +size_t +lexbor_in_node_offset_noi(const lexbor_in_node_t *node) +{ + return lexbor_in_node_offset(node); +} + +lexbor_in_node_t * +lexbor_in_node_next_noi(const lexbor_in_node_t *node) +{ + return lexbor_in_node_next(node); +} + +lexbor_in_node_t * +lexbor_in_node_prev_noi(const lexbor_in_node_t *node) +{ + return lexbor_in_node_prev(node); +} + +lexbor_in_t * +lexbor_in_node_in_noi(const lexbor_in_node_t *node) +{ + return lexbor_in_node_in(node); +} + +bool +lexbor_in_segment_noi(const lexbor_in_node_t *node, const lxb_char_t *data) +{ + return lexbor_in_segment(node, data); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/in.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/in.h new file mode 100644 index 0000000..3e944f2 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/in.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_IN_H +#define LEXBOR_IN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" +#include "lexbor/core/dobject.h" + + +typedef struct lexbor_in_node lexbor_in_node_t; +typedef int lexbor_in_opt_t; + +enum lexbor_in_opt { + LEXBOR_IN_OPT_UNDEF = 0x00, + LEXBOR_IN_OPT_READONLY = 0x01, + LEXBOR_IN_OPT_DONE = 0x02, + LEXBOR_IN_OPT_FAKE = 0x04, + LEXBOR_IN_OPT_ALLOC = 0x08 +}; + +typedef struct { + lexbor_dobject_t *nodes; +} +lexbor_in_t; + +struct lexbor_in_node { + size_t offset; + lexbor_in_opt_t opt; + + const lxb_char_t *begin; + const lxb_char_t *end; + const lxb_char_t *use; + + lexbor_in_node_t *next; + lexbor_in_node_t *prev; + + lexbor_in_t *incoming; +}; + + +LXB_API lexbor_in_t * +lexbor_in_create(void); + +LXB_API lxb_status_t +lexbor_in_init(lexbor_in_t *incoming, size_t chunk_size); + +LXB_API void +lexbor_in_clean(lexbor_in_t *incoming); + +LXB_API lexbor_in_t * +lexbor_in_destroy(lexbor_in_t *incoming, bool self_destroy); + + +LXB_API lexbor_in_node_t * +lexbor_in_node_make(lexbor_in_t *incoming, lexbor_in_node_t *last_node, + const lxb_char_t *buf, size_t buf_size); + +LXB_API void +lexbor_in_node_clean(lexbor_in_node_t *node); + +LXB_API lexbor_in_node_t * +lexbor_in_node_destroy(lexbor_in_t *incoming, + lexbor_in_node_t *node, bool self_destroy); + + +LXB_API lexbor_in_node_t * +lexbor_in_node_split(lexbor_in_node_t *node, const lxb_char_t *pos); + +LXB_API lexbor_in_node_t * +lexbor_in_node_find(lexbor_in_node_t *node, const lxb_char_t *pos); + +/** + * Get position by `offset`. + * If position outside of nodes return `begin` position of first node + * in nodes chain. + */ +LXB_API const lxb_char_t * +lexbor_in_node_pos_up(lexbor_in_node_t *node, lexbor_in_node_t **return_node, + const lxb_char_t *pos, size_t offset); + +/** + * Get position by `offset`. + * If position outside of nodes return `end` + * position of last node in nodes chain. + */ +LXB_API const lxb_char_t * +lexbor_in_node_pos_down(lexbor_in_node_t *node, lexbor_in_node_t **return_node, + const lxb_char_t *pos, size_t offset); + +/* + * Inline functions + */ +lxb_inline const lxb_char_t * +lexbor_in_node_begin(const lexbor_in_node_t *node) +{ + return node->begin; +} + +lxb_inline const lxb_char_t * +lexbor_in_node_end(const lexbor_in_node_t *node) +{ + return node->end; +} + +lxb_inline size_t +lexbor_in_node_offset(const lexbor_in_node_t *node) +{ + return node->offset; +} + +lxb_inline lexbor_in_node_t * +lexbor_in_node_next(const lexbor_in_node_t *node) +{ + return node->next; +} + +lxb_inline lexbor_in_node_t * +lexbor_in_node_prev(const lexbor_in_node_t *node) +{ + return node->prev; +} + +lxb_inline lexbor_in_t * +lexbor_in_node_in(const lexbor_in_node_t *node) +{ + return node->incoming; +} + +lxb_inline bool +lexbor_in_segment(const lexbor_in_node_t *node, const lxb_char_t *data) +{ + return node->begin <= data && node->end >= data; +} + +/* + * No inline functions for ABI. + */ +LXB_API const lxb_char_t * +lexbor_in_node_begin_noi(const lexbor_in_node_t *node); + +LXB_API const lxb_char_t * +lexbor_in_node_end_noi(const lexbor_in_node_t *node); + +LXB_API size_t +lexbor_in_node_offset_noi(const lexbor_in_node_t *node); + +LXB_API lexbor_in_node_t * +lexbor_in_node_next_noi(const lexbor_in_node_t *node); + +LXB_API lexbor_in_node_t * +lexbor_in_node_prev_noi(const lexbor_in_node_t *node); + +LXB_API lexbor_in_t * +lexbor_in_node_in_noi(const lexbor_in_node_t *node); + +LXB_API bool +lexbor_in_segment_noi(const lexbor_in_node_t *node, const lxb_char_t *data); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_IN_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/lexbor.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/lexbor.h new file mode 100644 index 0000000..29c4035 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/lexbor.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_H +#define LEXBOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/def.h" + +typedef void *(*lexbor_memory_malloc_f)(size_t size); +typedef void *(*lexbor_memory_realloc_f)(void *dst, size_t size); +typedef void *(*lexbor_memory_calloc_f)(size_t num, size_t size); +typedef void (*lexbor_memory_free_f)(void *dst); + +LXB_API void * +lexbor_malloc(size_t size); + +LXB_API void * +lexbor_realloc(void *dst, size_t size); + +LXB_API void * +lexbor_calloc(size_t num, size_t size); + +LXB_API void * +lexbor_free(void *dst); + +LXB_API lxb_status_t +lexbor_memory_setup(lexbor_memory_malloc_f new_malloc, lexbor_memory_realloc_f new_realloc, + lexbor_memory_calloc_f new_calloc, lexbor_memory_free_f new_free); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mem.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mem.c new file mode 100644 index 0000000..9192af4 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mem.c @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/mem.h" + + +lexbor_mem_t * +lexbor_mem_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_mem_t)); +} + +lxb_status_t +lexbor_mem_init(lexbor_mem_t *mem, size_t min_chunk_size) +{ + if (mem == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (min_chunk_size == 0) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + mem->chunk_min_size = lexbor_mem_align(min_chunk_size); + + /* Create first chunk */ + mem->chunk = lexbor_mem_chunk_make(mem, mem->chunk_min_size); + if (mem->chunk == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + mem->chunk_length = 1; + mem->chunk_first = mem->chunk; + + return LXB_STATUS_OK; +} + +void +lexbor_mem_clean(lexbor_mem_t *mem) +{ + lexbor_mem_chunk_t *prev, *chunk; + + if (mem == NULL) { + return; + } + + chunk = mem->chunk; + + while (chunk->prev) { + prev = chunk->prev; + + chunk->data = lexbor_free(chunk->data); + lexbor_free(chunk); + + chunk = prev; + } + + chunk->next = NULL; + chunk->length = 0; + + mem->chunk = mem->chunk_first; + mem->chunk_length = 1; +} + +lexbor_mem_t * +lexbor_mem_destroy(lexbor_mem_t *mem, bool destroy_self) +{ + lexbor_mem_chunk_t *chunk, *prev; + + if (mem == NULL) { + return NULL; + } + + /* Destroy all chunk */ + if (mem->chunk) { + chunk = mem->chunk; + + while (chunk) { + prev = chunk->prev; + lexbor_mem_chunk_destroy(mem, chunk, true); + chunk = prev; + } + + mem->chunk = NULL; + } + + if (destroy_self) { + return lexbor_free(mem); + } + + return mem; +} + +uint8_t * +lexbor_mem_chunk_init(lexbor_mem_t *mem, + lexbor_mem_chunk_t *chunk, size_t length) +{ + length = lexbor_mem_align(length); + + if (length > mem->chunk_min_size) { + if (mem->chunk_min_size > (SIZE_MAX - length)) { + chunk->size = length; + } + else { + chunk->size = length + mem->chunk_min_size; + } + } + else { + chunk->size = mem->chunk_min_size; + } + + chunk->length = 0; + chunk->data = lexbor_malloc(chunk->size * sizeof(uint8_t)); + + return chunk->data; +} + +lexbor_mem_chunk_t * +lexbor_mem_chunk_make(lexbor_mem_t *mem, size_t length) +{ + lexbor_mem_chunk_t *chunk = lexbor_calloc(1, sizeof(lexbor_mem_chunk_t)); + + if (chunk == NULL) { + return NULL; + } + + if (lexbor_mem_chunk_init(mem, chunk, length) == NULL) { + return lexbor_free(chunk); + } + + return chunk; +} + +lexbor_mem_chunk_t * +lexbor_mem_chunk_destroy(lexbor_mem_t *mem, + lexbor_mem_chunk_t *chunk, bool self_destroy) +{ + if (chunk == NULL || mem == NULL) { + return NULL; + } + + if (chunk->data) { + chunk->data = lexbor_free(chunk->data); + } + + if (self_destroy) { + return lexbor_free(chunk); + } + + return chunk; +} + +void * +lexbor_mem_alloc(lexbor_mem_t *mem, size_t length) +{ + if (length == 0) { + return NULL; + } + + length = lexbor_mem_align(length); + + if ((mem->chunk->length + length) > mem->chunk->size) { + if ((SIZE_MAX - mem->chunk_length) == 0) { + return NULL; + } + + mem->chunk->next = lexbor_mem_chunk_make(mem, length); + if (mem->chunk->next == NULL) { + return NULL; + } + + mem->chunk->next->prev = mem->chunk; + mem->chunk = mem->chunk->next; + + mem->chunk_length++; + } + + mem->chunk->length += length; + + return &mem->chunk->data[(mem->chunk->length - length)]; +} + +void * +lexbor_mem_calloc(lexbor_mem_t *mem, size_t length) +{ + void *data = lexbor_mem_alloc(mem, length); + + if (data != NULL) { + memset(data, 0, length); + } + + return data; +} + +/* + * No inline functions for ABI. + */ +size_t +lexbor_mem_current_length_noi(lexbor_mem_t *mem) +{ + return lexbor_mem_current_length(mem); +} + +size_t +lexbor_mem_current_size_noi(lexbor_mem_t *mem) +{ + return lexbor_mem_current_size(mem); +} + +size_t +lexbor_mem_chunk_length_noi(lexbor_mem_t *mem) +{ + return lexbor_mem_chunk_length(mem); +} +size_t +lexbor_mem_align_noi(size_t size) +{ + return lexbor_mem_align(size); +} + +size_t +lexbor_mem_align_floor_noi(size_t size) +{ + return lexbor_mem_align_floor(size); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mem.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mem.h new file mode 100644 index 0000000..f245528 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mem.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_MEM_H +#define LEXBOR_MEM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lexbor/core/base.h" + + +typedef struct lexbor_mem_chunk lexbor_mem_chunk_t; +typedef struct lexbor_mem lexbor_mem_t; + +struct lexbor_mem_chunk { + uint8_t *data; + size_t length; + size_t size; + + lexbor_mem_chunk_t *next; + lexbor_mem_chunk_t *prev; +}; + +struct lexbor_mem { + lexbor_mem_chunk_t *chunk; + lexbor_mem_chunk_t *chunk_first; + + size_t chunk_min_size; + size_t chunk_length; +}; + + +LXB_API lexbor_mem_t * +lexbor_mem_create(void); + +LXB_API lxb_status_t +lexbor_mem_init(lexbor_mem_t *mem, size_t min_chunk_size); + +LXB_API void +lexbor_mem_clean(lexbor_mem_t *mem); + +LXB_API lexbor_mem_t * +lexbor_mem_destroy(lexbor_mem_t *mem, bool destroy_self); + + +/* + * The memory allocated in lexbor_mem_chunk_* functions needs to be freed + * by lexbor_mem_chunk_destroy function. + * + * This memory will not be automatically freed by a function lexbor_mem_destroy. + */ +LXB_API uint8_t * +lexbor_mem_chunk_init(lexbor_mem_t *mem, + lexbor_mem_chunk_t *chunk, size_t length); + +LXB_API lexbor_mem_chunk_t * +lexbor_mem_chunk_make(lexbor_mem_t *mem, size_t length); + +LXB_API lexbor_mem_chunk_t * +lexbor_mem_chunk_destroy(lexbor_mem_t *mem, + lexbor_mem_chunk_t *chunk, bool self_destroy); + +/* + * The memory allocated in lexbor_mem_alloc and lexbor_mem_calloc function + * will be freeds after calling lexbor_mem_destroy function. + */ +LXB_API void * +lexbor_mem_alloc(lexbor_mem_t *mem, size_t length); + +LXB_API void * +lexbor_mem_calloc(lexbor_mem_t *mem, size_t length); + + +/* + * Inline functions + */ +lxb_inline size_t +lexbor_mem_current_length(lexbor_mem_t *mem) +{ + return mem->chunk->length; +} + +lxb_inline size_t +lexbor_mem_current_size(lexbor_mem_t *mem) +{ + return mem->chunk->size; +} + +lxb_inline size_t +lexbor_mem_chunk_length(lexbor_mem_t *mem) +{ + return mem->chunk_length; +} + +lxb_inline size_t +lexbor_mem_align(size_t size) +{ + return ((size % LEXBOR_MEM_ALIGN_STEP) != 0) + ? size + (LEXBOR_MEM_ALIGN_STEP - (size % LEXBOR_MEM_ALIGN_STEP)) + : size; +} + +lxb_inline size_t +lexbor_mem_align_floor(size_t size) +{ + return ((size % LEXBOR_MEM_ALIGN_STEP) != 0) + ? size - (size % LEXBOR_MEM_ALIGN_STEP) + : size; +} + +/* + * No inline functions for ABI. + */ +LXB_API size_t +lexbor_mem_current_length_noi(lexbor_mem_t *mem); + +LXB_API size_t +lexbor_mem_current_size_noi(lexbor_mem_t *mem); + +LXB_API size_t +lexbor_mem_chunk_length_noi(lexbor_mem_t *mem); + +LXB_API size_t +lexbor_mem_align_noi(size_t size); + +LXB_API size_t +lexbor_mem_align_floor_noi(size_t size); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_MEM_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mraw.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mraw.c new file mode 100644 index 0000000..2e629fb --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mraw.c @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2018-2019 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/mraw.h" + + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + #include +#endif + + +#define lexbor_mraw_meta_set(data, size) \ + do { \ + memcpy(data, size, sizeof(size_t)); \ + } \ + while (0) + +#define lexbor_mraw_data_begin(data) \ + &((uint8_t *) (data))[ lexbor_mraw_meta_size() ] + + +lxb_inline void * +lexbor_mraw_realloc_tail(lexbor_mraw_t *mraw, void *data, void *begin, + size_t size, size_t begin_len, size_t new_size, + bool *is_valid); + + +lexbor_mraw_t * +lexbor_mraw_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_mraw_t)); +} + +lxb_status_t +lexbor_mraw_init(lexbor_mraw_t *mraw, size_t chunk_size) +{ + lxb_status_t status; + + if (mraw == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (chunk_size == 0) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + /* Init memory */ + mraw->mem = lexbor_mem_create(); + + status = lexbor_mem_init(mraw->mem, chunk_size + lexbor_mraw_meta_size()); + if (status) { + return status; + } + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(mraw->mem->chunk->data, mraw->mem->chunk->size); +#endif + + /* Cache */ + mraw->cache = lexbor_bst_create(); + + status = lexbor_bst_init(mraw->cache, 512); + if (status) { + return status; + } + + mraw->ref_count = 0; + + return LXB_STATUS_OK; +} + +void +lexbor_mraw_clean(lexbor_mraw_t *mraw) +{ + if (mraw != NULL) { + lexbor_mem_clean(mraw->mem); + lexbor_bst_clean(mraw->cache); + + mraw->ref_count = 0; + } +} + +lexbor_mraw_t * +lexbor_mraw_destroy(lexbor_mraw_t *mraw, bool destroy_self) +{ + if (mraw == NULL) { + return NULL; + } + + mraw->mem = lexbor_mem_destroy(mraw->mem, true); + mraw->cache = lexbor_bst_destroy(mraw->cache, true); + + if (destroy_self) { + return lexbor_free(mraw); + } + + return mraw; +} + +lxb_inline void * +lexbor_mraw_mem_alloc(lexbor_mraw_t *mraw, size_t length) +{ + uint8_t *data; + lexbor_mem_t *mem = mraw->mem; + + if (length == 0) { + return NULL; + } + + if ((mem->chunk->length + length) > mem->chunk->size) { + lexbor_mem_chunk_t *chunk = mem->chunk; + + if ((SIZE_MAX - mem->chunk_length) == 0) { + return NULL; + } + + if (chunk->length == 0) { + lexbor_mem_chunk_destroy(mem, chunk, false); + lexbor_mem_chunk_init(mem, chunk, length); + + chunk->length = length; + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(chunk->data, chunk->size); +#endif + + return chunk->data; + } + + size_t diff = lexbor_mem_align_floor(chunk->size - chunk->length); + + /* Save tail to cache */ + if (diff > lexbor_mraw_meta_size()) { + diff -= lexbor_mraw_meta_size(); + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_UNPOISON_MEMORY_REGION(&chunk->data[chunk->length], + lexbor_mraw_meta_size()); +#endif + + lexbor_mraw_meta_set(&chunk->data[chunk->length], &diff); + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(&chunk->data[chunk->length], + diff + lexbor_mraw_meta_size()); +#endif + + lexbor_bst_insert(mraw->cache, + lexbor_bst_root_ref(mraw->cache), diff, + lexbor_mraw_data_begin(&chunk->data[chunk->length])); + + chunk->length = chunk->size; + } + + chunk->next = lexbor_mem_chunk_make(mem, length); + if (chunk->next == NULL) { + return NULL; + } + + chunk->next->prev = chunk; + mem->chunk = chunk->next; + + mem->chunk_length++; + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(mem->chunk->data, mem->chunk->size); +#endif + } + + data = &mem->chunk->data[ mem->chunk->length ]; + mem->chunk->length += length; + + return data; +} + +void * +lexbor_mraw_alloc(lexbor_mraw_t *mraw, size_t size) +{ + void *data; + + size = lexbor_mem_align(size); + + if (mraw->cache->tree_length != 0) { + data = lexbor_bst_remove_close(mraw->cache, + lexbor_bst_root_ref(mraw->cache), + size, NULL); + if (data != NULL) { + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + uint8_t *real_data = ((uint8_t *) data) - lexbor_mraw_meta_size(); + + /* Set unpoison for current data size */ + ASAN_UNPOISON_MEMORY_REGION(real_data, lexbor_mraw_meta_size()); + + size_t cur_size = lexbor_mraw_data_size(data); + + ASAN_UNPOISON_MEMORY_REGION(real_data, + (cur_size + lexbor_mraw_meta_size())); +#endif + + mraw->ref_count++; + + return data; + } + } + + data = lexbor_mraw_mem_alloc(mraw, (size + lexbor_mraw_meta_size())); + + if (data == NULL) { + return NULL; + } + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_UNPOISON_MEMORY_REGION(data, (size + lexbor_mraw_meta_size())); +#endif + + mraw->ref_count++; + + lexbor_mraw_meta_set(data, &size); + return lexbor_mraw_data_begin(data); +} + +void * +lexbor_mraw_calloc(lexbor_mraw_t *mraw, size_t size) +{ + void *data = lexbor_mraw_alloc(mraw, size); + + if (data != NULL) { + memset(data, 0, lexbor_mraw_data_size(data)); + } + + return data; +} + +/* + * TODO: I don't really like this interface. Perhaps need to simplify. + */ +lxb_inline void * +lexbor_mraw_realloc_tail(lexbor_mraw_t *mraw, void *data, void *begin, + size_t size, size_t begin_len, size_t new_size, + bool *is_valid) +{ + size_t length; + uint8_t *tmp; + lexbor_mem_chunk_t *chunk = mraw->mem->chunk; + + if (chunk->size > (begin_len + new_size)) { + *is_valid = true; + + if (new_size == 0) { + chunk->length = begin_len - lexbor_mraw_meta_size(); + return NULL; + } + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_UNPOISON_MEMORY_REGION(begin, new_size + lexbor_mraw_meta_size()); +#endif + + chunk->length = begin_len + new_size; + memcpy(begin, &new_size, sizeof(size_t)); + + return data; + } + + /* + * If the tail is short then we increase the current data. + */ + if (begin_len == lexbor_mraw_meta_size()) { +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_UNPOISON_MEMORY_REGION(chunk->data, chunk->size); +#endif + *is_valid = true; + + length = lexbor_mem_align(new_size + lexbor_mraw_meta_size() + + mraw->mem->chunk_min_size); + + tmp = lexbor_realloc(chunk->data, length); + if (tmp == NULL) { + return NULL; + } + + chunk->data = tmp; + chunk->size = length; + chunk->length = new_size + lexbor_mraw_meta_size(); + + lexbor_mraw_meta_set(tmp, &new_size); + + return lexbor_mraw_data_begin(tmp); + } + + *is_valid = false; + + /* + * Next, this piece will go into the cache. + */ + size = lexbor_mem_align_floor(size + (chunk->size - chunk->length)); + memcpy(begin, &size, sizeof(size_t)); + + chunk->length = chunk->size; + + return NULL; +} + +void * +lexbor_mraw_realloc(lexbor_mraw_t *mraw, void *data, size_t new_size) +{ + void *begin; + size_t size, begin_len; + lexbor_mem_chunk_t *chunk = mraw->mem->chunk; + + begin = ((uint8_t *) data) - lexbor_mraw_meta_size(); + memcpy(&size, begin, sizeof(size_t)); + + new_size = lexbor_mem_align(new_size); + + /* + * Look, whether there is an opportunity + * to prolong the current data in chunk? + */ + if (chunk->length >= size) { + begin_len = chunk->length - size; + + if (&chunk->data[begin_len] == data) { + bool is_valid; + void *ptr = lexbor_mraw_realloc_tail(mraw, data, begin, + size, begin_len, new_size, + &is_valid); + if (is_valid == true) { + return ptr; + } + } + } + + if (new_size < size) { + if (new_size == 0) { + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(begin, size + lexbor_mraw_meta_size()); +#endif + mraw->ref_count--; + + lexbor_bst_insert(mraw->cache, lexbor_bst_root_ref(mraw->cache), + size, data); + return NULL; + } + + size_t diff = lexbor_mem_align_floor(size - new_size); + + if (diff > lexbor_mraw_meta_size()) { + memcpy(begin, &new_size, sizeof(size_t)); + + begin = &((uint8_t *) data)[new_size]; + new_size = diff - lexbor_mraw_meta_size(); + + lexbor_mraw_meta_set(begin, &new_size); + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + ASAN_POISON_MEMORY_REGION(begin, new_size + lexbor_mraw_meta_size()); +#endif + lexbor_bst_insert(mraw->cache, lexbor_bst_root_ref(mraw->cache), + new_size, lexbor_mraw_data_begin(begin)); + } + + return data; + } + + begin = lexbor_mraw_alloc(mraw, new_size); + if (begin == NULL) { + return NULL; + } + + if (size != 0) { + memcpy(begin, data, sizeof(uint8_t) * size); + } + + lexbor_mraw_free(mraw, data); + + return begin; +} + +void * +lexbor_mraw_free(lexbor_mraw_t *mraw, void *data) +{ + size_t size = lexbor_mraw_data_size(data); + +#if defined(LEXBOR_HAVE_ADDRESS_SANITIZER) + uint8_t *real_data = ((uint8_t *) data) - lexbor_mraw_meta_size(); + ASAN_POISON_MEMORY_REGION(real_data, size + lexbor_mraw_meta_size()); +#endif + + lexbor_bst_insert(mraw->cache, lexbor_bst_root_ref(mraw->cache), + size, data); + + mraw->ref_count--; + + return NULL; +} + +/* + * No inline functions for ABI. + */ +size_t +lexbor_mraw_data_size_noi(void *data) +{ + return lexbor_mraw_data_size(data); +} + +void +lexbor_mraw_data_size_set_noi(void *data, size_t size) +{ + lexbor_mraw_data_size_set(data, size); +} + +void * +lexbor_mraw_dup_noi(lexbor_mraw_t *mraw, const void *src, size_t size) +{ + return lexbor_mraw_dup(mraw, src, size); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mraw.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mraw.h new file mode 100644 index 0000000..1ffb64d --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/mraw.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_MRAW_H +#define LEXBOR_MRAW_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lexbor/core/base.h" +#include "lexbor/core/mem.h" +#include "lexbor/core/bst.h" + + +#define lexbor_mraw_meta_size() \ + (((sizeof(size_t) % LEXBOR_MEM_ALIGN_STEP) != 0) \ + ? sizeof(size_t) \ + + (LEXBOR_MEM_ALIGN_STEP - (sizeof(size_t) % LEXBOR_MEM_ALIGN_STEP)) \ + : sizeof(size_t)) + + +typedef struct { + lexbor_mem_t *mem; + lexbor_bst_t *cache; + size_t ref_count; +} +lexbor_mraw_t; + + +LXB_API lexbor_mraw_t * +lexbor_mraw_create(void); + +LXB_API lxb_status_t +lexbor_mraw_init(lexbor_mraw_t *mraw, size_t chunk_size); + +LXB_API void +lexbor_mraw_clean(lexbor_mraw_t *mraw); + +LXB_API lexbor_mraw_t * +lexbor_mraw_destroy(lexbor_mraw_t *mraw, bool destroy_self); + + +LXB_API void * +lexbor_mraw_alloc(lexbor_mraw_t *mraw, size_t size); + +LXB_API void * +lexbor_mraw_calloc(lexbor_mraw_t *mraw, size_t size); + +LXB_API void * +lexbor_mraw_realloc(lexbor_mraw_t *mraw, void *data, size_t new_size); + +LXB_API void * +lexbor_mraw_free(lexbor_mraw_t *mraw, void *data); + + +/* + * Inline functions + */ +lxb_inline size_t +lexbor_mraw_data_size(void *data) +{ + return *((size_t *) (((uint8_t *) data) - lexbor_mraw_meta_size())); +} + +lxb_inline void +lexbor_mraw_data_size_set(void *data, size_t size) +{ + data = (((uint8_t *) data) - lexbor_mraw_meta_size()); + memcpy(data, &size, sizeof(size_t)); +} + +lxb_inline void * +lexbor_mraw_dup(lexbor_mraw_t *mraw, const void *src, size_t size) +{ + void *data = lexbor_mraw_alloc(mraw, size); + + if (data != NULL) { + memcpy(data, src, size); + } + + return data; +} + +lxb_inline size_t +lexbor_mraw_reference_count(lexbor_mraw_t *mraw) +{ + return mraw->ref_count; +} + + +/* + * No inline functions for ABI. + */ +LXB_API size_t +lexbor_mraw_data_size_noi(void *data); + +LXB_API void +lexbor_mraw_data_size_set_noi(void *data, size_t size); + +LXB_API void * +lexbor_mraw_dup_noi(lexbor_mraw_t *mraw, const void *src, size_t size); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_MRAW_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/perf.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/perf.h new file mode 100644 index 0000000..49bf0bb --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/perf.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2018-2024 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_PERF_H +#define LEXBOR_PERF_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +LXB_API void * +lexbor_perf_create(void); + +LXB_API void +lexbor_perf_clean(void *perf); + +LXB_API void +lexbor_perf_destroy(void *perf); + +LXB_API lxb_status_t +lexbor_perf_begin(void *perf); + +LXB_API lxb_status_t +lexbor_perf_end(void *perf); + +LXB_API double +lexbor_perf_in_sec(void *perf); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_PERF_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/plog.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/plog.c new file mode 100644 index 0000000..71344b0 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/plog.c @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2019 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/plog.h" + + +lxb_status_t +lexbor_plog_init(lexbor_plog_t *plog, size_t init_size, size_t struct_size) +{ + lxb_status_t status; + + if (plog == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + if (struct_size < sizeof(lexbor_plog_entry_t)) { + struct_size = sizeof(lexbor_plog_entry_t); + } + + status = lexbor_array_obj_init(&plog->list, init_size, struct_size); + if (status != LXB_STATUS_OK) { + return status; + } + + return LXB_STATUS_OK; +} + +lexbor_plog_t * +lexbor_plog_destroy(lexbor_plog_t *plog, bool self_destroy) +{ + if (plog == NULL) { + return NULL; + } + + lexbor_array_obj_destroy(&plog->list, false); + + if (self_destroy) { + return lexbor_free(plog); + } + + return plog; +} + +/* + * No inline functions. + */ +lexbor_plog_t * +lexbor_plog_create_noi(void) +{ + return lexbor_plog_create(); +} + +void +lexbor_plog_clean_noi(lexbor_plog_t *plog) +{ + lexbor_plog_clean(plog); +} + +void * +lexbor_plog_push_noi(lexbor_plog_t *plog, const lxb_char_t *data, void *ctx, + unsigned id) +{ + return lexbor_plog_push(plog, data, ctx, id); +} + +size_t +lexbor_plog_length_noi(lexbor_plog_t *plog) +{ + return lexbor_plog_length(plog); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/plog.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/plog.h new file mode 100644 index 0000000..91b35bf --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/plog.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2019 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_PLOG_H +#define LEXBOR_PLOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/array_obj.h" + + +typedef struct { + const lxb_char_t *data; + void *context; + unsigned id; +} +lexbor_plog_entry_t; + +typedef struct { + lexbor_array_obj_t list; +} +lexbor_plog_t; + + +LXB_API lxb_status_t +lexbor_plog_init(lexbor_plog_t *plog, size_t init_size, size_t struct_size); + +LXB_API lexbor_plog_t * +lexbor_plog_destroy(lexbor_plog_t *plog, bool self_destroy); + + +/* + * Inline functions + */ +lxb_inline lexbor_plog_t * +lexbor_plog_create(void) +{ + return (lexbor_plog_t *) lexbor_calloc(1, sizeof(lexbor_plog_t)); +} + +lxb_inline void +lexbor_plog_clean(lexbor_plog_t *plog) +{ + lexbor_array_obj_clean(&plog->list); +} + +lxb_inline void * +lexbor_plog_push(lexbor_plog_t *plog, const lxb_char_t *data, void *ctx, + unsigned id) +{ + lexbor_plog_entry_t *entry; + + if (plog == NULL) { + return NULL; + } + + entry = (lexbor_plog_entry_t *) lexbor_array_obj_push(&plog->list); + if (entry == NULL) { + return NULL; + } + + entry->data = data; + entry->context = ctx; + entry->id = id; + + return (void *) entry; +} + +lxb_inline size_t +lexbor_plog_length(lexbor_plog_t *plog) +{ + return lexbor_array_obj_length(&plog->list); +} + +/* + * No inline functions for ABI. + */ +LXB_API lexbor_plog_t * +lexbor_plog_create_noi(void); + +LXB_API void +lexbor_plog_clean_noi(lexbor_plog_t *plog); + +LXB_API void * +lexbor_plog_push_noi(lexbor_plog_t *plog, const lxb_char_t *data, void *ctx, + unsigned id); + +LXB_API size_t +lexbor_plog_length_noi(lexbor_plog_t *plog); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_PLOG_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/print.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/print.c new file mode 100644 index 0000000..63a6f20 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/print.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/str.h" +#include "lexbor/core/print.h" + + +#define lexbor_sprintf_append(dst, end, src, length) \ + do { \ + if ((size_t) ((end) - (dst)) < (length)) { \ + return (end) - (dst); \ + } \ + \ + memcpy((dst), (src), (length)); \ + (dst) += (length); \ + } \ + while (false) + + +size_t +lexbor_printf_size(const char *format, ...) +{ + size_t ret; + va_list va; + + va_start(va, format); + ret = lexbor_vprintf_size(format, va); + va_end(va); + + return ret; +} + +size_t +lexbor_vprintf_size(const char *format, va_list va) +{ + char c; + const char *begin, *cdata; + size_t size; + lexbor_str_t *str; + + begin = format; + size = 0; + + while (true) { + c = *format; + + if (c == '%') { + c = format[1]; + + switch (c) { + case '\0': + return size + (format - begin) + 1; + + case 's': + cdata = va_arg(va, const char *); + size += (format - begin) + strlen(cdata); + break; + + case 'S': + str = va_arg(va, lexbor_str_t *); + size += (format - begin) + str->length; + break; + + case '%': + size += (format - begin) + 1; + break; + + default: + return LXB_PRINT_ERROR; + } + + format++; + begin = format + 1; + } + else if (c == '\0') { + return size + (format - begin); + } + + format++; + } +} + +size_t +lexbor_sprintf(lxb_char_t *dst, size_t size, const char *format, ...) +{ + size_t ret; + va_list va; + + va_start(va, format); + ret = lexbor_vsprintf(dst, size, format, va); + va_end(va); + + return ret; +} + +size_t +lexbor_vsprintf(lxb_char_t *dst, size_t size, const char *format, va_list va) +{ + char c; + const char *begin, *cdata; + lxb_char_t *end, *start; + lexbor_str_t *str; + + begin = format; + start = dst; + end = dst + size; + + while (true) { + c = *format; + + if (c == '%') { + c = format[1]; + + switch (c) { + case '\0': + size = (format - begin) + 1; + lexbor_sprintf_append(dst, end, begin, size); + goto done; + + case 's': + size = format - begin; + lexbor_sprintf_append(dst, end, begin, size); + + cdata = va_arg(va, const char *); + size = strlen(cdata); + lexbor_sprintf_append(dst, end, cdata, size); + break; + + case 'S': + size = format - begin; + lexbor_sprintf_append(dst, end, begin, size); + + str = va_arg(va, lexbor_str_t *); + lexbor_sprintf_append(dst, end, str->data, str->length); + break; + + case '%': + size = (format - begin) + 1; + lexbor_sprintf_append(dst, end, begin, size); + break; + + default: + return LXB_PRINT_ERROR; + } + + format++; + begin = format + 1; + } + else if (c == '\0') { + size = format - begin; + lexbor_sprintf_append(dst, end, begin, size); + goto done; + } + + format++; + } + +done: + + if (end - dst > 0) { + *dst = '\0'; + } + + return dst - start; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/print.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/print.h new file mode 100644 index 0000000..5e62245 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/print.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_PRINT_H +#define LEXBOR_PRINT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lexbor/core/base.h" + + +#define LXB_PRINT_ERROR ((size_t) - 1) + + +LXB_API size_t +lexbor_printf_size(const char *format, ...); + +LXB_API size_t +lexbor_vprintf_size(const char *format, va_list va); + +LXB_API size_t +lexbor_sprintf(lxb_char_t *dst, size_t size, const char *format, ...); + +LXB_API size_t +lexbor_vsprintf(lxb_char_t *dst, size_t size, const char *format, va_list va); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_PRINT_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/sbst.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/sbst.h new file mode 100644 index 0000000..b0fbc54 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/sbst.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_SBST_H +#define LEXBOR_SBST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lexbor/core/base.h" + + +typedef struct { + lxb_char_t key; + + void *value; + size_t value_len; + + size_t left; + size_t right; + size_t next; +} +lexbor_sbst_entry_static_t; + + +/* + * Inline functions + */ +lxb_inline const lexbor_sbst_entry_static_t * +lexbor_sbst_entry_static_find(const lexbor_sbst_entry_static_t *strt, + const lexbor_sbst_entry_static_t *root, + const lxb_char_t key) +{ + while (root != strt) { + if (root->key == key) { + return root; + } + else if (key > root->key) { + root = &strt[root->right]; + } + else { + root = &strt[root->left]; + } + } + + return NULL; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_SBST_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/serialize.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/serialize.c new file mode 100644 index 0000000..599e3c7 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/serialize.c @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/serialize.h" +#include "lexbor/core/str.h" + + +lxb_status_t +lexbor_serialize_length_cb(const lxb_char_t *data, size_t length, void *ctx) +{ + *((size_t *) ctx) += length; + return LXB_STATUS_OK; +} + +lxb_status_t +lexbor_serialize_copy_cb(const lxb_char_t *data, size_t length, void *ctx) +{ + lexbor_str_t *str = ctx; + + memcpy(str->data + str->length, data, length); + str->length += length; + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/serialize.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/serialize.h new file mode 100644 index 0000000..d6352f2 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/serialize.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_SERIALIZE_H +#define LEXBOR_SERIALIZE_H + + +#include "lexbor/core/base.h" + + +#define lexbor_serialize_write(cb, data, length, ctx, status) \ + do { \ + (status) = (cb)((lxb_char_t *) (data), (length), (ctx)); \ + if ((status) != LXB_STATUS_OK) { \ + return (status); \ + } \ + } \ + while (false) + + +LXB_API lxb_status_t +lexbor_serialize_length_cb(const lxb_char_t *data, size_t length, void *ctx); + + +LXB_API lxb_status_t +lexbor_serialize_copy_cb(const lxb_char_t *data, size_t length, void *ctx); + + +#endif /* LEXBOR_SERIALIZE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/shs.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/shs.c new file mode 100644 index 0000000..c275345 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/shs.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/shs.h" +#include "lexbor/core/str.h" + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_map_lowercase[256]; + LXB_EXTERN const lxb_char_t lexbor_str_res_map_uppercase[256]; +#endif + +#define lexbor_shs_make_id_m(key, size, table_size) \ + (((((key[0] * key[size - 1]) * key[0]) + size) % table_size) + 0x01) + +#define lexbor_shs_make_id_lower_m(key, size, table_size) \ + (((((lexbor_str_res_map_lowercase[key[0]] \ + * lexbor_str_res_map_lowercase[key[size - 1]]) \ + * lexbor_str_res_map_lowercase[key[0]]) \ + + size) \ + % table_size) + 0x01) + +#define lexbor_shs_make_id_upper_m(key, size, table_size) \ + (((((lexbor_str_res_map_uppercase[key[0]] \ + * lexbor_str_res_map_uppercase[key[size - 1]]) \ + * lexbor_str_res_map_uppercase[key[0]]) \ + + size) \ + % table_size) + 0x01) + + +const lexbor_shs_entry_t * +lexbor_shs_entry_get_static(const lexbor_shs_entry_t *root, + const lxb_char_t *key, size_t key_len) +{ + const lexbor_shs_entry_t *entry; + entry = root + lexbor_shs_make_id_m(key, key_len, root->key_len); + + while (entry->key != NULL) + { + if (entry->key_len == key_len) { + if (lexbor_str_data_ncmp((const lxb_char_t *) entry->key, + key, key_len)) + { + return entry; + } + + entry = &root[entry->next]; + } + else if (entry->key_len > key_len) { + return NULL; + } + else { + entry = &root[entry->next]; + } + } + + return NULL; +} + +const lexbor_shs_entry_t * +lexbor_shs_entry_get_lower_static(const lexbor_shs_entry_t *root, + const lxb_char_t *key, size_t key_len) +{ + const lexbor_shs_entry_t *entry; + entry = root + lexbor_shs_make_id_lower_m(key, key_len, root->key_len); + + while (entry->key != NULL) + { + if (entry->key_len == key_len) { + if (lexbor_str_data_nlocmp_right((const lxb_char_t *) entry->key, + key, key_len)) + { + return entry; + } + + entry = &root[entry->next]; + } + else if (entry->key_len > key_len) { + return NULL; + } + else { + entry = &root[entry->next]; + } + } + + return NULL; +} + +const lexbor_shs_entry_t * +lexbor_shs_entry_get_upper_static(const lexbor_shs_entry_t *root, + const lxb_char_t *key, size_t key_len) +{ + const lexbor_shs_entry_t *entry; + entry = root + lexbor_shs_make_id_upper_m(key, key_len, root->key_len); + + while (entry->key != NULL) + { + if (entry->key_len == key_len) { + if (lexbor_str_data_nupcmp_right((const lxb_char_t *) entry->key, + key, key_len)) + { + return entry; + } + + entry = &root[entry->next]; + } + else if (entry->key_len > key_len) { + return NULL; + } + else { + entry = &root[entry->next]; + } + } + + return NULL; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/shs.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/shs.h new file mode 100644 index 0000000..7a63a07 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/shs.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_SHS_H +#define LEXBOR_SHS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "lexbor/core/base.h" + + +typedef struct { + char *key; + void *value; + + size_t key_len; + size_t next; +} +lexbor_shs_entry_t; + +typedef struct { + uint32_t key; + void *value; + + size_t next; +} +lexbor_shs_hash_t; + + +LXB_API const lexbor_shs_entry_t * +lexbor_shs_entry_get_static(const lexbor_shs_entry_t *tree, + const lxb_char_t *key, size_t size); + +LXB_API const lexbor_shs_entry_t * +lexbor_shs_entry_get_lower_static(const lexbor_shs_entry_t *root, + const lxb_char_t *key, size_t key_len); + +LXB_API const lexbor_shs_entry_t * +lexbor_shs_entry_get_upper_static(const lexbor_shs_entry_t *root, + const lxb_char_t *key, size_t key_len); + +/* + * Inline functions + */ +lxb_inline const lexbor_shs_hash_t * +lexbor_shs_hash_get_static(const lexbor_shs_hash_t *table, + const size_t table_size, const uint32_t key) +{ + const lexbor_shs_hash_t *entry; + + entry = &table[ (key % table_size) + 1 ]; + + do { + if (entry->key == key) { + return entry; + } + + entry = &table[entry->next]; + } + while (entry != table); + + return NULL; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_SHS_H */ + + + + + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str.c new file mode 100644 index 0000000..3d164eb --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str.c @@ -0,0 +1,667 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/str.h" +#include "lexbor/core/str_res.h" + + +lexbor_str_t * +lexbor_str_create(void) +{ + return lexbor_calloc(1, sizeof(lexbor_str_t)); +} + +lxb_char_t * +lexbor_str_init(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t size) +{ + if (str == NULL) { + return NULL; + } + + str->data = lexbor_mraw_alloc(mraw, (size + 1)); + str->length = 0; + + if (str->data != NULL) { + *str->data = '\0'; + } + + return str->data; +} + +lxb_char_t * +lexbor_str_init_append(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *data, size_t length) +{ + lxb_char_t *p; + + if (str == NULL) { + return NULL; + } + + p = lexbor_mraw_alloc(mraw, (length + 1)); + if (p == NULL) { + return NULL; + } + + memcpy(p, data, length); + + p[length] = '\0'; + + str->data = p; + str->length = length; + + return p; +} + +void +lexbor_str_clean(lexbor_str_t *str) +{ + str->length = 0; +} + +void +lexbor_str_clean_all(lexbor_str_t *str) +{ + memset(str, 0, sizeof(lexbor_str_t)); +} + +lexbor_str_t * +lexbor_str_destroy(lexbor_str_t *str, lexbor_mraw_t *mraw, bool destroy_obj) +{ + if (str == NULL) { + return NULL; + } + + if (str->data != NULL) { + lexbor_str_clean(str); + str->data = lexbor_mraw_free(mraw, str->data); + } + + if (destroy_obj) { + return lexbor_free(str); + } + + return str; +} + +lxb_char_t * +lexbor_str_realloc(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t new_size) +{ + lxb_char_t *tmp = lexbor_mraw_realloc(mraw, str->data, new_size); + if (tmp == NULL) { + return NULL; + } + + str->data = tmp; + + return tmp; +} + +lxb_char_t * +lexbor_str_check_size(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t plus_len) +{ + lxb_char_t *tmp; + + if (str->length > (SIZE_MAX - plus_len)) { + return NULL; + } + + if ((str->length + plus_len) <= lexbor_str_size(str)) { + return str->data; + } + + tmp = lexbor_mraw_realloc(mraw, str->data, (str->length + plus_len)); + if (tmp == NULL) { + return NULL; + } + + str->data = tmp; + + return tmp; +} + +/* Append API */ +lxb_char_t * +lexbor_str_append(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *buff, size_t length) +{ + lxb_char_t *data_begin; + + if (length == 0) { + return str->data; + } + + lexbor_str_check_size_arg_m(str, lexbor_str_size(str), + mraw, (length + 1), NULL); + + data_begin = &str->data[str->length]; + memcpy(data_begin, buff, sizeof(lxb_char_t) * length); + + str->length += length; + str->data[str->length] = '\0'; + + return data_begin; +} + +lxb_char_t * +lexbor_str_append_before(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *buff, size_t length) +{ + lxb_char_t *data_begin; + + lexbor_str_check_size_arg_m(str, lexbor_str_size(str), + mraw, (length + 1), NULL); + + data_begin = &str->data[str->length]; + + memmove(&str->data[length], str->data, sizeof(lxb_char_t) * str->length); + memcpy(str->data, buff, sizeof(lxb_char_t) * length); + + str->length += length; + str->data[str->length] = '\0'; + + return data_begin; +} + +lxb_char_t * +lexbor_str_append_one(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t data) +{ + lexbor_str_check_size_arg_m(str, lexbor_str_size(str), mraw, 2, NULL); + + str->data[str->length] = data; + + str->length += 1; + str->data[str->length] = '\0'; + + return &str->data[(str->length - 1)]; +} + +lxb_char_t * +lexbor_str_append_lowercase(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *data, size_t length) +{ + size_t i; + lxb_char_t *data_begin; + + lexbor_str_check_size_arg_m(str, lexbor_str_size(str), + mraw, (length + 1), NULL); + + data_begin = &str->data[str->length]; + + for (i = 0; i < length; i++) { + data_begin[i] = lexbor_str_res_map_lowercase[ data[i] ]; + } + + data_begin[i] = '\0'; + str->length += length; + + return data_begin; +} + +lxb_char_t * +lexbor_str_append_with_rep_null_chars(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *buff, size_t length) +{ + const lxb_char_t *pos, *res, *end; + size_t current_len = str->length; + + lexbor_str_check_size_arg_m(str, lexbor_str_size(str), + mraw, (length + 1), NULL); + end = buff + length; + + while (buff != end) { + pos = memchr(buff, '\0', sizeof(lxb_char_t) * (end - buff)); + if (pos == NULL) { + break; + } + + res = lexbor_str_append(str, mraw, buff, (pos - buff)); + if (res == NULL) { + return NULL; + } + + res = lexbor_str_append(str, mraw, + lexbor_str_res_ansi_replacement_character, + sizeof(lexbor_str_res_ansi_replacement_character) - 1); + if (res == NULL) { + return NULL; + } + + buff = pos + 1; + } + + if (buff != end) { + res = lexbor_str_append(str, mraw, buff, (end - buff)); + if (res == NULL) { + return NULL; + } + } + + return &str->data[current_len]; +} + +lxb_char_t * +lexbor_str_copy(lexbor_str_t *dest, const lexbor_str_t *target, + lexbor_mraw_t *mraw) +{ + if (target->data == NULL) { + return NULL; + } + + if (dest->data == NULL) { + lexbor_str_init(dest, mraw, target->length); + + if (dest->data == NULL) { + return NULL; + } + } + + return lexbor_str_append(dest, mraw, target->data, target->length); +} + +void +lexbor_str_stay_only_whitespace(lexbor_str_t *target) +{ + size_t i, pos = 0; + lxb_char_t *data = target->data; + + for (i = 0; i < target->length; i++) { + if (lexbor_utils_whitespace(data[i], ==, ||)) { + data[pos] = data[i]; + pos++; + } + } + + target->length = pos; +} + +void +lexbor_str_strip_collapse_whitespace(lexbor_str_t *target) +{ + size_t i, offset, ws_i; + lxb_char_t *data = target->data; + + if (target->length == 0) { + return; + } + + if (lexbor_utils_whitespace(*data, ==, ||)) { + *data = 0x20; + } + + for (i = 0, offset = 0, ws_i = 0; i < target->length; i++) + { + if (lexbor_utils_whitespace(data[i], ==, ||)) { + if (data[ws_i] != 0x20) { + data[offset] = 0x20; + + ws_i = offset; + offset++; + } + } + else { + if (data[ws_i] == 0x20) { + ws_i = offset; + } + + data[offset] = data[i]; + offset++; + } + } + + if (offset != i) { + if (offset != 0) { + if (data[offset - 1] == 0x20) { + offset--; + } + } + + data[offset] = 0x00; + target->length = offset; + } +} + +size_t +lexbor_str_crop_whitespace_from_begin(lexbor_str_t *target) +{ + size_t i; + lxb_char_t *data = target->data; + + for (i = 0; i < target->length; i++) { + if (lexbor_utils_whitespace(data[i], !=, &&)) { + break; + } + } + + if (i != 0 && i != target->length) { + memmove(target->data, &target->data[i], (target->length - i)); + } + + target->length -= i; + return i; +} + +size_t +lexbor_str_whitespace_from_begin(lexbor_str_t *target) +{ + size_t i; + lxb_char_t *data = target->data; + + for (i = 0; i < target->length; i++) { + if (lexbor_utils_whitespace(data[i], !=, &&)) { + break; + } + } + + return i; +} + +size_t +lexbor_str_whitespace_from_end(lexbor_str_t *target) +{ + size_t i = target->length; + lxb_char_t *data = target->data; + + while (i) { + i--; + + if (lexbor_utils_whitespace(data[i], !=, &&)) { + return target->length - (i + 1); + } + } + + return 0; +} + +lxb_char_t * +lexbor_str_copy_to(lexbor_str_t *str, const lxb_char_t *buff, size_t length) +{ + lxb_char_t *data_begin; + + data_begin = &str->data[str->length]; + memcpy(data_begin, buff, sizeof(lxb_char_t) * length); + + str->length += length; + + return data_begin; +} + +lxb_char_t * +lexbor_str_copy_to_with_null(lexbor_str_t *str, + const lxb_char_t *buff, size_t length) +{ + lxb_char_t *data_begin = lexbor_str_copy_to(str, buff, length); + + str->data[str->length] = '\0'; + + return data_begin; +} + +/* + * Data utils + * TODO: All functions need optimization. + */ +const lxb_char_t * +lexbor_str_data_ncasecmp_first(const lxb_char_t *first, const lxb_char_t *sec, + size_t sec_size) +{ + size_t i; + + for (i = 0; i < sec_size; i++) { + if (first[i] == '\0') { + return &first[i]; + } + + if (lexbor_str_res_map_lowercase[ first[i] ] + != lexbor_str_res_map_lowercase[ sec[i] ]) + { + return NULL; + } + } + + return &first[i]; +} + +bool +lexbor_str_data_ncasecmp_end(const lxb_char_t *first, const lxb_char_t *sec, + size_t size) +{ + while (size != 0) { + size--; + + if (lexbor_str_res_map_lowercase[ first[size] ] + != lexbor_str_res_map_lowercase[ sec[size] ]) + { + return false; + } + } + + return true; +} + +bool +lexbor_str_data_ncasecmp_contain(const lxb_char_t *where, size_t where_size, + const lxb_char_t *what, size_t what_size) +{ + for (size_t i = 0; what_size <= (where_size - i); i++) { + if(lexbor_str_data_ncasecmp(&where[i], what, what_size)) { + return true; + } + } + + return false; +} + +bool +lexbor_str_data_ncasecmp(const lxb_char_t *first, const lxb_char_t *sec, + size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (lexbor_str_res_map_lowercase[ first[i] ] + != lexbor_str_res_map_lowercase[ sec[i] ]) + { + return false; + } + } + + return true; +} + +bool +lexbor_str_data_nlocmp_right(const lxb_char_t *first, const lxb_char_t *sec, + size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (first[i] != lexbor_str_res_map_lowercase[ sec[i] ]) { + return false; + } + } + + return true; +} + +bool +lexbor_str_data_nupcmp_right(const lxb_char_t *first, const lxb_char_t *sec, + size_t size) +{ + for (size_t i = 0; i < size; i++) { + if (first[i] != lexbor_str_res_map_uppercase[ sec[i] ]) { + return false; + } + } + + return true; +} + +bool +lexbor_str_data_casecmp(const lxb_char_t *first, const lxb_char_t *sec) +{ + for (;;) { + if (lexbor_str_res_map_lowercase[*first] + != lexbor_str_res_map_lowercase[*sec]) + { + return false; + } + + if (*first == '\0') { + return true; + } + + first++; + sec++; + } +} + +bool +lexbor_str_data_ncmp_end(const lxb_char_t *first, const lxb_char_t *sec, + size_t size) +{ + while (size != 0) { + size--; + + if (first[size] != sec[size]) { + return false; + } + } + + return true; +} + +bool +lexbor_str_data_ncmp_contain(const lxb_char_t *where, size_t where_size, + const lxb_char_t *what, size_t what_size) +{ + for (size_t i = 0; what_size <= (where_size - i); i++) { + if(memcmp(&where[i], what, sizeof(lxb_char_t) * what_size) == 0) { + return true; + } + } + + return false; +} + +bool +lexbor_str_data_ncmp(const lxb_char_t *first, const lxb_char_t *sec, + size_t size) +{ + return memcmp(first, sec, sizeof(lxb_char_t) * size) == 0; +} + +bool +lexbor_str_data_cmp(const lxb_char_t *first, const lxb_char_t *sec) +{ + for (;;) { + if (*first != *sec) { + return false; + } + + if (*first == '\0') { + return true; + } + + first++; + sec++; + } +} + +bool +lexbor_str_data_cmp_ws(const lxb_char_t *first, const lxb_char_t *sec) +{ + for (;;) { + if (*first != *sec) { + return false; + } + + if (lexbor_utils_whitespace(*first, ==, ||) || *first == '\0') { + return true; + } + + first++; + sec++; + } +} + +void +lexbor_str_data_to_lowercase(lxb_char_t *to, const lxb_char_t *from, size_t len) +{ + while (len) { + len--; + + to[len] = lexbor_str_res_map_lowercase[ from[len] ]; + } +} + +void +lexbor_str_data_to_uppercase(lxb_char_t *to, const lxb_char_t *from, size_t len) +{ + while (len) { + len--; + + to[len] = lexbor_str_res_map_uppercase[ from[len] ]; + } +} + +const lxb_char_t * +lexbor_str_data_find_lowercase(const lxb_char_t *data, size_t len) +{ + while (len) { + len--; + + if (data[len] == lexbor_str_res_map_lowercase[ data[len] ]) { + return &data[len]; + } + } + + return NULL; +} + +const lxb_char_t * +lexbor_str_data_find_uppercase(const lxb_char_t *data, size_t len) +{ + while (len) { + len--; + + if (data[len] == lexbor_str_res_map_uppercase[ data[len] ]) { + return &data[len]; + } + } + + return NULL; +} + +/* + * No inline functions for ABI. + */ +lxb_char_t * +lexbor_str_data_noi(lexbor_str_t *str) +{ + return lexbor_str_data(str); +} + +size_t +lexbor_str_length_noi(lexbor_str_t *str) +{ + return lexbor_str_length(str); +} + +size_t +lexbor_str_size_noi(lexbor_str_t *str) +{ + return lexbor_str_size(str); +} + +void +lexbor_str_data_set_noi(lexbor_str_t *str, lxb_char_t *data) +{ + lexbor_str_data_set(str, data); +} + +lxb_char_t * +lexbor_str_length_set_noi(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t length) +{ + return lexbor_str_length_set(str, mraw, length); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str.h new file mode 100644 index 0000000..8e5f380 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str.h @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2018-2023 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_STR_H +#define LEXBOR_STR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" +#include "lexbor/core/mraw.h" +#include "lexbor/core/utils.h" + + +#define lexbor_str_get(str, attr) str->attr +#define lexbor_str_set(str, attr) lexbor_str_get(str, attr) +#define lexbor_str_len(str) lexbor_str_get(str, length) +#define lexbor_str(p) {.data = (lxb_char_t *) (p), sizeof(p) - 1} + +#define lexbor_str_check_size_arg_m(str, size, mraw, plus_len, return_fail) \ + do { \ + void *tmp; \ + \ + if (str->length > (SIZE_MAX - (plus_len))) \ + return (return_fail); \ + \ + if ((str->length + (plus_len)) > (size)) { \ + tmp = lexbor_mraw_realloc(mraw, str->data, \ + (str->length + plus_len)); \ + \ + if (tmp == NULL) { \ + return (return_fail); \ + } \ + \ + str->data = (lxb_char_t *) tmp; \ + } \ + } \ + while (0) + + +typedef struct { + lxb_char_t *data; + size_t length; +} +lexbor_str_t; + + +LXB_API lexbor_str_t * +lexbor_str_create(void); + +LXB_API lxb_char_t * +lexbor_str_init(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t size); + +LXB_API lxb_char_t * +lexbor_str_init_append(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *data, size_t length); + +LXB_API void +lexbor_str_clean(lexbor_str_t *str); + +LXB_API void +lexbor_str_clean_all(lexbor_str_t *str); + +LXB_API lexbor_str_t * +lexbor_str_destroy(lexbor_str_t *str, lexbor_mraw_t *mraw, bool destroy_obj); + + +LXB_API lxb_char_t * +lexbor_str_realloc(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t new_size); + +LXB_API lxb_char_t * +lexbor_str_check_size(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t plus_len); + +/* Append */ +LXB_API lxb_char_t * +lexbor_str_append(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *data, size_t length); + +LXB_API lxb_char_t * +lexbor_str_append_before(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *buff, size_t length); + +LXB_API lxb_char_t * +lexbor_str_append_one(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t data); + +LXB_API lxb_char_t * +lexbor_str_append_lowercase(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *data, size_t length); + +LXB_API lxb_char_t * +lexbor_str_append_with_rep_null_chars(lexbor_str_t *str, lexbor_mraw_t *mraw, + const lxb_char_t *buff, size_t length); + +/* Other functions */ +LXB_API lxb_char_t * +lexbor_str_copy(lexbor_str_t *dest, const lexbor_str_t *target, + lexbor_mraw_t *mraw); + +LXB_API void +lexbor_str_stay_only_whitespace(lexbor_str_t *target); + +LXB_API void +lexbor_str_strip_collapse_whitespace(lexbor_str_t *target); + +LXB_API size_t +lexbor_str_crop_whitespace_from_begin(lexbor_str_t *target); + +LXB_API size_t +lexbor_str_whitespace_from_begin(lexbor_str_t *target); + +LXB_API size_t +lexbor_str_whitespace_from_end(lexbor_str_t *target); + +LXB_API lxb_char_t * +lexbor_str_copy_to(lexbor_str_t *str, const lxb_char_t *buff, size_t length); + +LXB_API lxb_char_t * +lexbor_str_copy_to_with_null(lexbor_str_t *str, + const lxb_char_t *buff, size_t length); + +/* Data utils */ +/* + * [in] first: must be null-terminated + * [in] sec: no matter what data + * [in] sec_size: size of the 'sec' buffer + * + * Function compare two lxb_char_t data until find '\0' in first arg. + * Successfully if the function returned a pointer starting with '\0', + * otherwise, if the data of the second buffer is insufficient function returned + * position in first buffer. + * If function returns NULL, the data are not equal. + */ +LXB_API const lxb_char_t * +lexbor_str_data_ncasecmp_first(const lxb_char_t *first, const lxb_char_t *sec, + size_t sec_size); +LXB_API bool +lexbor_str_data_ncasecmp_end(const lxb_char_t *first, const lxb_char_t *sec, + size_t size); +LXB_API bool +lexbor_str_data_ncasecmp_contain(const lxb_char_t *where, size_t where_size, + const lxb_char_t *what, size_t what_size); +LXB_API bool +lexbor_str_data_ncasecmp(const lxb_char_t *first, const lxb_char_t *sec, + size_t size); +LXB_API bool +lexbor_str_data_nlocmp_right(const lxb_char_t *first, const lxb_char_t *sec, + size_t size); +LXB_API bool +lexbor_str_data_nupcmp_right(const lxb_char_t *first, const lxb_char_t *sec, + size_t size); +LXB_API bool +lexbor_str_data_casecmp(const lxb_char_t *first, const lxb_char_t *sec); + +LXB_API bool +lexbor_str_data_ncmp_end(const lxb_char_t *first, const lxb_char_t *sec, + size_t size); +LXB_API bool +lexbor_str_data_ncmp_contain(const lxb_char_t *where, size_t where_size, + const lxb_char_t *what, size_t what_size); +LXB_API bool +lexbor_str_data_ncmp(const lxb_char_t *first, const lxb_char_t *sec, + size_t size); + +LXB_API bool +lexbor_str_data_cmp(const lxb_char_t *first, const lxb_char_t *sec); + +LXB_API bool +lexbor_str_data_cmp_ws(const lxb_char_t *first, const lxb_char_t *sec); + +LXB_API void +lexbor_str_data_to_lowercase(lxb_char_t *to, const lxb_char_t *from, size_t len); + +LXB_API void +lexbor_str_data_to_uppercase(lxb_char_t *to, const lxb_char_t *from, size_t len); + +LXB_API const lxb_char_t * +lexbor_str_data_find_lowercase(const lxb_char_t *data, size_t len); + +LXB_API const lxb_char_t * +lexbor_str_data_find_uppercase(const lxb_char_t *data, size_t len); + + +/* + * Inline functions + */ +lxb_inline lxb_char_t * +lexbor_str_data(lexbor_str_t *str) +{ + return str->data; +} + +lxb_inline size_t +lexbor_str_length(lexbor_str_t *str) +{ + return str->length; +} + +lxb_inline size_t +lexbor_str_size(lexbor_str_t *str) +{ + return lexbor_mraw_data_size(str->data); +} + +lxb_inline void +lexbor_str_data_set(lexbor_str_t *str, lxb_char_t *data) +{ + str->data = data; +} + +lxb_inline lxb_char_t * +lexbor_str_length_set(lexbor_str_t *str, lexbor_mraw_t *mraw, size_t length) +{ + if (length >= lexbor_str_size(str)) { + lxb_char_t *tmp; + + tmp = lexbor_str_realloc(str, mraw, length + 1); + if (tmp == NULL) { + return NULL; + } + } + + str->length = length; + str->data[length] = 0x00; + + return str->data; +} + +/* + * No inline functions for ABI. + */ +LXB_API lxb_char_t * +lexbor_str_data_noi(lexbor_str_t *str); + +LXB_API size_t +lexbor_str_length_noi(lexbor_str_t *str); + +LXB_API size_t +lexbor_str_size_noi(lexbor_str_t *str); + +LXB_API void +lexbor_str_data_set_noi(lexbor_str_t *str, lxb_char_t *data); + +LXB_API lxb_char_t * +lexbor_str_length_set_noi(lexbor_str_t *str, lexbor_mraw_t *mraw, + size_t length); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_STR_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str_res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str_res.h new file mode 100644 index 0000000..be34a0e --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/str_res.h @@ -0,0 +1,360 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + + +LXB_API const lxb_char_t +lexbor_str_res_ansi_replacement_character[4] = "\xEF\xBF\xBD"; + +LXB_API const lxb_char_t +lexbor_str_res_map_num[256] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +LXB_API const lxb_char_t +lexbor_str_res_map_hex[256] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +LXB_API const lxb_char_t +lexbor_str_res_map_lowercase[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, + 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, + 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, + 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, + 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff +}; + +LXB_API const lxb_char_t +lexbor_str_res_map_uppercase[256] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, + 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, + 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, + 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, + 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, + 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x41, 0x42, + 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, + 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, + 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, + 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, + 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, + 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, + 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, + 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, + 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, + 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, + 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, + 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, + 0xfc, 0xfd, 0xfe, 0xff +}; + +LXB_API const size_t +lexbor_str_res_replacement_character[160] = +{ + 65533, 1, 2, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65, 66, 67, 68, 69, 70, 71, + 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 8364, 129, 8218, 402, 8222, 8230, 8224, + 8225, 710, 8240, 352, 8249, 338, 141, 381, 143, + 144, 8216, 8217, 8220, 8221, 8226, 8211, 8212, 732, + 8482, 353, 8250, 339, 157, 382, 376 +}; + +LXB_API const size_t +lexbor_str_res_alphanumeric_character[256] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, + 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +LXB_API const size_t +lexbor_str_res_alpha_character[256] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, + 0x0b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f, 0x0a, 0x0b, 0x0c, 0x0d, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +LXB_API const unsigned char +lexbor_tokenizer_chars_map[256] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x02, 0x02, 0xff, 0x02, 0x02, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x02, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff +}; + +LXB_API const lxb_char_t +lexbor_str_res_map_hex_to_char[17] = +{ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x00 +}; + +LXB_API const lxb_char_t +lexbor_str_res_map_hex_to_char_lowercase[17] = +{ + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, + 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x00 +}; + +LXB_API const char * +lexbor_str_res_char_to_two_hex_value[257] = +{ + "00", "01", "02", "03", "04", "05", "06", "07", + "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", + "10", "11", "12", "13", "14", "15", "16", "17", + "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", + "20", "21", "22", "23", "24", "25", "26", "27", + "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", + "30", "31", "32", "33", "34", "35", "36", "37", + "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", + "40", "41", "42", "43", "44", "45", "46", "47", + "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", + "50", "51", "52", "53", "54", "55", "56", "57", + "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", + "60", "61", "62", "63", "64", "65", "66", "67", + "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", + "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", + "80", "81", "82", "83", "84", "85", "86", "87", + "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", + "90", "91", "92", "93", "94", "95", "96", "97", + "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", + "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", + "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", + "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", + "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", + "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", + "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", + "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", + "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", + "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", + "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", + "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", + "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF", + NULL +}; + +LXB_API const char * +lexbor_str_res_char_to_two_hex_value_lowercase[257] = +{ + "00", "01", "02", "03", "04", "05", "06", "07", + "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", + "10", "11", "12", "13", "14", "15", "16", "17", + "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", + "20", "21", "22", "23", "24", "25", "26", "27", + "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", + "30", "31", "32", "33", "34", "35", "36", "37", + "38", "39", "3a", "3b", "3c", "3d", "3e", "3f", + "40", "41", "42", "43", "44", "45", "46", "47", + "48", "49", "4a", "4b", "4c", "4d", "4e", "4f", + "50", "51", "52", "53", "54", "55", "56", "57", + "58", "59", "5a", "5b", "5c", "5d", "5e", "5f", + "60", "61", "62", "63", "64", "65", "66", "67", + "68", "69", "6a", "6b", "6c", "6d", "6e", "6f", + "70", "71", "72", "73", "74", "75", "76", "77", + "78", "79", "7a", "7b", "7c", "7d", "7e", "7f", + "80", "81", "82", "83", "84", "85", "86", "87", + "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", + "90", "91", "92", "93", "94", "95", "96", "97", + "98", "99", "9a", "9b", "9c", "9d", "9e", "9f", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af", + "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", + "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf", + "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", + "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf", + "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", + "d8", "d9", "da", "db", "dc", "dd", "de", "df", + "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", + "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef", + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff", + NULL +}; diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/strtod.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/strtod.c new file mode 100644 index 0000000..2dad45c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/strtod.c @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2015-2019 NGINX, Inc. + * Copyright (C) 2019-2025 F5, Inc. + * Copyright (C) 2015-2021 Igor Sysoev + * Copyright (C) 2017-2025 Dmitry Volyntsev + * Copyright (C) 2019-2022 Alexander Borisov + * Copyright (C) 2022-2025 Vadim Zhestikov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) Alexander Borisov + */ + +#include +#include + +#include "lexbor/core/diyfp.h" +#include "lexbor/core/strtod.h" + + +/* + * Max double: 1.7976931348623157 x 10^308 + * Min non-zero double: 4.9406564584124654 x 10^-324 + * Any x >= 10^309 is interpreted as +infinity. + * Any x <= 10^-324 is interpreted as 0. + * Note that 2.5e-324 (despite being smaller than the min double) + * will be read as non-zero (equal to the min non-zero double). + */ + +#define LEXBOR_DECIMAL_POWER_MAX 309 +#define LEXBOR_DECIMAL_POWER_MIN (-324) + +#define LEXBOR_UINT64_MAX lexbor_uint64_hl(0xFFFFFFFF, 0xFFFFFFFF) +#define LEXBOR_UINT64_DECIMAL_DIGITS_MAX 19 + +#define LEXBOR_DENOM_LOG 3 +#define LEXBOR_DENOM (1 << LEXBOR_DENOM_LOG) + + +static lexbor_diyfp_t +lexbor_strtod_diyfp_read(const lxb_char_t *start, size_t length, + int *remaining); + +static double +lexbor_strtod_diyfp_strtod(const lxb_char_t *start, size_t length, int exp); + + +/* + * Reads digits from the buffer and converts them to a uint64. + * Reads in as many digits as fit into a uint64. + * When the string starts with "1844674407370955161" no further digit is read. + * Since 2^64 = 18446744073709551616 it would still be possible read another + * digit if it was less or equal than 6, but this would complicate the code. + */ +lxb_inline uint64_t +lexbor_strtod_read_uint64(const lxb_char_t *start, size_t length, + size_t *ndigits) +{ + lxb_char_t d; + uint64_t value; + const lxb_char_t *p, *e; + + value = 0; + + p = start; + e = p + length; + + while (p < e && value <= (UINT64_MAX / 10 - 1)) { + d = *p++ - '0'; + value = 10 * value + d; + } + + *ndigits = p - start; + + return value; +} + +/* + * Reads a nxt_diyfp_t from the buffer. + * The returned nxt_diyfp_t is not necessarily normalized. + * If remaining is zero then the returned nxt_diyfp_t is accurate. + * Otherwise it has been rounded and has error of at most 1/2 ulp. + */ +static lexbor_diyfp_t +lexbor_strtod_diyfp_read(const lxb_char_t *start, size_t length, int *remaining) +{ + size_t read; + uint64_t significand; + + significand = lexbor_strtod_read_uint64(start, length, &read); + + /* Round the significand. */ + + if (length != read) { + if (start[read] >= '5') { + significand++; + } + } + + *remaining = (int) (length - read); + + return lexbor_diyfp(significand, 0); +} + +/* + * Returns 10^exp as an exact nxt_diyfp_t. + * The given exp must be in the range [1; NXT_DECIMAL_EXPONENT_DIST[. + */ +lxb_inline lexbor_diyfp_t +lexbor_strtod_adjust_pow10(int exp) +{ + switch (exp) { + case 1: + return lexbor_diyfp(lexbor_uint64_hl(0xa0000000, 00000000), -60); + case 2: + return lexbor_diyfp(lexbor_uint64_hl(0xc8000000, 00000000), -57); + case 3: + return lexbor_diyfp(lexbor_uint64_hl(0xfa000000, 00000000), -54); + case 4: + return lexbor_diyfp(lexbor_uint64_hl(0x9c400000, 00000000), -50); + case 5: + return lexbor_diyfp(lexbor_uint64_hl(0xc3500000, 00000000), -47); + case 6: + return lexbor_diyfp(lexbor_uint64_hl(0xf4240000, 00000000), -44); + case 7: + return lexbor_diyfp(lexbor_uint64_hl(0x98968000, 00000000), -40); + default: + return lexbor_diyfp(0, 0); + } +} + +/* + * Returns the significand size for a given order of magnitude. + * If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude. + * This function returns the number of significant binary digits v will have + * once its encoded into a double. In almost all cases this is equal to + * NXT_SIGNIFICAND_SIZE. The only exception are denormals. They start with + * leading zeroes and their effective significand-size is hence smaller. + */ +lxb_inline int +lexbor_strtod_diyfp_sgnd_size(int order) +{ + if (order >= (LEXBOR_DBL_EXPONENT_DENORMAL + LEXBOR_SIGNIFICAND_SIZE)) { + return LEXBOR_SIGNIFICAND_SIZE; + } + + if (order <= LEXBOR_DBL_EXPONENT_DENORMAL) { + return 0; + } + + return order - LEXBOR_DBL_EXPONENT_DENORMAL; +} + +/* + * Returns either the correct double or the double that is just below + * the correct double. + */ +static double +lexbor_strtod_diyfp_strtod(const lxb_char_t *start, size_t length, int exp) +{ + int magnitude, prec_digits; + int remaining, dec_exp, adj_exp, orig_e, shift; + int64_t error; + uint64_t prec_bits, half_way; + lexbor_diyfp_t value, pow, adj_pow, rounded; + + value = lexbor_strtod_diyfp_read(start, length, &remaining); + + exp += remaining; + + /* + * Since some digits may have been dropped the value is not accurate. + * If remaining is different than 0 than the error is at most .5 ulp + * (unit in the last place). + * Using a common denominator to avoid dealing with fractions. + */ + + error = (remaining == 0 ? 0 : LEXBOR_DENOM / 2); + + orig_e = value.exp; + value = lexbor_diyfp_normalize(value); + error <<= orig_e - value.exp; + + if (exp < LEXBOR_DECIMAL_EXPONENT_MIN) { + return 0.0; + } + + pow = lexbor_cached_power_dec(exp, &dec_exp); + + if (dec_exp != exp) { + adj_exp = exp - dec_exp; + adj_pow = lexbor_strtod_adjust_pow10(exp - dec_exp); + value = lexbor_diyfp_mul(value, adj_pow); + + if (LEXBOR_UINT64_DECIMAL_DIGITS_MAX - (int) length < adj_exp) { + /* + * The adjustment power is exact. There is hence only + * an error of 0.5. + */ + error += LEXBOR_DENOM / 2; + } + } + + value = lexbor_diyfp_mul(value, pow); + + /* + * The error introduced by a multiplication of a * b equals + * error_a + error_b + error_a * error_b / 2^64 + 0.5 + * Substituting a with 'value' and b with 'pow': + * error_b = 0.5 (all cached powers have an error of less than 0.5 ulp), + * error_ab = 0 or 1 / NXT_DENOM > error_a * error_b / 2^64. + */ + + error += LEXBOR_DENOM + (error != 0 ? 1 : 0); + + orig_e = value.exp; + value = lexbor_diyfp_normalize(value); + error <<= orig_e - value.exp; + + /* + * Check whether the double's significand changes when the error is added + * or subtracted. + */ + + magnitude = LEXBOR_DIYFP_SIGNIFICAND_SIZE + value.exp; + prec_digits = LEXBOR_DIYFP_SIGNIFICAND_SIZE + - lexbor_strtod_diyfp_sgnd_size(magnitude); + + if (prec_digits + LEXBOR_DENOM_LOG >= LEXBOR_DIYFP_SIGNIFICAND_SIZE) { + /* + * This can only happen for very small denormals. In this case the + * half-way multiplied by the denominator exceeds the range of uint64. + * Simply shift everything to the right. + */ + shift = prec_digits + LEXBOR_DENOM_LOG + - LEXBOR_DIYFP_SIGNIFICAND_SIZE + 1; + + value = lexbor_diyfp_shift_right(value, shift); + + /* + * Add 1 for the lost precision of error, and NXT_DENOM + * for the lost precision of value.significand. + */ + error = (error >> shift) + 1 + LEXBOR_DENOM; + prec_digits -= shift; + } + + prec_bits = value.significand & (((uint64_t) 1 << prec_digits) - 1); + prec_bits *= LEXBOR_DENOM; + + half_way = (uint64_t) 1 << (prec_digits - 1); + half_way *= LEXBOR_DENOM; + + rounded = lexbor_diyfp_shift_right(value, prec_digits); + + if (prec_bits >= half_way + error) { + rounded.significand++; + } + + return lexbor_diyfp_2d(rounded); +} + +double +lexbor_strtod_internal(const lxb_char_t *start, size_t length, int exp) +{ + size_t left, right; + const lxb_char_t *p, *e, *b; + + /* Trim leading zeroes. */ + + p = start; + e = p + length; + + while (p < e) { + if (*p != '0') { + start = p; + break; + } + + p++; + } + + left = e - p; + + /* Trim trailing zeroes. */ + + b = start; + p = b + left - 1; + + while (p > b) { + if (*p != '0') { + break; + } + + p--; + } + + right = p - b + 1; + + length = right; + + if (length == 0) { + return 0.0; + } + + exp += (int) (left - right); + + if (exp + (int) length - 1 >= LEXBOR_DECIMAL_POWER_MAX) { + return INFINITY; + } + + if (exp + (int) length <= LEXBOR_DECIMAL_POWER_MIN) { + return 0.0; + } + + return lexbor_strtod_diyfp_strtod(start, length, exp); +} + +#undef LEXBOR_DECIMAL_POWER_MAX +#undef LEXBOR_DECIMAL_POWER_MIN + +#undef LEXBOR_UINT64_MAX +#undef LEXBOR_UINT64_DECIMAL_DIGITS_MAX + +#undef LEXBOR_DENOM_LOG +#undef LEXBOR_DENOM diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/strtod.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/strtod.h new file mode 100644 index 0000000..0f834ba --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/strtod.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015-2019 NGINX, Inc. + * Copyright (C) 2019-2025 F5, Inc. + * Copyright (C) 2015-2021 Igor Sysoev + * Copyright (C) 2017-2025 Dmitry Volyntsev + * Copyright (C) 2019-2022 Alexander Borisov + * Copyright (C) 2022-2025 Vadim Zhestikov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (C) Alexander Borisov + */ + +#ifndef LEXBOR_STRTOD_H +#define LEXBOR_STRTOD_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +LXB_API double +lexbor_strtod_internal(const lxb_char_t *start, size_t length, int exp); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_STRTOD_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/swar.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/swar.h new file mode 100644 index 0000000..ec0a13b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/swar.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 Alexander Borisov + * + * Author: Niels Dossche + */ + +#ifndef LEXBOR_SWAR_H +#define LEXBOR_SWAR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "lexbor/core/base.h" + + +/* + * Based on techniques from https://graphics.stanford.edu/~seander/bithacks.html + */ +#define LEXBOR_SWAR_ONES (~((size_t) 0) / 0xFF) +#define LEXBOR_SWAR_REPEAT(x) (LEXBOR_SWAR_ONES * (x)) +#define LEXBOR_SWAR_HAS_ZERO(v) (((v) - LEXBOR_SWAR_ONES) & ~(v) & LEXBOR_SWAR_REPEAT(0x80)) +#define LEXBOR_SWAR_IS_LITTLE_ENDIAN (*(unsigned char *) &(uint16_t){1}) + + +/* + * When handling hot loops that search for a set of characters, + * this function can be used to quickly move the data pointer much + * closer to the first occurrence of such a character. + */ +lxb_inline const lxb_char_t * +lexbor_swar_seek4(const lxb_char_t *data, const lxb_char_t *end, + lxb_char_t c1, lxb_char_t c2, lxb_char_t c3, lxb_char_t c4) +{ + size_t bytes, matches, t1, t2, t3, t4; + + if (LEXBOR_SWAR_IS_LITTLE_ENDIAN) { + while (data + sizeof(size_t) <= end) { + memcpy(&bytes, data, sizeof(size_t)); + + t1 = bytes ^ LEXBOR_SWAR_REPEAT(c1); + t2 = bytes ^ LEXBOR_SWAR_REPEAT(c2); + t3 = bytes ^ LEXBOR_SWAR_REPEAT(c3); + t4 = bytes ^ LEXBOR_SWAR_REPEAT(c4); + matches = LEXBOR_SWAR_HAS_ZERO(t1) | LEXBOR_SWAR_HAS_ZERO(t2) + | LEXBOR_SWAR_HAS_ZERO(t3) | LEXBOR_SWAR_HAS_ZERO(t4); + + if (matches) { + data += ((((matches - 1) & LEXBOR_SWAR_ONES) * LEXBOR_SWAR_ONES) + >> (sizeof(size_t) * 8 - 8)) - 1; + break; + } else { + data += sizeof(size_t); + } + } + } + + return data; +} + +lxb_inline const lxb_char_t * +lexbor_swar_seek3(const lxb_char_t *data, const lxb_char_t *end, + lxb_char_t c1, lxb_char_t c2, lxb_char_t c3) +{ + size_t bytes, matches, t1, t2, t3; + + if (LEXBOR_SWAR_IS_LITTLE_ENDIAN) { + while (data + sizeof(size_t) <= end) { + memcpy(&bytes, data, sizeof(size_t)); + + t1 = bytes ^ LEXBOR_SWAR_REPEAT(c1); + t2 = bytes ^ LEXBOR_SWAR_REPEAT(c2); + t3 = bytes ^ LEXBOR_SWAR_REPEAT(c3); + matches = LEXBOR_SWAR_HAS_ZERO(t1) | LEXBOR_SWAR_HAS_ZERO(t2) + | LEXBOR_SWAR_HAS_ZERO(t3); + + if (matches) { + data += ((((matches - 1) & LEXBOR_SWAR_ONES) * LEXBOR_SWAR_ONES) + >> (sizeof(size_t) * 8 - 8)) - 1; + break; + } else { + data += sizeof(size_t); + } + } + } + + return data; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_SWAR_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/types.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/types.h new file mode 100644 index 0000000..00f82ad --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/types.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_TYPES_H +#define LEXBOR_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +/* Inline */ +#ifdef _MSC_VER + #define lxb_inline static __forceinline +#else + #define lxb_inline static inline +#endif + + +/* Simple types */ +typedef uint32_t lxb_codepoint_t; +typedef unsigned char lxb_char_t; +typedef unsigned int lxb_status_t; + +/* Callbacks */ +typedef lxb_status_t (*lexbor_callback_f)(const lxb_char_t *buffer, + size_t size, void *ctx); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_TYPES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/utils.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/utils.c new file mode 100644 index 0000000..9ca393a --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/utils.c @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/utils.h" + + +size_t +lexbor_utils_power(size_t t, size_t k) +{ + size_t res = 1; + + while (k) { + if (k & 1) { + res *= t; + } + + t *= t; + k >>= 1; + } + + return res; +} + +size_t +lexbor_utils_hash_hash(const lxb_char_t *key, size_t key_size) +{ + size_t hash, i; + + for (hash = i = 0; i < key_size; i++) { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return hash; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/utils.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/utils.h new file mode 100644 index 0000000..f0ebf16 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/core/utils.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_UTILS_H +#define LEXBOR_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" + + +#define lexbor_utils_whitespace(onechar, action, logic) \ + (onechar action ' ' logic \ + onechar action '\t' logic \ + onechar action '\n' logic \ + onechar action '\f' logic \ + onechar action '\r') + + +LXB_API size_t +lexbor_utils_power(size_t t, size_t k); + +LXB_API size_t +lexbor_utils_hash_hash(const lxb_char_t *key, size_t key_size); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_UTILS_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule.c new file mode 100644 index 0000000..6c5435d --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule.c @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/at_rule.h" +#include "lexbor/css/css.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/stylesheet.h" +#include "lexbor/css/at_rule/state.h" +#include "lexbor/css/at_rule/types.h" +#include "lexbor/css/at_rule/res.h" +#include "lexbor/core/serialize.h" + + +const lxb_css_entry_at_rule_data_t * +lxb_css_at_rule_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_at_rule_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_entry_at_rule_data_t * +lxb_css_at_rule_by_id(uintptr_t id) +{ + return &lxb_css_at_rule_data[id]; +} + +lxb_css_rule_at_t * +lxb_css_at_rule_create(lxb_css_parser_t *parser, + const lxb_char_t *name, size_t length, + const lxb_css_entry_at_rule_data_t **out_entry) +{ + void *prop; + const lxb_css_entry_at_rule_data_t *entry; + lxb_css_at_rule__custom_t *custom; + lxb_css_rule_at_t *at; + + at = lxb_css_rule_at_create(parser->memory); + if (at == NULL) { + return NULL; + } + + entry = lxb_css_at_rule_by_name(name, length); + if (entry == NULL) { + entry = lxb_css_at_rule_by_id(LXB_CSS_AT_RULE__CUSTOM); + + prop = entry->create(parser->memory); + if (prop == NULL) { + goto failed; + } + + custom = prop; + + (void) lexbor_str_init(&custom->name, parser->memory->mraw, length); + if (custom->name.data == NULL) { + goto failed; + } + + memcpy(custom->name.data, name, length); + + custom->name.length = length; + custom->name.data[custom->name.length] = 0x00; + } + else { + prop = entry->create(parser->memory); + if (prop == NULL) { + goto failed; + } + } + + at->type = entry->unique; + at->u.user = prop; + + if (out_entry != NULL) { + *out_entry = entry; + } + + return at; + +failed: + + if (prop != NULL) { + (void) entry->destroy(parser->memory, prop, true); + } + + if (at != NULL) { + (void) lxb_css_rule_at_destroy(at, true); + } + + if (out_entry != NULL) { + *out_entry = NULL; + } + + return NULL; +} + +void * +lxb_css_at_rule_destroy(lxb_css_memory_t *memory, void *value, + lxb_css_at_rule_type_t type, bool self_destroy) +{ + const lxb_css_entry_at_rule_data_t *data; + + data = lxb_css_at_rule_by_id(type); + if (data == NULL) { + return value; + } + + return data->destroy(memory, value, self_destroy); +} + +lxb_status_t +lxb_css_at_rule_convert_to_undef(lxb_css_parser_t *parser, + lxb_css_rule_at_t *at) +{ + lxb_css_at_rule__undef_t *undef; + + undef = lxb_css_at_rule__undef_create(parser->memory); + if (undef == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + undef->type = at->type; + + (void) lxb_css_at_rule_destroy(parser->memory, at, undef->type, false); + + at->type = LXB_CSS_AT_RULE__UNDEF; + at->u.undef = undef; + + return lxb_css_make_data(parser, &at->u.undef->prelude, + at->prelude_begin, at->prelude_end); +} + +lxb_status_t +lxb_css_at_rule_serialize(const void *style, lxb_css_at_rule_type_t type, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_entry_at_rule_data_t *data; + + data = lxb_css_at_rule_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + return data->serialize(style, cb, ctx); +} + +lxb_status_t +lxb_css_at_rule_serialize_str(const void *style, lxb_css_at_rule_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str) +{ + const lxb_css_entry_at_rule_data_t *data; + + data = lxb_css_at_rule_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + return lxb_css_serialize_str_handler(style, str, mraw, data->serialize); +} + +lxb_status_t +lxb_css_at_rule_serialize_name(const void *style, lxb_css_at_rule_type_t type, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_entry_at_rule_data_t *data; + + if (type == LXB_CSS_AT_RULE__UNDEF) { + return lxb_css_at_rule__undef_serialize_name(style, cb, ctx); + } + else if (type == LXB_CSS_AT_RULE__CUSTOM) { + return lxb_css_at_rule__custom_serialize_name(style, cb, ctx); + } + + data = lxb_css_at_rule_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + return cb(data->name, data->length, ctx); +} + +lxb_status_t +lxb_css_at_rule_serialize_name_str(const void *style, lxb_css_at_rule_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str) +{ + const lxb_css_entry_at_rule_data_t *data; + + if (type == LXB_CSS_AT_RULE__UNDEF) { + return lxb_css_serialize_str_handler(style, str, mraw, + lxb_css_at_rule__undef_serialize_name); + } + else if (type == LXB_CSS_AT_RULE__CUSTOM) { + return lxb_css_serialize_str_handler(style, str, mraw, + lxb_css_at_rule__custom_serialize_name); + } + + data = lxb_css_at_rule_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + if (str->data == NULL) { + lexbor_str_init(str, mraw, data->length); + if (str->data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + (void) lexbor_str_append(str, mraw, data->name, data->length); + + return LXB_STATUS_OK; +} + +/* _undef. */ + +void * +lxb_css_at_rule__undef_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_at_rule__undef_t)); +} + +void * +lxb_css_at_rule__undef_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + if (style == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_mraw_free(memory->mraw, style); + } + + return style; +} + +lxb_status_t +lxb_css_at_rule__undef_serialize(const void *at, lexbor_serialize_cb_f cb, + void *ctx) +{ + lxb_status_t status; + const lxb_css_entry_at_rule_data_t *data; + const lxb_css_at_rule__undef_t *undef = at; + + static const lxb_char_t wc_str[] = " "; + static const lxb_char_t lb_str[] = "{"; + static const lxb_char_t rb_str[] = "}"; + static const lxb_char_t sm_str[] = ";"; + + data = lxb_css_at_rule_by_id(undef->type); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + if (undef->prelude.data != NULL) { + lexbor_serialize_write(cb, wc_str, (sizeof(wc_str) - 1), ctx, status); + lexbor_serialize_write(cb, undef->prelude.data, undef->prelude.length, + ctx, status); + } + + if (undef->block != NULL) { + lexbor_serialize_write(cb, lb_str, (sizeof(lb_str) - 1), ctx, status); + + status = lxb_css_rule_list_serialize(undef->block, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, rb_str, (sizeof(rb_str) - 1), ctx, status); + } + else { + lexbor_serialize_write(cb, sm_str, (sizeof(sm_str) - 1), ctx, status); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_at_rule__undef_serialize_name(const void *at, lexbor_serialize_cb_f cb, + void *ctx) +{ + const lxb_css_entry_at_rule_data_t *data; + const lxb_css_at_rule__undef_t *undef = at; + + data = lxb_css_at_rule_by_id(undef->type); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + return cb(data->name, data->length, ctx); +} + +/* _custom. */ + +void * +lxb_css_at_rule__custom_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_at_rule__custom_t)); +} + +void * +lxb_css_at_rule__custom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + if (style == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_mraw_free(memory->mraw, style); + } + + return style; +} + +lxb_status_t +lxb_css_at_rule__custom_serialize(const void *at, lexbor_serialize_cb_f cb, + void *ctx) +{ + lxb_status_t status; + const lxb_css_at_rule__custom_t *custom = at; + + static const lxb_char_t ws_str[] = " "; + static const lxb_char_t lb_str[] = "{"; + static const lxb_char_t rb_str[] = "}"; + + + if (custom->prelude.data != NULL) { + lexbor_serialize_write(cb, ws_str, (sizeof(ws_str) - 1), ctx, status); + lexbor_serialize_write(cb, custom->prelude.data, custom->prelude.length, + ctx, status); + } + + if (custom->block != NULL) { + lexbor_serialize_write(cb, lb_str, (sizeof(lb_str) - 1), ctx, status); + + status = lxb_css_rule_list_serialize(custom->block, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, rb_str, (sizeof(rb_str) - 1), ctx, status); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_at_rule__custom_serialize_name(const void *at, lexbor_serialize_cb_f cb, + void *ctx) +{ + const lxb_css_at_rule__custom_t *custom = at; + + return cb(custom->name.data, custom->name.length, ctx); +} + +/* Media. */ + +void * +lxb_css_at_rule_media_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_at_rule_media_t)); +} + +void * +lxb_css_at_rule_media_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_at_rule__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_at_rule_media_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx) +{ + return LXB_STATUS_OK; +} + +/* Namespace. */ + +void * +lxb_css_at_rule_namespace_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_at_rule_namespace_t)); +} + +void * +lxb_css_at_rule_namespace_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_at_rule__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_at_rule_namespace_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx) +{ + return LXB_STATUS_OK; +} + +/* Font-face. */ + +void * +lxb_css_at_rule_font_face_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_at_rule_font_face_t)); +} + +void * +lxb_css_at_rule_font_face_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_at_rule__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_at_rule_font_face_serialize(const void *font_face, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_at_rule_font_face_t *ff = font_face; + + static const lxb_char_t lb_str[] = " {"; + static const lxb_char_t rb_str[] = "}"; + + if (ff->block != NULL) { + lexbor_serialize_write(cb, lb_str, (sizeof(lb_str) - 1), ctx, status); + + status = lxb_css_rule_list_serialize(ff->block, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, rb_str, (sizeof(rb_str) - 1), ctx, status); + } + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule.h new file mode 100644 index 0000000..cacfa4c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule.h @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_AT_RULE_H +#define LXB_CSS_AT_RULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/syntax/syntax.h" +#include "lexbor/css/at_rule/const.h" + + +typedef struct { + lxb_css_at_rule_type_t type; + lexbor_str_t prelude; + lxb_css_rule_list_t *block; +} +lxb_css_at_rule__undef_t; + +typedef struct { + lexbor_str_t name; + lexbor_str_t prelude; + lxb_css_rule_list_t *block; +} +lxb_css_at_rule__custom_t; + +typedef struct { + lxb_css_rule_list_t *block; +} +lxb_css_at_rule_media_t; + +typedef struct { + uintptr_t reserved; +} +lxb_css_at_rule_namespace_t; + +typedef struct { + lxb_css_rule_list_t *block; +} +lxb_css_at_rule_font_face_t; + + +LXB_API const lxb_css_entry_at_rule_data_t * +lxb_css_at_rule_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_entry_at_rule_data_t * +lxb_css_at_rule_by_id(uintptr_t id); + +LXB_API lxb_css_rule_at_t * +lxb_css_at_rule_create(lxb_css_parser_t *parser, + const lxb_char_t *name, size_t length, + const lxb_css_entry_at_rule_data_t **out_entry); + +LXB_API void * +lxb_css_at_rule_destroy(lxb_css_memory_t *memory, void *value, + lxb_css_at_rule_type_t type, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_at_rule_convert_to_undef(lxb_css_parser_t *parser, + lxb_css_rule_at_t *at); + +LXB_API lxb_status_t +lxb_css_at_rule_serialize(const void *style, lxb_css_at_rule_type_t type, + lexbor_serialize_cb_f cb, void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_serialize_str(const void *style, lxb_css_at_rule_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str); +LXB_API lxb_status_t +lxb_css_at_rule_serialize_name(const void *style, lxb_css_at_rule_type_t type, + lexbor_serialize_cb_f cb, void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_serialize_name_str(const void *style, lxb_css_at_rule_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str); + +/* _undef. */ + +LXB_API void * +lxb_css_at_rule__undef_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_at_rule__undef_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_at_rule__undef_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule__undef_serialize_name(const void *at, lexbor_serialize_cb_f cb, + void *ctx); + +/* _custom. */ + +LXB_API void * +lxb_css_at_rule__custom_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_at_rule__custom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_at_rule__custom_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule__custom_serialize_name(const void *at, lexbor_serialize_cb_f cb, + void *ctx); + +/* Media. */ + +LXB_API void * +lxb_css_at_rule_media_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_at_rule_media_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_at_rule_media_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx); + +/* Namespace. */ + +LXB_API void * +lxb_css_at_rule_namespace_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_at_rule_namespace_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_at_rule_namespace_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx); + +/* Font-face. */ + +LXB_API void * +lxb_css_at_rule_font_face_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_at_rule_font_face_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_at_rule_font_face_serialize(const void *style, lexbor_serialize_cb_f cb, + void *ctx); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_AT_RULE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/const.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/const.h new file mode 100644 index 0000000..29ba3dd --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/const.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_AT_RULE_CONST_H +#define LXB_CSS_AT_RULE_CONST_H + + +#include "lexbor/css/value/const.h" + + +enum { + LXB_CSS_AT_RULE__UNDEF = 0x0000, + LXB_CSS_AT_RULE__CUSTOM = 0x0001, + LXB_CSS_AT_RULE_FONT_FACE = 0x0002, + LXB_CSS_AT_RULE_MEDIA = 0x0003, + LXB_CSS_AT_RULE_NAMESPACE = 0x0004, + LXB_CSS_AT_RULE__LAST_ENTRY = 0x0005 +}; +typedef uintptr_t lxb_css_at_rule_type_t; + + +#endif /* LXB_CSS_AT_RULE_CONST_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/res.h new file mode 100644 index 0000000..6604fb9 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/res.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_AT_RULE_RES_H +#define LXB_CSS_AT_RULE_RES_H + +#include "lexbor/core/shs.h" +#include "lexbor/css/at_rule/const.h" + + +static const lxb_css_entry_at_rule_data_t lxb_css_at_rule_data[LXB_CSS_AT_RULE__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_AT_RULE__UNDEF, &lxb_css_at_rule__undef_cb, + lxb_css_at_rule__undef_create, lxb_css_at_rule__undef_destroy, lxb_css_at_rule__undef_serialize, (void *) (uintptr_t) LXB_CSS_AT_RULE__UNDEF}, + {(lxb_char_t *) "#сustom", 7, LXB_CSS_AT_RULE__CUSTOM, &lxb_css_at_rule__custom_cb, + lxb_css_at_rule__custom_create, lxb_css_at_rule__custom_destroy, lxb_css_at_rule__custom_serialize, (void *) (uintptr_t) LXB_CSS_AT_RULE__CUSTOM}, + {(lxb_char_t *) "font-face", 9, LXB_CSS_AT_RULE_FONT_FACE, &lxb_css_at_rule_font_face_cb, + lxb_css_at_rule_font_face_create, lxb_css_at_rule_font_face_destroy, lxb_css_at_rule_font_face_serialize, + NULL}, + {(lxb_char_t *) "media", 5, LXB_CSS_AT_RULE_MEDIA, &lxb_css_at_rule_media_cb, + lxb_css_at_rule_media_create, lxb_css_at_rule_media_destroy, lxb_css_at_rule_media_serialize, + NULL}, + {(lxb_char_t *) "namespace", 9, LXB_CSS_AT_RULE_NAMESPACE, &lxb_css_at_rule_namespace_cb, + lxb_css_at_rule_namespace_create, lxb_css_at_rule_namespace_destroy, lxb_css_at_rule_namespace_serialize, + NULL} +}; + +static const lexbor_shs_entry_t lxb_css_at_rule_shs[6] = +{ + {NULL, NULL, 5, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"media", (void *) &lxb_css_at_rule_data[LXB_CSS_AT_RULE_MEDIA], 5, 0}, + {"font-face", (void *) &lxb_css_at_rule_data[LXB_CSS_AT_RULE_FONT_FACE], 9, 0}, + {"namespace", (void *) &lxb_css_at_rule_data[LXB_CSS_AT_RULE_NAMESPACE], 9, 0} +}; + + +#endif /* LXB_CSS_AT_RULE_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/state.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/state.c new file mode 100644 index 0000000..4df2f60 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/state.c @@ -0,0 +1,374 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/at_rule.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/rule.h" +#include "lexbor/css/blank.h" +#include "lexbor/css/at_rule/state.h" + + +/* Undef */ + +bool +lxb_css_at_rule__undef_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_begin = token->offset; + + /* Skip all prelude. */ + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +lxb_status_t +lxb_css_at_rule__undef_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_status_t status; + lxb_css_rule_at_t *at = ctx; + + at->prelude_end = token->offset; + + status = lxb_css_make_data(parser, &at->u.undef->prelude, + at->prelude_begin, at->prelude_end); + if (status != LXB_STATUS_OK) { + return lxb_css_parser_memory_fail_status(parser); + } + + return LXB_STATUS_OK; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_at_rule__undef_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return lxb_css_state_at_rule_block_begin(parser, token, ctx, out_rule); +} + +bool +lxb_css_at_rule__undef_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + /* For _UNDEF and _CUSTOM, access here is not possible. */ + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +lxb_status_t +lxb_css_at_rule__undef_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_at_t *at = ctx; + lxb_css_rule_list_t *block = lxb_css_syntax_returned(parser); + + /* + * Here we do not check for failed because it cannot happen; we do not call + * failed anywhere in _UNDEF and _CUSTOM, we simply skip the tokens. + */ + + at->u.undef->block = block; + + lxb_css_syntax_set_return(parser, at); + + return LXB_STATUS_OK; +} + +/* Custom */ + +bool +lxb_css_at_rule__custom_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_at_rule__undef_prelude(parser, token, ctx); +} + +lxb_status_t +lxb_css_at_rule__custom_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_status_t status; + lxb_css_rule_at_t *at = ctx; + + at->prelude_end = token->offset; + + status = lxb_css_make_data(parser, &at->u.custom->prelude, + at->prelude_begin, at->prelude_end); + if (status != LXB_STATUS_OK) { + return lxb_css_parser_memory_fail_status(parser); + } + + return LXB_STATUS_OK; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_at_rule__custom_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return lxb_css_state_at_rule_block_begin(parser, token, ctx, out_rule); +} + +bool +lxb_css_at_rule__custom_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_at_rule__undef_prelude_failed(parser, token, ctx); +} + +lxb_status_t +lxb_css_at_rule__custom_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_at_t *at = ctx; + lxb_css_rule_list_t *block = lxb_css_syntax_returned(parser); + + /* + * Here we do not check for failed because it cannot happen; we do not call + * failed anywhere in _UNDEF and _CUSTOM, we simply skip the tokens. + */ + + at->u.custom->block = block; + + lxb_css_syntax_set_return(parser, at); + + return LXB_STATUS_OK; +} + +/* Namespace */ + +bool +lxb_css_at_rule_namespace_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_begin = token->offset; + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +lxb_status_t +lxb_css_at_rule_namespace_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_end = token->offset; + + return LXB_STATUS_OK; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_at_rule_namespace_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lxb_css_parser_failed_set(parser, true); + + return lxb_css_state_at_rule_block_begin(parser, token, ctx, out_rule); +} + +bool +lxb_css_at_rule_namespace_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_at_rule__undef_prelude_failed(parser, token, ctx); +} + +lxb_status_t +lxb_css_at_rule_namespace_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_status_t status; + lxb_css_rule_at_t *at = ctx; + + if (failed) { + status = lxb_css_at_rule_convert_to_undef(parser, at); + if (status != LXB_STATUS_OK) { + return status; + } + + at->u.undef->block = lxb_css_syntax_returned(parser); + } + + lxb_css_syntax_set_return(parser, at); + + return LXB_STATUS_OK; +} + +/* Media */ + +bool +lxb_css_at_rule_media_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_begin = token->offset; + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +lxb_status_t +lxb_css_at_rule_media_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_end = token->offset; + + return LXB_STATUS_OK; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_at_rule_media_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return lxb_css_state_at_rule_block_begin(parser, token, ctx, out_rule); +} + +bool +lxb_css_at_rule_media_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_at_rule__undef_prelude_failed(parser, token, ctx); +} + +lxb_status_t +lxb_css_at_rule_media_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_status_t status; + lxb_css_rule_at_t *at = ctx; + lxb_css_rule_list_t *list = lxb_css_syntax_returned(parser); + + if (list != NULL && !failed) { + at->u.media->block = list; + } + else { + status = lxb_css_at_rule_convert_to_undef(parser, at); + if (status != LXB_STATUS_OK) { + return status; + } + + at->u.undef->block = list; + } + + lxb_css_syntax_set_return(parser, at); + + return LXB_STATUS_OK; +} + +/* Font-face */ + +bool +lxb_css_at_rule_font_face_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_begin = token->offset; + + if (token->type != LXB_CSS_SYNTAX_TOKEN__END) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} + +lxb_status_t +lxb_css_at_rule_font_face_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_end = token->offset; + + return LXB_STATUS_OK; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_at_rule_font_face_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return lxb_css_state_at_rule_block_begin(parser, token, ctx, out_rule); +} + +bool +lxb_css_at_rule_font_face_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_at_rule__undef_prelude_failed(parser, token, ctx); +} + +lxb_status_t +lxb_css_at_rule_font_face_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_status_t status; + lxb_css_rule_at_t *at = ctx; + lxb_css_rule_list_t *block = lxb_css_syntax_returned(parser); + + if (!failed) { + at->u.font_face->block = block; + } + else { + status = lxb_css_at_rule_convert_to_undef(parser, at); + if (status != LXB_STATUS_OK) { + return status; + } + + at->u.undef->block = block; + } + + lxb_css_syntax_set_return(parser, at); + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/state.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/state.h new file mode 100644 index 0000000..337a23c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/state.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_AT_RULE_STATE_H +#define LXB_CSS_AT_RULE_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" + + +LXB_API bool +lxb_css_at_rule__undef_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule__undef_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_at_rule__undef_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +LXB_API bool +lxb_css_at_rule__undef_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule__undef_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API bool +lxb_css_at_rule__custom_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule__custom_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_at_rule__custom_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +LXB_API bool +lxb_css_at_rule__custom_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule__custom_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API bool +lxb_css_at_rule_namespace_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_namespace_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_at_rule_namespace_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +LXB_API bool +lxb_css_at_rule_namespace_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_namespace_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API bool +lxb_css_at_rule_media_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_media_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_at_rule_media_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +LXB_API bool +lxb_css_at_rule_media_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_media_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API bool +lxb_css_at_rule_font_face_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_font_face_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_at_rule_font_face_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +LXB_API bool +lxb_css_at_rule_font_face_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +LXB_API lxb_status_t +lxb_css_at_rule_font_face_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_AT_RULE_STATE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/types.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/types.h new file mode 100644 index 0000000..1079bb6 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/at_rule/types.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_AT_RULE_TYPES_H +#define LXB_CSS_AT_RULE_TYPES_H + + +static const lxb_css_syntax_cb_at_rule_t lxb_css_at_rule__undef_cb = { + .prelude = lxb_css_at_rule__undef_prelude, + .prelude_end = lxb_css_at_rule__undef_prelude_end, + .block = lxb_css_at_rule__undef_block, + .cb.failed = lxb_css_at_rule__undef_prelude_failed, + .cb.end = lxb_css_at_rule__undef_end +}; + +static const lxb_css_syntax_cb_at_rule_t lxb_css_at_rule__custom_cb = { + .prelude = lxb_css_at_rule__custom_prelude, + .prelude_end = lxb_css_at_rule__custom_prelude_end, + .block = lxb_css_at_rule__custom_block, + .cb.failed = lxb_css_at_rule__custom_prelude_failed, + .cb.end = lxb_css_at_rule__custom_end +}; + +static const lxb_css_syntax_cb_at_rule_t lxb_css_at_rule_font_face_cb = { + .prelude = lxb_css_at_rule_font_face_prelude, + .prelude_end = lxb_css_at_rule_font_face_prelude_end, + .block = lxb_css_at_rule_font_face_block, + .cb.failed = lxb_css_at_rule_font_face_prelude_failed, + .cb.end = lxb_css_at_rule_font_face_end +}; + +static const lxb_css_syntax_cb_at_rule_t lxb_css_at_rule_media_cb = { + .prelude = lxb_css_at_rule_media_prelude, + .prelude_end = lxb_css_at_rule_media_prelude_end, + .block = lxb_css_at_rule_media_block, + .cb.failed = lxb_css_at_rule_media_prelude_failed, + .cb.end = lxb_css_at_rule_media_end +}; + +static const lxb_css_syntax_cb_at_rule_t lxb_css_at_rule_namespace_cb = { + .prelude = lxb_css_at_rule_namespace_prelude, + .prelude_end = lxb_css_at_rule_namespace_prelude_end, + .block = lxb_css_at_rule_namespace_block, + .cb.failed = lxb_css_at_rule_namespace_prelude_failed, + .cb.end = lxb_css_at_rule_namespace_end +}; + + + +#endif /* LXB_CSS_AT_RULE_TYPES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/base.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/base.h new file mode 100644 index 0000000..26712ce --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/base.h @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2019-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_BASE_H +#define LEXBOR_CSS_BASE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "lexbor/core/base.h" +#include "lexbor/core/mraw.h" +#include "lexbor/core/str.h" + + +#define LXB_CSS_VERSION_MAJOR 1 +#define LXB_CSS_VERSION_MINOR 4 +#define LXB_CSS_VERSION_PATCH 0 + +#define LXB_CSS_VERSION_STRING \ + LEXBOR_STRINGIZE(LXB_CSS_VERSION_MAJOR) "." \ + LEXBOR_STRINGIZE(LXB_CSS_VERSION_MINOR) "." \ + LEXBOR_STRINGIZE(LXB_CSS_VERSION_PATCH) + + +typedef struct lxb_css_memory { + lexbor_dobject_t *objs; + lexbor_mraw_t *mraw; + lexbor_mraw_t *tree; + + size_t ref_count; +} +lxb_css_memory_t; + +typedef uint32_t lxb_css_type_t; + +typedef struct lxb_css_parser lxb_css_parser_t; +typedef struct lxb_css_parser_state lxb_css_parser_state_t; +typedef struct lxb_css_parser_error lxb_css_parser_error_t; + +typedef struct lxb_css_syntax_tokenizer lxb_css_syntax_tokenizer_t; +typedef struct lxb_css_syntax_token lxb_css_syntax_token_t; + +/* Callbacks. */ + +typedef bool +(*lxb_css_parser_state_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +typedef void * +(*lxb_css_style_create_f)(lxb_css_memory_t *memory); + +typedef lxb_status_t +(*lxb_css_style_serialize_f)(const void *style, lexbor_serialize_cb_f cb, + void *ctx); + +typedef void * +(*lxb_css_style_destroy_f)(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +/* StyleSheet tree structures. */ + +typedef struct lxb_css_stylesheet lxb_css_stylesheet_t; +typedef struct lxb_css_rule_list lxb_css_rule_list_t; +typedef struct lxb_css_rule_style lxb_css_rule_style_t; +typedef struct lxb_css_rule_bad_style lxb_css_rule_bad_style_t; +typedef struct lxb_css_rule_declaration_list lxb_css_rule_declaration_list_t; +typedef struct lxb_css_rule_declaration lxb_css_rule_declaration_t; +typedef struct lxb_css_rule_at lxb_css_rule_at_t; + +typedef struct { + lxb_char_t *name; + size_t length; + uintptr_t unique; + lxb_css_parser_state_f state; + lxb_css_style_create_f create; + lxb_css_style_destroy_f destroy; + lxb_css_style_serialize_f serialize; + void *initial; +} +lxb_css_entry_data_t; + +typedef struct { + lxb_char_t *name; + size_t length; + uintptr_t unique; + + /* const lxb_css_syntax_cb_at_rule_t */ + const void *cbs; + + lxb_css_style_create_f create; + lxb_css_style_destroy_f destroy; + lxb_css_style_serialize_f serialize; + void *initial; +} +lxb_css_entry_at_rule_data_t; + +typedef struct { + lxb_char_t *name; + size_t length; + uintptr_t unique; +} +lxb_css_data_t; + + +LXB_API lxb_css_memory_t * +lxb_css_memory_create(void); + +LXB_API lxb_status_t +lxb_css_memory_init(lxb_css_memory_t *memory, size_t prepare_count); + +LXB_API void +lxb_css_memory_clean(lxb_css_memory_t *memory); + +LXB_API lxb_css_memory_t * +lxb_css_memory_destroy(lxb_css_memory_t *memory, bool self_destroy); + +LXB_API lxb_css_memory_t * +lxb_css_memory_ref_inc(lxb_css_memory_t *memory); + +LXB_API void +lxb_css_memory_ref_dec(lxb_css_memory_t *memory); + +LXB_API lxb_css_memory_t * +lxb_css_memory_ref_dec_destroy(lxb_css_memory_t *memory); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_BASE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/blank.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/blank.c new file mode 100644 index 0000000..80e60f7 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/blank.c @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/blank.h" +#include "lexbor/css/state.h" +#include "lexbor/css/css.h" +#include "lexbor/css/at_rule/state.h" + + +static bool +lxb_css_blank_list_rules_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_blank_list_rules_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_at_rule_t * +lxb_css_blank_at_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule); + +static bool +lxb_css_blank_at_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static lxb_status_t +lxb_css_blank_at_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_block_t * +lxb_css_blank_at_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +static bool +lxb_css_blank_at_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +static lxb_status_t +lxb_css_blank_at_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_blank_qualified_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static bool +lxb_css_blank_qualified_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static lxb_status_t +lxb_css_blank_qualified_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_block_t * +lxb_css_blank_qualified_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static bool +lxb_css_blank_qualified_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +static lxb_status_t +lxb_css_blank_qualified_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static bool +lxb_css_blank_block_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_blank_block_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_declarations_t * +lxb_css_blank_declarations_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static lxb_css_parser_state_f +lxb_css_blank_declaration_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +static bool +lxb_css_blank_declaration_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_blank_declaration_end(lxb_css_parser_t *parser, + void *declarations, void *ctx, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed); + +static lxb_status_t +lxb_css_blank_declarations_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static bool +lxb_css_blank_declarations_bad(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + + +static const lxb_css_syntax_cb_list_rules_t lxb_css_blank_list_rules = { + .at_rule = lxb_css_blank_at_rule_begin, + .qualified_rule = lxb_css_blank_qualified_rule_begin, + .next = lxb_css_blank_list_rules_next, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_blank_list_rules_end +}; + +static const lxb_css_syntax_cb_at_rule_t lxb_css_blank_at_rule = { + .prelude = lxb_css_blank_at_rule_prelude, + .prelude_end = lxb_css_blank_at_rule_prelude_end, + .block = lxb_css_blank_at_rule_block_begin, + .cb.failed = lxb_css_blank_at_rule_prelude_failed, + .cb.end = lxb_css_blank_at_rule_end +}; + +static const lxb_css_syntax_cb_qualified_rule_t lxb_css_blank_qualified_rule = { + .prelude = lxb_css_blank_qualified_rule_prelude, + .prelude_end = lxb_css_blank_qualified_rule_prelude_end, + .block = lxb_css_blank_qualified_rule_block_begin, + .cb.failed = lxb_css_blank_qualified_rule_prelude_failed, + .cb.end = lxb_css_blank_qualified_rule_end +}; + +static const lxb_css_syntax_cb_block_t lxb_css_blank_block = { + .at_rule = lxb_css_blank_at_rule_begin, + .declarations = lxb_css_blank_declarations_begin, + .qualified_rule = lxb_css_blank_qualified_rule_begin, + .next = lxb_css_blank_block_next, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_blank_block_end, +}; + +static const lxb_css_syntax_cb_declarations_t lxb_css_blank_declaration = { + .name = lxb_css_blank_declaration_name, + .end = lxb_css_blank_declaration_end, + .cb.failed = lxb_css_blank_declarations_bad, + .cb.end = lxb_css_blank_declarations_end +}; + + +const lxb_css_syntax_cb_list_rules_t * +lxb_css_blank_cb_list_rules(void) +{ + return &lxb_css_blank_list_rules; +} + +const lxb_css_syntax_cb_at_rule_t * +lxb_css_blank_cb_at_rule(void) +{ + return &lxb_css_blank_at_rule; +} + +const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_blank_cb_qualified_rule(void) +{ + return &lxb_css_blank_qualified_rule; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_blank_cb_block(void) +{ + return &lxb_css_blank_block; +} + +const lxb_css_syntax_cb_declarations_t * +lxb_css_blank_cb_declarations(void) +{ + return &lxb_css_blank_declaration; +} + +static bool +lxb_css_blank_list_rules_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_list_rules_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_at_rule_t * +lxb_css_blank_at_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule) +{ + return &lxb_css_blank_at_rule; +} + +static bool +lxb_css_blank_at_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_at_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_block_t * +lxb_css_blank_at_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return &lxb_css_blank_block; +} + +static bool +lxb_css_blank_at_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_at_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_blank_qualified_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return &lxb_css_blank_qualified_rule; +} + +static bool +lxb_css_blank_qualified_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_qualified_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_block_t * +lxb_css_blank_qualified_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return &lxb_css_blank_block; +} + +static bool +lxb_css_blank_qualified_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_qualified_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static bool +lxb_css_blank_block_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_block_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_declarations_t * +lxb_css_blank_declarations_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return &lxb_css_blank_declaration; +} + +static lxb_css_parser_state_f +lxb_css_blank_declaration_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + return lxb_css_blank_declaration_value; +} + +static bool +lxb_css_blank_declaration_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_blank_declaration_end(lxb_css_parser_t *parser, + void *declarations, void *ctx, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed) +{ + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_blank_declarations_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static bool +lxb_css_blank_declarations_bad(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/blank.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/blank.h new file mode 100644 index 0000000..05a13bf --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/blank.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_BLANK_H +#define LXB_CSS_BLANK_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/syntax/syntax.h" + + +LXB_API const lxb_css_syntax_cb_list_rules_t * +lxb_css_blank_cb_list_rules(void); + +LXB_API const lxb_css_syntax_cb_at_rule_t * +lxb_css_blank_cb_at_rule(void); + +LXB_API const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_blank_cb_qualified_rule(void); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_blank_cb_block(void); + +LXB_API const lxb_css_syntax_cb_declarations_t * +lxb_css_blank_cb_declarations(void); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_BLANK_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/css.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/css.c new file mode 100644 index 0000000..68c6c97 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/css.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" + + +typedef struct { + lexbor_str_t *str; + lexbor_mraw_t *mraw; +} +lxb_css_str_ctx_t; + + +static lxb_status_t +lxb_css_str_cb(const lxb_char_t *data, size_t len, void *cb_ctx); + + +lxb_css_memory_t * +lxb_css_memory_create(void) +{ + return lexbor_calloc(1, sizeof(lxb_css_memory_t)); +} + +lxb_status_t +lxb_css_memory_init(lxb_css_memory_t *memory, size_t prepare_count) +{ + lxb_status_t status; + + static const size_t size_mem = lexbor_max(sizeof(lxb_css_selector_t), + sizeof(lxb_css_selector_list_t)); + + if (memory == NULL) { + return LXB_STATUS_ERROR_INCOMPLETE_OBJECT; + } + + if (prepare_count < 64) { + prepare_count = 64; + } + + if (memory->objs == NULL) { + memory->objs = lexbor_dobject_create(); + status = lexbor_dobject_init(memory->objs, prepare_count, size_mem); + if (status != LXB_STATUS_OK) { + goto failed; + } + } + + if (memory->tree == NULL) { + prepare_count = prepare_count * 96; + + memory->tree = lexbor_mraw_create(); + status = lexbor_mraw_init(memory->tree, prepare_count); + if (status != LXB_STATUS_OK) { + goto failed; + } + } + + if (memory->mraw == NULL) { + memory->mraw = lexbor_mraw_create(); + status = lexbor_mraw_init(memory->mraw, 4096); + if (status != LXB_STATUS_OK) { + goto failed; + } + } + + memory->ref_count = 1; + + return LXB_STATUS_OK; + +failed: + + (void) lxb_css_memory_destroy(memory, false); + + return status; +} + +void +lxb_css_memory_clean(lxb_css_memory_t *memory) +{ + if (memory->objs != NULL) { + lexbor_dobject_clean(memory->objs); + } + + if (memory->mraw != NULL) { + lexbor_mraw_clean(memory->mraw); + } + + if (memory->tree != NULL) { + lexbor_mraw_clean(memory->tree); + } +} + +lxb_css_memory_t * +lxb_css_memory_destroy(lxb_css_memory_t *memory, bool self_destroy) +{ + if (memory == NULL) { + return NULL; + } + + if (memory->objs != NULL) { + memory->objs = lexbor_dobject_destroy(memory->objs, true); + } + + if (memory->mraw != NULL) { + memory->mraw = lexbor_mraw_destroy(memory->mraw, true); + } + + if (memory->tree != NULL) { + memory->tree = lexbor_mraw_destroy(memory->tree, true); + } + + if (self_destroy) { + return lexbor_free(memory); + } + + return memory; +} + +lxb_css_memory_t * +lxb_css_memory_ref_inc(lxb_css_memory_t *memory) +{ + if (SIZE_MAX - memory->ref_count == 0) { + return NULL; + } + + memory->ref_count++; + + return memory; +} + +void +lxb_css_memory_ref_dec(lxb_css_memory_t *memory) +{ + if (memory->ref_count > 0) { + memory->ref_count--; + } +} + +lxb_css_memory_t * +lxb_css_memory_ref_dec_destroy(lxb_css_memory_t *memory) +{ + if (memory->ref_count > 0) { + memory->ref_count--; + } + + if (memory->ref_count == 0) { + return lxb_css_memory_destroy(memory, true); + } + + return memory; +} + +lxb_status_t +lxb_css_make_data(lxb_css_parser_t *parser, lexbor_str_t *str, + size_t begin, size_t end) +{ + size_t length; + const lxb_char_t *p; + + p = parser->tkz->in_begin; + length = end - begin; + + if (str->data == NULL) { + (void) lexbor_str_init(str, parser->memory->mraw, length); + if (str->data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + memcpy(str->data, p + begin, length); + + str->length = length; + str->data[str->length] = '\0'; + + return LXB_STATUS_OK; +} + +lxb_char_t * +lxb_css_serialize_char_handler(const void *style, lxb_css_style_serialize_f cb, + size_t *out_length) +{ + size_t length = 0; + lxb_status_t status; + lexbor_str_t str; + + status = cb(style, lexbor_serialize_length_cb, &length); + if (status != LXB_STATUS_OK) { + goto failed; + } + + /* + 1 == '\0' */ + str.data = lexbor_malloc(length + 1); + if (str.data == NULL) { + goto failed; + } + + str.length = 0; + + status = cb(style, lexbor_serialize_copy_cb, &str); + if (status != LXB_STATUS_OK) { + lexbor_free(str.data); + goto failed; + } + + str.data[str.length] = '\0'; + + if (out_length != NULL) { + *out_length = str.length; + } + + return str.data; + +failed: + + if (out_length != NULL) { + *out_length = 0; + } + + return NULL; +} + +lxb_status_t +lxb_css_serialize_str_handler(const void *style, lexbor_str_t *str, + lexbor_mraw_t *mraw, + lxb_css_style_serialize_f cb) +{ + lxb_css_str_ctx_t ctx; + + ctx.str = str; + ctx.mraw = mraw; + + if (str->data == NULL) { + lexbor_str_init(str, mraw, 1); + if (str->data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + return cb(style, lxb_css_str_cb, &ctx); +} + +static lxb_status_t +lxb_css_str_cb(const lxb_char_t *data, size_t len, void *cb_ctx) +{ + lxb_char_t *ptr; + lxb_css_str_ctx_t *ctx = (lxb_css_str_ctx_t *) cb_ctx; + + ptr = lexbor_str_append(ctx->str, ctx->mraw, data, len); + + return (ptr != NULL) ? LXB_STATUS_OK : LXB_STATUS_ERROR_MEMORY_ALLOCATION; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/css.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/css.h new file mode 100644 index 0000000..4ba7152 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/css.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_H +#define LXB_CSS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/log.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/stylesheet.h" +#include "lexbor/css/property.h" +#include "lexbor/css/value.h" +#include "lexbor/css/at_rule.h" +#include "lexbor/css/rule.h" +#include "lexbor/css/unit.h" +#include "lexbor/css/state.h" +#include "lexbor/css/declaration.h" +#include "lexbor/css/syntax/tokenizer/error.h" +#include "lexbor/css/syntax/tokenizer.h" +#include "lexbor/css/syntax/token.h" +#include "lexbor/css/syntax/parser.h" +#include "lexbor/css/syntax/anb.h" +#include "lexbor/css/selectors/selectors.h" +#include "lexbor/css/selectors/selector.h" +#include "lexbor/css/selectors/state.h" +#include "lexbor/css/selectors/pseudo.h" + + +LXB_API lxb_status_t +lxb_css_make_data(lxb_css_parser_t *parser, lexbor_str_t *str, + size_t begin, size_t end); + +LXB_API lxb_char_t * +lxb_css_serialize_char_handler(const void *style, lxb_css_style_serialize_f cb, + size_t *out_length); +LXB_API lxb_status_t +lxb_css_serialize_str_handler(const void *style, lexbor_str_t *str, + lexbor_mraw_t *mraw, lxb_css_style_serialize_f cb); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/declaration.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/declaration.c new file mode 100644 index 0000000..e275714 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/declaration.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2022-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/declaration.h" + + +lxb_css_rule_declaration_t * +lxb_css_declaration_create(lxb_css_parser_t *parser, + const lxb_char_t *name, size_t length, + const lxb_css_entry_data_t **out_entry) +{ + void *prop; + const lxb_css_entry_data_t *entry; + lxb_css_property__custom_t *custom; + lxb_css_rule_declaration_t *declar; + + declar = lxb_css_rule_declaration_create(parser->memory); + if (declar == NULL) { + return NULL; + } + + entry = lxb_css_property_by_name(name, length); + if (entry == NULL) { + entry = lxb_css_property_by_id(LXB_CSS_PROPERTY__CUSTOM); + + prop = entry->create(parser->memory); + if (prop == NULL) { + goto failed; + } + + custom = prop; + + (void) lexbor_str_init(&custom->name, parser->memory->mraw, length); + if (custom->name.data == NULL) { + goto failed; + } + + memcpy(custom->name.data, name, length); + + custom->name.length = length; + custom->name.data[custom->name.length] = 0x00; + } + else { + prop = entry->create(parser->memory); + if (prop == NULL) { + goto failed; + } + } + + declar->type = entry->unique; + declar->u.user = prop; + + if (out_entry != NULL) { + *out_entry = entry; + } + + return declar; + +failed: + + if (prop != NULL) { + (void) entry->destroy(parser->memory, prop, true); + } + + if (declar != NULL) { + (void) lxb_css_rule_declaration_destroy(declar, true); + } + + if (out_entry != NULL) { + *out_entry = NULL; + } + + return NULL; +} + +lxb_css_rule_declaration_list_t * +lxb_css_declaration_list_parse(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_syntax_parse_declarations(parser, + lxb_css_state_cb_declarations(), + data, length); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/declaration.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/declaration.h new file mode 100644 index 0000000..53ab061 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/declaration.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_DECLARATION_H +#define LXB_CSS_DECLARATION_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/css.h" +#include "lexbor/core/mraw.h" + + +LXB_API lxb_css_rule_declaration_t * +lxb_css_declaration_create(lxb_css_parser_t *parser, + const lxb_char_t *name, size_t length, + const lxb_css_entry_data_t **out_entry); + + +LXB_API lxb_css_rule_declaration_list_t * +lxb_css_declaration_list_parse(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_DECLARATION_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/log.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/log.c new file mode 100644 index 0000000..47895ed --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/log.c @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/log.h" + + +typedef struct { + const char *msg; + size_t length; +} +lxb_css_log_type_str_t; + + +static const lxb_css_log_type_str_t lxb_css_log_types_map[] = { + {"Info", 4}, + {"Warning", 7}, + {"Error", 5}, + {"Syntax error", 12} +}; + + +lxb_css_log_t * +lxb_css_log_create(void) +{ + return lexbor_calloc(1, sizeof(lxb_css_log_t)); +} + +lxb_status_t +lxb_css_log_init(lxb_css_log_t *log, lexbor_mraw_t *mraw) +{ + lxb_status_t status; + + if (log == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + status = lexbor_array_obj_init(&log->messages, 64, + sizeof(lxb_css_log_message_t)); + if (status != LXB_STATUS_OK) { + return status; + } + + if (mraw != NULL) { + log->mraw = mraw; + log->self_mraw = false; + return LXB_STATUS_OK; + } + + log->self_mraw = true; + + log->mraw = lexbor_mraw_create(); + + return lexbor_mraw_init(log->mraw, 4096); +} + +void +lxb_css_log_clean(lxb_css_log_t *log) +{ + if (log != NULL) { + lexbor_array_obj_clean(&log->messages); + + if (log->self_mraw) { + lexbor_mraw_clean(log->mraw); + } + } +} + +lxb_css_log_t * +lxb_css_log_destroy(lxb_css_log_t *log, bool self_destroy) +{ + if (log == NULL) { + return NULL; + } + + (void) lexbor_array_obj_destroy(&log->messages, false); + + if (log->self_mraw) { + (void) lexbor_mraw_destroy(log->mraw, true); + } + + if (self_destroy) { + log = lexbor_free(log); + } + + return log; +} + +lxb_css_log_message_t * +lxb_css_log_append(lxb_css_log_t *log, lxb_css_log_type_t type, + const lxb_char_t *str, size_t length) +{ + lxb_css_log_message_t *msg; + + msg = lexbor_array_obj_push(&log->messages); + if (msg == NULL) { + return NULL; + } + + if (lexbor_str_init(&msg->text, log->mraw, length) == NULL) { + lexbor_array_obj_pop(&log->messages); + return NULL; + } + + memcpy(msg->text.data, str, length); + msg->text.length = length; + + msg->text.data[length] = '\0'; + + msg->type = type; + + return msg; +} + +lxb_css_log_message_t * +lxb_css_log_push(lxb_css_log_t *log, lxb_css_log_type_t type, size_t length) +{ + lxb_css_log_message_t *msg; + + msg = lexbor_array_obj_push(&log->messages); + if (msg == NULL) { + return NULL; + } + + if (lexbor_str_init(&msg->text, log->mraw, length) == NULL) { + lexbor_array_obj_pop(&log->messages); + return NULL; + } + + msg->type = type; + + return msg; +} + +lxb_css_log_message_t * +lxb_css_log_format(lxb_css_log_t *log, lxb_css_log_type_t type, + const char *format, ...) +{ + (void) type; (void) format; + + /* Size patch: message text is never read by the shim (parser->status is + * the only observable), so arguments are not formatted. The record itself + * still exists: callers treat NULL as an allocation failure. */ + return lxb_css_log_push(log, type, 0); +} + +lxb_css_log_message_t * +lxb_css_log_not_supported(lxb_css_log_t *log, + const char *module_name, const char *description) +{ + (void) module_name; (void) description; + + return lxb_css_log_push(log, LXB_CSS_LOG_SYNTAX_ERROR, 0); +} + +const lxb_char_t * +lxb_css_log_type_by_id(lxb_css_log_type_t type, size_t *out_length) +{ + if (out_length != NULL) { + *out_length = lxb_css_log_types_map[type].length; + } + + return (const lxb_char_t *) lxb_css_log_types_map[type].msg; +} + + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/log.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/log.h new file mode 100644 index 0000000..0c03f46 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/log.h @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_LOG_H +#define LEXBOR_CSS_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/mraw.h" +#include "lexbor/core/str.h" +#include "lexbor/core/array_obj.h" +#include "lexbor/css/base.h" + + +typedef enum { + LXB_CSS_LOG_INFO = 0, + LXB_CSS_LOG_WARNING, + LXB_CSS_LOG_ERROR, + LXB_CSS_LOG_SYNTAX_ERROR +} +lxb_css_log_type_t; + +typedef struct { + lexbor_str_t text; + lxb_css_log_type_t type; +} +lxb_css_log_message_t; + +typedef struct { + lexbor_array_obj_t messages; + lexbor_mraw_t *mraw; + bool self_mraw; +} +lxb_css_log_t; + + +LXB_API lxb_css_log_t * +lxb_css_log_create(void); + +LXB_API lxb_status_t +lxb_css_log_init(lxb_css_log_t *log, lexbor_mraw_t *mraw); + +LXB_API void +lxb_css_log_clean(lxb_css_log_t *log); + +LXB_API lxb_css_log_t * +lxb_css_log_destroy(lxb_css_log_t *log, bool self_destroy); + +LXB_API lxb_css_log_message_t * +lxb_css_log_append(lxb_css_log_t *log, lxb_css_log_type_t type, + const lxb_char_t *str, size_t length); + +LXB_API lxb_css_log_message_t * +lxb_css_log_push(lxb_css_log_t *log, lxb_css_log_type_t type, size_t length); + +LXB_API lxb_css_log_message_t * +lxb_css_log_format(lxb_css_log_t *log, lxb_css_log_type_t type, + const char *format, ...); + +LXB_API lxb_css_log_message_t * +lxb_css_log_not_supported(lxb_css_log_t *log, + const char *module_name, const char *description); + +LXB_API const lxb_char_t * +lxb_css_log_type_by_id(lxb_css_log_type_t type, size_t *out_length); + +LXB_API lxb_status_t +lxb_css_log_serialize(lxb_css_log_t *log, lexbor_serialize_cb_f cb, void *ctx, + const lxb_char_t *indent, size_t indent_length); + +LXB_API lxb_char_t * +lxb_css_log_serialize_char(lxb_css_log_t *log, size_t *out_length, + const lxb_char_t *indent, size_t indent_length); + +LXB_API lxb_status_t +lxb_css_log_message_serialize(lxb_css_log_message_t *msg, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_char_t * +lxb_css_log_message_serialize_char(lxb_css_log_message_t *msg, + size_t *out_length); + + +/* + * Inline functions + */ +lxb_inline size_t +lxb_css_log_length(lxb_css_log_t *log) +{ + return lexbor_array_obj_length(&log->messages); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_LOG_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/parser.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/parser.c new file mode 100644 index 0000000..6251438 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/parser.c @@ -0,0 +1,563 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/parser.h" +#include "lexbor/css/state.h" +#include "lexbor/css/syntax/syntax.h" + + +lxb_css_parser_t * +lxb_css_parser_create(void) +{ + return lexbor_calloc(1, sizeof(lxb_css_parser_t)); +} + +lxb_status_t +lxb_css_parser_init(lxb_css_parser_t *parser, lxb_css_syntax_tokenizer_t *tkz) +{ + lxb_status_t status; + static const size_t lxb_rules_length = 128; + static const size_t lxb_states_length = 1024; + + if (parser == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + /* Stack */ + parser->states_begin = lexbor_malloc(sizeof(lxb_css_parser_state_t) + * lxb_states_length); + if (parser->states_begin == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + parser->states = parser->states_begin; + parser->states_end = parser->states_begin + lxb_states_length; + + memset(parser->states, 0x00, sizeof(lxb_css_parser_state_t)); + parser->states->root = true; + + /* Syntax */ + parser->my_tkz = false; + + if (tkz == NULL) { + tkz = lxb_css_syntax_tokenizer_create(); + status = lxb_css_syntax_tokenizer_init(tkz); + if (status != LXB_STATUS_OK) { + return status; + } + + parser->my_tkz = true; + } + + /* Rules */ + parser->rules_begin = lexbor_malloc(sizeof(lxb_css_syntax_rule_t) + * lxb_rules_length); + if (parser->rules_begin == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + parser->rules_end = parser->rules_begin + lxb_rules_length; + parser->rules = parser->rules_begin; + + /* + * Zero those parameters that can be used (passed to the function). + * The parser->rules->phase parameter will be assigned at the end of the + * parsing. + * + * The point is that parser->rules[0] is used as a stub before exiting + * parsing. + */ + parser->rules->context = NULL; + + /* Temp */ + parser->str.length = 0; + parser->str_size = 4096; + + parser->str.data = lexbor_malloc(sizeof(lxb_char_t) * parser->str_size); + if (parser->str.data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + parser->log = lxb_css_log_create(); + status = lxb_css_log_init(parser->log, NULL); + if (status != LXB_STATUS_OK) { + return status; + } + + parser->tkz = tkz; + parser->types_begin = NULL; + parser->types_pos = NULL; + parser->types_end = NULL; + parser->stage = LXB_CSS_PARSER_CLEAN; + parser->status = LXB_STATUS_OK; + parser->fake_null = false; + parser->token_end.type = LXB_CSS_SYNTAX_TOKEN__END; + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_parser_selectors_init(lxb_css_parser_t *parser) +{ + lxb_status_t status; + + parser->selectors = lxb_css_selectors_create(); + status = lxb_css_selectors_init(parser->selectors); + if (status != LXB_STATUS_OK) { + parser->selectors = lxb_css_selectors_destroy(parser->selectors, true); + } + + return status; +} + +void +lxb_css_parser_selectors_destroy(lxb_css_parser_t *parser) +{ + if (parser->selectors != NULL) { + parser->selectors = lxb_css_selectors_destroy(parser->selectors, true); + } +} + +void +lxb_css_parser_clean(lxb_css_parser_t *parser) +{ + lxb_css_syntax_tokenizer_clean(parser->tkz); + lxb_css_log_clean(parser->log); + + parser->rules = parser->rules_begin; + parser->states = parser->states_begin; + parser->types_pos = parser->types_begin; + parser->stage = LXB_CSS_PARSER_CLEAN; + parser->status = LXB_STATUS_OK; + parser->str.length = 0; + parser->fake_null = false; +} + +void +lxb_css_parser_erase(lxb_css_parser_t *parser) +{ + lxb_css_parser_clean(parser); + + if (parser->memory != NULL) { + lxb_css_memory_clean(parser->memory); + } +} + +lxb_css_parser_t * +lxb_css_parser_destroy(lxb_css_parser_t *parser, bool self_destroy) +{ + if (parser == NULL) { + return NULL; + } + + if (parser->my_tkz) { + parser->tkz = lxb_css_syntax_tokenizer_destroy(parser->tkz); + } + + parser->log = lxb_css_log_destroy(parser->log, true); + + if (parser->rules_begin != NULL) { + parser->rules_begin = lexbor_free(parser->rules_begin); + } + + if (parser->states_begin != NULL) { + parser->states_begin = lexbor_free(parser->states_begin); + } + + if (parser->types_begin != NULL) { + parser->types_begin = lexbor_free(parser->types_begin); + } + + if (parser->str.data != NULL) { + parser->str.data = lexbor_free(parser->str.data); + } + + if (self_destroy) { + return lexbor_free(parser); + } + + return parser; +} + +lxb_css_parser_state_t * +lxb_css_parser_states_push(lxb_css_parser_t *parser, + lxb_css_parser_state_f state, void *ctx, bool root) +{ + size_t length, cur_length; + lxb_css_parser_state_t *states = ++parser->states; + + if (states >= parser->states_end) { + cur_length = states - parser->states_begin; + + if (SIZE_MAX - cur_length < 1024) { + goto memory_error; + } + + length = cur_length + 1024; + + states = lexbor_realloc(parser->states_begin, + length * sizeof(lxb_css_parser_state_t)); + if (states == NULL) { + goto memory_error; + } + + parser->states_begin = states; + parser->states_end = states + length; + parser->states = states + cur_length; + + states = parser->states; + } + + states->state = state; + states->context = ctx; + states->root = root; + + return states; + +memory_error: + + parser->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + + return NULL; +} + +lxb_css_parser_state_t * +lxb_css_parser_states_next(lxb_css_parser_t *parser, + lxb_css_parser_state_f next, + lxb_css_parser_state_f back, void *ctx, bool root) +{ + lxb_css_parser_state_t *state; + + state = lxb_css_parser_states_push(parser, back, ctx, root); + if (state == NULL) { + return NULL; + } + + parser->rules->state = next; + + return state; +} + +lxb_status_t +lxb_css_parser_types_push(lxb_css_parser_t *parser, + lxb_css_syntax_token_type_t type) +{ + size_t length, new_length; + lxb_css_syntax_token_type_t *tmp; + + if (parser->types_pos >= parser->types_end) { + length = parser->types_end - parser->types_begin; + + if ((SIZE_MAX - length) < 1024) { + return LXB_STATUS_ERROR_OVERFLOW; + } + + new_length = length + 1024; + + tmp = lexbor_realloc(parser->types_begin, + new_length * sizeof(lxb_css_syntax_token_type_t)); + if (tmp == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + parser->types_begin = tmp; + parser->types_end = tmp + new_length; + parser->types_pos = parser->types_begin + length; + } + + *parser->types_pos++ = type; + + return LXB_STATUS_OK; +} + +bool +lxb_css_parser_stop(lxb_css_parser_t *parser) +{ + parser->loop = false; + return true; +} + +bool +lxb_css_parser_fail(lxb_css_parser_t *parser, lxb_status_t status) +{ + parser->status = status; + parser->loop = false; + return true; +} + +bool +lxb_css_parser_unexpected(lxb_css_parser_t *parser) +{ + (void) lxb_css_parser_unexpected_status(parser); + return true; +} + +bool +lxb_css_parser_success(lxb_css_parser_t *parser) +{ + parser->rules->state = lxb_css_state_success; + return true; +} + +bool +lxb_css_parser_failed(lxb_css_parser_t *parser) +{ + lxb_css_syntax_rule_t *rule = parser->rules; + + rule->state = rule->cbx.cb->failed; + rule->failed = true; + + return true; +} + +lxb_status_t +lxb_css_parser_unexpected_status(lxb_css_parser_t *parser) +{ + parser->status = LXB_STATUS_ERROR_UNEXPECTED_DATA; + + parser->rules->failed = true; + + return LXB_STATUS_ERROR_UNEXPECTED_DATA; +} + +bool +lxb_css_parser_unexpected_data(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + static const char selectors[] = "Selectors"; + parser->status = LXB_STATUS_ERROR_UNEXPECTED_DATA; + + if (lxb_css_syntax_token_error(parser, token, selectors) == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return true; +} + +lxb_status_t +lxb_css_parser_unexpected_data_status(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + static const char selectors[] = "Selectors"; + parser->status = LXB_STATUS_ERROR_UNEXPECTED_DATA; + + if (lxb_css_syntax_token_error(parser, token, selectors) == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + return LXB_STATUS_ERROR_UNEXPECTED_DATA; +} + +void * +lxb_css_parser_memory_fail_null(lxb_css_parser_t *parser) +{ + parser->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + parser->loop = false; + return NULL; +} + +bool +lxb_css_parser_memory_fail(lxb_css_parser_t *parser) +{ + parser->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + parser->loop = false; + return true; +} + +lxb_status_t +lxb_css_parser_memory_fail_status(lxb_css_parser_t *parser) +{ + parser->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + parser->loop = false; + + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; +} + +/* + * No-inline functions for ABI. + */ +lxb_status_t +lxb_css_parser_status_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_status(parser); +} + +lxb_css_memory_t * +lxb_css_parser_memory_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_memory(parser); +} + +void +lxb_css_parser_memory_set_noi(lxb_css_parser_t *parser, lxb_css_memory_t *memory) +{ + lxb_css_parser_memory_set(parser, memory); +} + +lxb_css_selectors_t * +lxb_css_parser_selectors_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_selectors(parser); +} + +void +lxb_css_parser_selectors_set_noi(lxb_css_parser_t *parser, + lxb_css_selectors_t *selectors) +{ + lxb_css_parser_selectors_set(parser, selectors); +} + +bool +lxb_css_parser_is_running_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_is_running(parser); +} + +bool +lxb_css_parser_status_is_unexpected_data_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_status_is_unexpected_data(parser); +} + +void +lxb_css_parser_failed_set_noi(lxb_css_parser_t *parser, bool is) +{ + lxb_css_parser_failed_set(parser, is); +} + +void +lxb_css_parser_failed_set_by_id_noi(lxb_css_parser_t *parser, int idx, bool is) +{ + lxb_css_parser_failed_set_by_id(parser, idx, is); +} + +bool +lxb_css_parser_is_failed_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_is_failed(parser); +} + +void +lxb_css_parser_set_ok_noi(lxb_css_parser_t *parser) +{ + lxb_css_parser_set_ok(parser); +} + +const lxb_char_t * +lxb_css_parser_buffer_noi(lxb_css_parser_t *parser, size_t *length) +{ + return lxb_css_parser_buffer(parser, length); +} + +void +lxb_css_parser_buffer_set_noi(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + lxb_css_parser_buffer_set(parser, data, length); +} + +lxb_css_parser_state_f +lxb_css_parser_state_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_state(parser); +} + +void +lxb_css_parser_state_set_noi(lxb_css_parser_t *parser, lxb_css_parser_state_f state) +{ + lxb_css_parser_state_set(parser, state); +} + +lxb_css_syntax_rule_t * +lxb_css_parser_current_rule_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_current_rule(parser); +} + +size_t +lxb_css_parser_rule_deep_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_rule_deep(parser); +} + +lxb_css_parser_state_t * +lxb_css_parser_states_pop_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_states_pop(parser); +} + +lxb_css_parser_state_t * +lxb_css_parser_states_to_root_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_states_to_root(parser); +} + +bool +lxb_css_parser_states_set_back_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_states_set_back(parser); +} + +void +lxb_css_parser_states_clean_noi(lxb_css_parser_t *parser) +{ + lxb_css_parser_states_clean(parser); +} + +lxb_css_parser_state_t * +lxb_css_parser_states_current_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_states_current(parser); +} + +void +lxb_css_parser_states_set_noi(lxb_css_parser_state_t *states, + lxb_css_parser_state_f state, void *context) +{ + lxb_css_parser_states_set(states, state, context); +} + +void +lxb_css_parser_states_up_noi(lxb_css_parser_t *parser) +{ + lxb_css_parser_states_up(parser); +} + +void +lxb_css_parser_states_down_noi(lxb_css_parser_t *parser) +{ + lxb_css_parser_states_down(parser); +} + +lxb_css_log_t * +lxb_css_parser_log_noi(lxb_css_parser_t *parser) +{ + return lxb_css_parser_log(parser); +} + +const lxb_css_syntax_token_t * +lxb_css_parser_token_end_noi(lxb_css_parser_t *parser, size_t offset) +{ + return lxb_css_parser_token_end(parser, offset); +} + +void +lxb_css_parser_set_context_noi(lxb_css_parser_t *parser, void *ctx) +{ + lxb_css_parser_set_context(parser, ctx); +} + +void +lxb_css_syntax_set_return_noi(lxb_css_parser_t *parser, void *value) +{ + lxb_css_syntax_set_return(parser, value); +} + +void * +lxb_css_syntax_returned_noi(lxb_css_parser_t *parser) +{ + return lxb_css_syntax_returned(parser); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/parser.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/parser.h new file mode 100644 index 0000000..c4e906a --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/parser.h @@ -0,0 +1,756 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_PARSER_H +#define LEXBOR_CSS_PARSER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/log.h" +#include "lexbor/css/syntax/syntax.h" +#include "lexbor/css/syntax/parser.h" +#include "lexbor/css/selectors/selectors.h" + + +#define lxb_css_parser_token_m(parser, token) \ + do { \ + token = lxb_css_syntax_parser_token(parser); \ + if (token == NULL) { \ + return lxb_css_parser_fail((parser), (parser)->tkz->status); \ + } \ + } \ + while (false) + +#define lxb_css_parser_token_next_m(parser, token) \ + do { \ + token = lxb_css_syntax_token_next((parser)->tkz); \ + if (token == NULL) { \ + return lxb_css_parser_fail((parser), (parser)->tkz->status); \ + } \ + } \ + while (false) + +#define lxb_css_parser_token_wo_ws_m(parser, token) \ + do { \ + token = lxb_css_syntax_parser_token(parser); \ + if (token == NULL) { \ + return lxb_css_parser_fail((parser), (parser)->tkz->status); \ + } \ + \ + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { \ + lxb_css_syntax_parser_consume(parser); \ + token = lxb_css_syntax_parser_token(parser); \ + if (token == NULL) { \ + return lxb_css_parser_fail((parser), (parser)->tkz->status); \ + } \ + } \ + } \ + while (false) + +#define lxb_css_parser_token_status_m(parser, token) \ + do { \ + if ((token = lxb_css_syntax_parser_token(parser)) == NULL) { \ + return parser->tkz->status; \ + } \ + } \ + while (false) + +#define lxb_css_parser_token_status_next_m(parser, token) \ + do { \ + token = lxb_css_syntax_token_next((parser)->tkz); \ + if (token == NULL) { \ + return parser->tkz->status; \ + } \ + } \ + while (false) + +#define lxb_css_parser_token_status_wo_ws_m(parser, token) \ + do { \ + if ((token = lxb_css_syntax_parser_token(parser)) == NULL) { \ + return parser->tkz->status; \ + } \ + \ + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { \ + lxb_css_syntax_parser_consume(parser); \ + if ((token = lxb_css_syntax_parser_token(parser)) == NULL) { \ + return parser->tkz->status; \ + } \ + } \ + } \ + while (false) + +#define lxb_css_parser_string_dup_m(parser, token, _str, mraw) \ + do { \ + if (lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token),\ + (_str), (mraw)) != LXB_STATUS_OK) \ + { \ + return lxb_css_parser_fail((parser), \ + LXB_STATUS_ERROR_MEMORY_ALLOCATION); \ + } \ + } \ + while (false) + + +enum { + LXB_CSS_SYNTAX_PARSER_ERROR_UNDEF = 0x0000, + /* eof-in-at-rule */ + LXB_CSS_SYNTAX_PARSER_ERROR_EOINATRU, + /* eof-in-qualified-rule */ + LXB_CSS_SYNTAX_PARSER_ERROR_EOINQURU, + /* eof-in-simple-block */ + LXB_CSS_SYNTAX_PARSER_ERROR_EOINSIBL, + /* eof-in-function */ + LXB_CSS_SYNTAX_PARSER_ERROR_EOINFU, + /* eof-before-parse-rule */ + LXB_CSS_SYNTAX_PARSER_ERROR_EOBEPARU, + /* unexpected-token-after-parse-rule */ + LXB_CSS_SYNTAX_PARSER_ERROR_UNTOAFPARU, + /* eof-before-parse-component-value */ + LXB_CSS_SYNTAX_PARSER_ERROR_EOBEPACOVA, + /* unexpected-token-after-parse-component-value */ + LXB_CSS_SYNTAX_PARSER_ERROR_UNTOAFPACOVA, + /* unexpected-token-in-declaration */ + LXB_CSS_SYNTAX_PARSER_ERROR_UNTOINDE, +}; + +typedef enum { + LXB_CSS_PARSER_CLEAN = 0, + LXB_CSS_PARSER_RUN, + LXB_CSS_PARSER_STOP, + LXB_CSS_PARSER_END +} +lxb_css_parser_stage_t; + +struct lxb_css_parser { + /* Modules */ + lxb_css_syntax_tokenizer_t *tkz; + lxb_css_selectors_t *selectors; + + /* Memory for all structures. */ + lxb_css_memory_t *memory; + + /* Syntax parse rules. */ + lxb_css_syntax_rule_t *rules_begin; + lxb_css_syntax_rule_t *rules_end; + lxb_css_syntax_rule_t *rules; + + /* States */ + lxb_css_parser_state_t *states_begin; + lxb_css_parser_state_t *states_end; + lxb_css_parser_state_t *states; + + /* Types */ + lxb_css_syntax_token_type_t *types_begin; + lxb_css_syntax_token_type_t *types_end; + lxb_css_syntax_token_type_t *types_pos; + + lxb_css_syntax_token_t token_end; + + lexbor_str_t str; + size_t str_size; + + lxb_css_log_t *log; + + lxb_css_parser_stage_t stage; + + lxb_css_syntax_declaration_offset_t offset; + + bool loop; + bool fake_null; + bool my_tkz; + + lxb_status_t status; +}; + +struct lxb_css_parser_state { + lxb_css_parser_state_f state; + void *context; + bool root; +}; + +struct lxb_css_parser_error { + lexbor_str_t message; +}; + + +/* + * Create a new CSS parser object. + * + * @return lxb_css_parser_t* if successful, otherwise NULL. + */ +LXB_API lxb_css_parser_t * +lxb_css_parser_create(void); + +/* + * Initialize the CSS parser with a tokenizer. + * + * @param[in] parser Required. The CSS parser object. + * If NULL, the function returns + * LXB_STATUS_ERROR_OBJECT_IS_NULL. + * @param[in] tkz Optional. The tokenizer object. + * If NULL, a new tokenizer will be created and used. + * (In that case the parser manages the tokenizer lifetime.) + * + * @return LXB_STATUS_OK if successful, otherwise an error status value. + */ +LXB_API lxb_status_t +lxb_css_parser_init(lxb_css_parser_t *parser, lxb_css_syntax_tokenizer_t *tkz); + +/* + * Initialize the Selectors module in the parser. + * + * Note: + * Be sure to destroy the Selectors object you created yourself using + * the lxb_css_parser_selectors_destroy() function. + * + * @param[in] parser Required. The CSS parser object. + * + * @return LXB_STATUS_OK if successful, otherwise an error status value. + */ +LXB_API lxb_status_t +lxb_css_parser_selectors_init(lxb_css_parser_t *parser); + +/* + * Destroy the selectors module in the parser. + * + * @param[in] parser Required. The CSS parser object. + */ +LXB_API void +lxb_css_parser_selectors_destroy(lxb_css_parser_t *parser); + +/* + * Clean the parser object. + * + * This resets internal parser state, but keeps allocated memory so the parser + * can be reused. + * + * @param[in] parser Required. The CSS parser object. + */ +LXB_API void +lxb_css_parser_clean(lxb_css_parser_t *parser); + +/* + * Erase the parser object. + * + * This resets internal parser state and releases internal allocations owned by + * the parser so it can be re-initialized. + * + * @param[in] parser Required. The CSS parser object. + */ +LXB_API void +lxb_css_parser_erase(lxb_css_parser_t *parser); + +/* + * Destroy the parser object. + * + * @param[in] parser Optional. The CSS parser object. + * If NULL, the function returns NULL. + * @param[in] self_destroy Optional flag. + * If true, also frees the parser object itself. + * If false, only inner resources are freed and the + * parser object remains valid. + * + * @return parser if self_destroy is false, otherwise NULL. + */ +LXB_API lxb_css_parser_t * +lxb_css_parser_destroy(lxb_css_parser_t *parser, bool self_destroy); + +/* + * Stop the parser main loop. + * + * This is a helper for state callbacks that want to immediately stop parsing + * without marking the current rule as failed. + * + * @param[in] parser Required. The CSS parser object. + * + * @return true (convenience return value, useful for state callbacks). + */ +LXB_API bool +lxb_css_parser_stop(lxb_css_parser_t *parser); + +/* + * Fail the parser with a status and stop the main loop. + * + * This is used for hard errors (OOM, overflow, etc.). It sets parser->status + * and stops the parser loop. + * + * @param[in] parser Required. The CSS parser object. + * @param[in] status Required. Status code describing the failure. + * + * @return true (convenience return value, useful for state callbacks). + */ +LXB_API bool +lxb_css_parser_fail(lxb_css_parser_t *parser, lxb_status_t status); + +/* + * Mark the current token as unexpected. + * + * This is a specialized helper for the common "unexpected data" parse error. + * It sets parser->status to LXB_STATUS_ERROR_UNEXPECTED_DATA and marks the + * current rule as failed. + * + * @param[in] parser Required. The CSS parser object. + * + * @return true (convenience return value, useful for state callbacks). + */ +LXB_API bool +lxb_css_parser_unexpected(lxb_css_parser_t *parser); + +/* + * Mark parsing of the current grammar/rule as successful. + * + * Why this function exists: + * - Most callbacks in the CSS parser work as a state machine: each callback + * receives the current token and returns bool to decide what to do next. + * - "Success" is not just a bool. The parser must switch to a special + * lxb_css_state_success state to properly handle trailing whitespace and + * the end-of-input token. + * - If you don't consume all tokens up to LXB_CSS_SYNTAX_TOKEN__END in the + * current rule and call this function, the parser will switch to "failed" + * mode. This is the same as calling the lxb_css_parser_failed() function. + * The exception is the LXB_CSS_SYNTAX_TOKEN_WHITESPACE token. If you are + * sure that only this token remains, the parser will simply exclude it. + * + * What it does: + * - Sets the current rule state to lxb_css_state_success. + * - Does not stop the parser loop by itself. + * + * Typical usage: + * - In css/property/state.c, after you have parsed and consumed the last token + * of a property value, you do: + * return lxb_css_parser_success(parser); + * - That transfers control to lxb_css_state_success, which consumes any + * whitespace and completes on LXB_CSS_SYNTAX_TOKEN__END. + * + * @param[in] parser Required. The CSS parser object. + * + * @return true (convenience return value, useful for state callbacks). + */ +LXB_API bool +lxb_css_parser_success(lxb_css_parser_t *parser); + +/* + * Mark parsing of the current grammar/rule as failed. + * + * Why this function exists: + * - In the state machine, failure is also not "just return false". The parser + * needs to switch to a rule-specific recovery state so it can safely skip + * input until it is allowed to stop (usually until end-of-input or a known + * synchronisation point). + * + * What it does: + * - Sets the current rule state to the rule-specific "failed" handler + * (rule->cbx.cb->failed). + * - Sets rule->failed = true. + * - Does not directly change parser->status. Use lxb_css_parser_fail() or + * lxb_css_parser_unexpected() when you need a concrete status code. + * + * Typical usage: + * - In css/property/state.c, if a token doesn't match the expected grammar, + * you do: + * return lxb_css_parser_failed(parser); + * - That switches the parser into the failed handler. For properties this lets + * the parser consume/skip tokens until it reaches LXB_CSS_SYNTAX_TOKEN__END. + * (See lxb_css_state_failed(): it consumes tokens until end, then calls + * lxb_css_parser_success() to finish.) + * + * Important! + * The user sets the callback to "failed" and must decide what to do in this + * situation. If the user does not consume all tokens before + * LXB_CSS_SYNTAX_TOKEN__END, there will be an infinite loop. + * + * @param[in] parser Required. The CSS parser object. + * + * @return true (convenience return value, useful for state callbacks). + */ + +LXB_API bool +lxb_css_parser_failed(lxb_css_parser_t *parser); + +LXB_API lxb_status_t +lxb_css_parser_unexpected_status(lxb_css_parser_t *parser); + +LXB_API bool +lxb_css_parser_unexpected_data(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +LXB_API lxb_status_t +lxb_css_parser_unexpected_data_status(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +LXB_API void * +lxb_css_parser_memory_fail_null(lxb_css_parser_t *parser); + +LXB_API bool +lxb_css_parser_memory_fail(lxb_css_parser_t *parser); + +LXB_API lxb_status_t +lxb_css_parser_memory_fail_status(lxb_css_parser_t *parser); + +/* + * Push a new state to the parser. + * + * @param[in] parser Required. The CSS parser object. + * @param[in] state Required. State callback to execute. + * @param[in] context Optional user pointer associated with this state. + * Stored as-is; the parser doesn't own it. + * @param[in] stop If true, the pushed state is marked as a "stop point". + * This is used by the parser to stop/return control when + * this state is reached. + * + * @return lxb_css_parser_state_t* if successful, otherwise NULL. + */ +LXB_API lxb_css_parser_state_t * +lxb_css_parser_states_push(lxb_css_parser_t *parser, + lxb_css_parser_state_f state, + void *context, bool stop); + +/* + * Go to the next state in the parser. + * + * @param[in] parser Required. The CSS parser object. + * @param[in] next Required. Next state callback. + * @param[in] back Required. State callback to return to. + * @param[in] ctx Optional user pointer for the next state. + * Stored as-is; the parser doesn't own it. + * @param[in] root If true, marks this state as a "root" state. Root states + * are used by helper functions (e.g. to rewind to root). + * + * @return lxb_css_parser_state_t* if successful, otherwise NULL. + */ +LXB_API lxb_css_parser_state_t * +lxb_css_parser_states_next(lxb_css_parser_t *parser, + lxb_css_parser_state_f next, + lxb_css_parser_state_f back, void *ctx, bool root); + +/* + * Push a token type to the parser. + * + * @param[in] parser Required. The CSS parser object. + * @param[in] type Required. Token type to push. + * + * @return LXB_STATUS_OK if successful, otherwise an error status value. + */ +LXB_API lxb_status_t +lxb_css_parser_types_push(lxb_css_parser_t *parser, + lxb_css_syntax_token_type_t type); + + +/* + * Inline functions + */ +lxb_inline lxb_status_t +lxb_css_parser_status(lxb_css_parser_t *parser) +{ + return parser->status; +} + +lxb_inline lxb_css_memory_t * +lxb_css_parser_memory(lxb_css_parser_t *parser) +{ + return parser->memory; +} + +lxb_inline void +lxb_css_parser_memory_set(lxb_css_parser_t *parser, lxb_css_memory_t *memory) +{ + parser->memory = memory; +} + +lxb_inline lxb_css_selectors_t * +lxb_css_parser_selectors(lxb_css_parser_t *parser) +{ + return parser->selectors; +} + +lxb_inline void +lxb_css_parser_selectors_set(lxb_css_parser_t *parser, + lxb_css_selectors_t *selectors) +{ + parser->selectors = selectors; +} + +lxb_inline bool +lxb_css_parser_is_running(lxb_css_parser_t *parser) +{ + return parser->stage == LXB_CSS_PARSER_RUN; +} + +lxb_inline bool +lxb_css_parser_status_is_unexpected_data(lxb_css_parser_t *parser) +{ + return parser->status == LXB_STATUS_ERROR_UNEXPECTED_DATA; +} + +lxb_inline void +lxb_css_parser_failed_set(lxb_css_parser_t *parser, bool is) +{ + parser->rules->failed = is; +} + +lxb_inline void +lxb_css_parser_failed_set_by_id(lxb_css_parser_t *parser, int idx, bool is) +{ + lxb_css_syntax_rule_t *rules = parser->rules + idx; + + if (rules > parser->rules_begin && rules < parser->rules_end) { + rules->failed = is; + } +} + +lxb_inline bool +lxb_css_parser_is_failed(lxb_css_parser_t *parser) +{ + return parser->rules->failed; +} + +lxb_inline void +lxb_css_parser_set_ok(lxb_css_parser_t *parser) +{ + parser->rules->failed = false; + parser->status = LXB_STATUS_OK; +} + +lxb_inline const lxb_char_t * +lxb_css_parser_buffer(lxb_css_parser_t *parser, size_t *length) +{ + if (length != NULL) { + *length = parser->tkz->in_end - parser->tkz->in_begin; + } + + return parser->tkz->in_begin; +} + +lxb_inline void +lxb_css_parser_buffer_set(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + lxb_css_syntax_tokenizer_buffer_set(parser->tkz, data, length); +} + +lxb_inline lxb_css_parser_state_f +lxb_css_parser_state(lxb_css_parser_t *parser) +{ + return parser->rules->state; +} + +lxb_inline void +lxb_css_parser_state_set(lxb_css_parser_t *parser, lxb_css_parser_state_f state) +{ + parser->rules->state = state; +} + +lxb_inline lxb_css_syntax_rule_t * +lxb_css_parser_current_rule(lxb_css_parser_t *parser) +{ + return parser->rules; +} + +lxb_inline size_t +lxb_css_parser_rule_deep(lxb_css_parser_t *parser) +{ + return parser->rules->deep; +} + +lxb_inline lxb_css_parser_state_t * +lxb_css_parser_states_pop(lxb_css_parser_t *parser) +{ + return parser->states--; +} + +lxb_inline lxb_css_parser_state_t * +lxb_css_parser_states_to_root(lxb_css_parser_t *parser) +{ + lxb_css_parser_state_t *entry = parser->states; + + while (!entry->root) { + entry--; + } + + parser->states = entry; + + return entry; +} + +lxb_inline bool +lxb_css_parser_states_set_back(lxb_css_parser_t *parser) +{ + const lxb_css_parser_state_t *entry = parser->states; + lxb_css_syntax_rule_t *rules = parser->rules; + + rules->state = entry->state; + rules->context = entry->context; + + return true; +} + +lxb_inline void +lxb_css_parser_states_clean(lxb_css_parser_t *parser) +{ + parser->states = parser->states_begin; +} + +lxb_inline lxb_css_parser_state_t * +lxb_css_parser_states_current(lxb_css_parser_t *parser) +{ + return parser->states; +} + +lxb_inline void +lxb_css_parser_states_set(lxb_css_parser_state_t *states, + lxb_css_parser_state_f state, void *context) +{ + states->state = state; + states->context = context; +} + +lxb_inline void +lxb_css_parser_states_up(lxb_css_parser_t *parser) +{ + parser->states++; +} + +lxb_inline void +lxb_css_parser_states_down(lxb_css_parser_t *parser) +{ + parser->states--; +} + +lxb_inline lxb_css_log_t * +lxb_css_parser_log(lxb_css_parser_t *parser) +{ + return parser->log; +} + +lxb_inline const lxb_css_syntax_token_t * +lxb_css_parser_token_end(lxb_css_parser_t *parser, size_t offset) +{ + parser->token_end.offset = offset; + return &parser->token_end; +} + +lxb_inline void +lxb_css_parser_set_context(lxb_css_parser_t *parser, void *ctx) +{ + parser->rules->context = ctx; +} + +lxb_inline void +lxb_css_syntax_set_return(lxb_css_parser_t *parser, void *value) +{ + parser->rules[-1].returned = value; +} + +lxb_inline void * +lxb_css_syntax_returned(lxb_css_parser_t *parser) +{ + return parser->rules->returned; +} + +/* + * No-inline functions for ABI. + */ +LXB_API lxb_status_t +lxb_css_parser_status_noi(lxb_css_parser_t *parser); + +LXB_API lxb_css_memory_t * +lxb_css_parser_memory_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_memory_set_noi(lxb_css_parser_t *parser, lxb_css_memory_t *memory); + +LXB_API lxb_css_selectors_t * +lxb_css_parser_selectors_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_selectors_set_noi(lxb_css_parser_t *parser, + lxb_css_selectors_t *selectors); + +LXB_API bool +lxb_css_parser_is_running_noi(lxb_css_parser_t *parser); + +LXB_API bool +lxb_css_parser_status_is_unexpected_data_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_failed_set_noi(lxb_css_parser_t *parser, bool is); + +LXB_API void +lxb_css_parser_failed_set_by_id_noi(lxb_css_parser_t *parser, int idx, bool is); + +LXB_API bool +lxb_css_parser_is_failed_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_set_ok_noi(lxb_css_parser_t *parser); + +LXB_API const lxb_char_t * +lxb_css_parser_buffer_noi(lxb_css_parser_t *parser, size_t *length); + +LXB_API void +lxb_css_parser_buffer_set_noi(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_parser_state_f +lxb_css_parser_state_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_state_set_noi(lxb_css_parser_t *parser, + lxb_css_parser_state_f state); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_parser_current_rule_noi(lxb_css_parser_t *parser); + +LXB_API size_t +lxb_css_parser_rule_deep_noi(lxb_css_parser_t *parser); + +LXB_API lxb_css_parser_state_t * +lxb_css_parser_states_pop_noi(lxb_css_parser_t *parser); + +LXB_API lxb_css_parser_state_t * +lxb_css_parser_states_to_root_noi(lxb_css_parser_t *parser); + +LXB_API bool +lxb_css_parser_states_set_back_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_states_clean_noi(lxb_css_parser_t *parser); + +LXB_API lxb_css_parser_state_t * +lxb_css_parser_states_current_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_states_set_noi(lxb_css_parser_state_t *states, + lxb_css_parser_state_f state, void *context); + +LXB_API void +lxb_css_parser_states_up_noi(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_parser_states_down_noi(lxb_css_parser_t *parser); + +LXB_API lxb_css_log_t * +lxb_css_parser_log_noi(lxb_css_parser_t *parser); + +LXB_API const lxb_css_syntax_token_t * +lxb_css_parser_token_end_noi(lxb_css_parser_t *parser, size_t offset); + +LXB_API void +lxb_css_parser_set_context_noi(lxb_css_parser_t *parser, void *ctx); + +LXB_API void +lxb_css_syntax_set_return_noi(lxb_css_parser_t *parser, void *value); + +LXB_API void * +lxb_css_syntax_returned_noi(lxb_css_parser_t *parser); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_PARSER_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property.c new file mode 100644 index 0000000..6e460c3 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property.c @@ -0,0 +1,3171 @@ +/* + * Copyright (C) 2021-2023 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/property.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/stylesheet.h" +#include "lexbor/css/property/state.h" +#include "lexbor/css/property/res.h" +#include "lexbor/core/serialize.h" +#include "lexbor/core/conv.h" + + +const lxb_css_entry_data_t * +lxb_css_property_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_property_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_entry_data_t * +lxb_css_property_by_id(uintptr_t id) +{ + return &lxb_css_property_data[id]; +} + +const void * +lxb_css_property_initial_by_id(uintptr_t id) +{ + if (id >= LXB_CSS_PROPERTY__LAST_ENTRY) { + return NULL; + } + + return lxb_css_property_data[id].initial; +} + +void * +lxb_css_property_destroy(lxb_css_memory_t *memory, void *style, + lxb_css_property_type_t type, bool self_destroy) +{ + const lxb_css_entry_data_t *data; + + data = lxb_css_property_by_id(type); + if (data == NULL) { + return style; + } + + return data->destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_serialize(const void *style, lxb_css_property_type_t type, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_entry_data_t *data; + + data = lxb_css_property_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + return data->serialize(style, cb, ctx); +} + +lxb_status_t +lxb_css_property_serialize_str(const void *style, lxb_css_property_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str) +{ + const lxb_css_entry_data_t *data; + + data = lxb_css_property_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + return lxb_css_serialize_str_handler(style, str, mraw, data->serialize); +} + +lxb_status_t +lxb_css_property_serialize_name(const void *style, lxb_css_property_type_t type, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_entry_data_t *data; + + switch (type) { + case LXB_CSS_PROPERTY__UNDEF: + return lxb_css_property__undef_serialize_name(style, cb, ctx); + + case LXB_CSS_PROPERTY__CUSTOM: + return lxb_css_property__custom_serialize_name(style, cb, ctx); + + default: + break; + } + + data = lxb_css_property_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + return cb(data->name, data->length, ctx); +} + +lxb_status_t +lxb_css_property_serialize_name_str(const void *style, lxb_css_property_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str) +{ + const lxb_css_entry_data_t *data; + + switch (type) { + case LXB_CSS_PROPERTY__UNDEF: + return lxb_css_serialize_str_handler(style, str, mraw, + lxb_css_property__undef_serialize_name); + + case LXB_CSS_PROPERTY__CUSTOM: + return lxb_css_serialize_str_handler(style, str, mraw, + lxb_css_property__custom_serialize_name); + + default: + break; + } + + data = lxb_css_property_by_id(type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + if (str->data == NULL) { + lexbor_str_init(str, mraw, data->length); + if (str->data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + (void) lexbor_str_append(str, mraw, data->name, data->length); + + return LXB_STATUS_OK; +} + +/* _undef. */ + +void * +lxb_css_property__undef_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property__undef_t)); +} + +void * +lxb_css_property__undef_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + if (style == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_mraw_free(memory->mraw, style); + } + + return style; +} + +lxb_status_t +lxb_css_property__undef_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property__undef_t *undef = style; + + return cb(undef->value.data, undef->value.length, ctx); +} + +lxb_status_t +lxb_css_property__undef_serialize_name(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property__undef_t *undef = style; + const lxb_css_entry_data_t *data; + + if (undef->type == LXB_CSS_PROPERTY__UNDEF) { + return LXB_STATUS_OK; + } + + data = lxb_css_property_by_id(undef->type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + return cb(data->name, data->length, ctx); +} + +lxb_status_t +lxb_css_property__undef_serialize_value(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property__undef_t *undef = style; + + if (undef->type == LXB_CSS_PROPERTY__UNDEF) { + return cb(undef->value.data, undef->value.length, ctx); + } + + return LXB_STATUS_OK; +} + +/* _custom. */ + +void * +lxb_css_property__custom_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property__custom_t)); +} + +void * +lxb_css_property__custom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + if (style == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_mraw_free(memory->mraw, style); + } + + return style; +} + +lxb_status_t +lxb_css_property__custom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property__custom_t *custom = style; + + if (custom->value.data == NULL) { + return LXB_STATUS_OK; + } + + return cb(custom->value.data, custom->value.length, ctx); +} + +lxb_status_t +lxb_css_property__custom_serialize_name(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property__custom_t *custom = style; + + return cb(custom->name.data, custom->name.length, ctx); +} + +lxb_status_t +lxb_css_property__custom_serialize_value(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property__custom_t *custom = style; + + if (custom->value.data == NULL) { + return LXB_STATUS_OK; + } + + return cb(custom->value.data, custom->value.length, ctx); +} + +/* Display. */ + +void * +lxb_css_property_display_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_display_t)); +} + +void * +lxb_css_property_display_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_display_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_data_t *data; + const lxb_css_property_display_t *display = property; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + data = lxb_css_value_by_id(display->a); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + lexbor_serialize_write(cb, data->name, data->length, ctx, status); + + if (display->b == LXB_CSS_PROPERTY__UNDEF) { + return LXB_STATUS_OK; + } + + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + data = lxb_css_value_by_id(display->b); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + lexbor_serialize_write(cb, data->name, data->length, ctx, status); + + if (display->c == LXB_CSS_PROPERTY__UNDEF) { + return LXB_STATUS_OK; + } + + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + data = lxb_css_value_by_id(display->c); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + lexbor_serialize_write(cb, data->name, data->length, ctx, status); + + return LXB_STATUS_OK; +} + +/* Order. */ + +void * +lxb_css_property_order_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_order_t)); +} + +void * +lxb_css_property_order_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_order_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_integer_type_sr(style, cb, ctx); +} + +/* Visibility. */ + +void * +lxb_css_property_visibility_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_visibility_t)); +} + +void * +lxb_css_property_visibility_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_visibility_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_visibility_t *vb = style; + + return lxb_css_value_serialize(vb->type, cb, ctx); +} + +/* Width. */ + +void * +lxb_css_property_width_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_width_t)); +} + +void * +lxb_css_property_width_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_width_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_width_t *width = property; + + switch (width->type) { + case LXB_CSS_VALUE__LENGTH: + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_length_sr(&width->u.length, cb, ctx); + + case LXB_CSS_VALUE__PERCENTAGE: + return lxb_css_value_percentage_sr(&width->u.percentage, cb, ctx); + + case LXB_CSS_VALUE__UNDEF: + /* FIXME: ???? */ + break; + + default: + return lxb_css_value_serialize(width->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +/* Height. */ + +void * +lxb_css_property_height_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_height_t)); +} + +void * +lxb_css_property_height_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_height_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_width_serialize(property, cb, ctx); +} + +/* Box-sizing. */ + +void * +lxb_css_property_box_sizing_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_box_sizing_t)); +} + +void * +lxb_css_property_box_sizing_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_box_sizing_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_box_sizing_t *bsize = property; + + return lxb_css_value_serialize(bsize->type, cb, ctx); +} + +/* Min-width. */ + +void * +lxb_css_property_min_width_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_min_width_t)); +} + +void * +lxb_css_property_min_width_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_min_width_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_width_serialize(property, cb, ctx); +} + +/* Min-height. */ + +void * +lxb_css_property_min_height_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_min_height_t)); +} + +void * +lxb_css_property_min_height_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_min_height_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_width_serialize(property, cb, ctx); +} + +/* Max-width. */ + +void * +lxb_css_property_max_width_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_max_width_t)); +} + +void * +lxb_css_property_max_width_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_max_width_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_width_serialize(property, cb, ctx); +} + +/* Max-height. */ + +void * +lxb_css_property_max_height_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_max_height_t)); +} + +void * +lxb_css_property_max_height_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_max_height_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_width_serialize(property, cb, ctx); +} + +/* Margin. */ + +void * +lxb_css_property_margin_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_margin_t)); +} + +void * +lxb_css_property_margin_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_margin_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_margin_t *margin = property; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + /* Top. */ + + status = lxb_css_value_length_percentage_sr(&margin->top, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (margin->right.type == LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_OK; + } + + /* Right. */ + + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + status = lxb_css_value_length_percentage_sr(&margin->right, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (margin->bottom.type == LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_OK; + } + + /* Bottom. */ + + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + status = lxb_css_value_length_percentage_sr(&margin->bottom, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (margin->left.type == LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_OK; + } + + /* Left. */ + + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + return lxb_css_value_length_percentage_sr(&margin->left, cb, ctx); +} + +/* Margin-top. */ + +void * +lxb_css_property_margin_top_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_margin_top_t)); +} + +void * +lxb_css_property_margin_top_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_margin_top_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Margin-right. */ + +void * +lxb_css_property_margin_right_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_margin_right_t)); +} + +void * +lxb_css_property_margin_right_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_margin_right_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Margin-bottom. */ + +void * +lxb_css_property_margin_bottom_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_margin_bottom_t)); +} + +void * +lxb_css_property_margin_bottom_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_margin_bottom_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Margin-left. */ + +void * +lxb_css_property_margin_left_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_margin_left_t)); +} + +void * +lxb_css_property_margin_left_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_margin_left_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Padding. */ + +void * +lxb_css_property_padding_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_padding_t)); +} + +void * +lxb_css_property_padding_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_padding_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_margin_serialize(property, cb, ctx); +} + +/* Padding-top. */ + +void * +lxb_css_property_padding_top_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_padding_top_t)); +} + +void * +lxb_css_property_padding_top_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_padding_top_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Padding-right. */ + +void * +lxb_css_property_padding_right_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_padding_right_t)); +} + +void * +lxb_css_property_padding_right_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_padding_right_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Padding-bottom. */ + +void * +lxb_css_property_padding_bottom_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_padding_bottom_t)); +} + +void * +lxb_css_property_padding_bottom_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_padding_bottom_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Padding-left. */ + +void * +lxb_css_property_padding_left_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_padding_left_t)); +} + +void * +lxb_css_property_padding_left_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_padding_left_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(property, cb, ctx); +} + +/* Border. */ + +void * +lxb_css_property_border_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_border_t)); +} + +void * +lxb_css_property_border_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_border_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + bool ws_print; + lxb_status_t status; + const lxb_css_property_border_t *border = property; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + ws_print = false; + + if (border->width.type != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_length_type_sr(&border->width, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ws_print = true; + } + + if (border->style != LXB_CSS_VALUE__UNDEF) { + if (ws_print) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_serialize(border->style, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ws_print = true; + } + + if (border->color.type != LXB_CSS_VALUE__UNDEF) { + if (ws_print) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_value_color_serialize(&border->color, cb, ctx); + } + + return LXB_STATUS_OK; +} + +/* Border-top. */ + +void * +lxb_css_property_border_top_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_border_top_t)); +} + +void * +lxb_css_property_border_top_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_border_top_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_border_serialize(property, cb, ctx); +} + +/* Border-right. */ + +void * +lxb_css_property_border_right_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_border_right_t)); +} + +void * +lxb_css_property_border_right_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_border_right_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_border_serialize(property, cb, ctx); +} + +/* Border-bottom. */ + +void * +lxb_css_property_border_bottom_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_border_bottom_t)); +} + +void * +lxb_css_property_border_bottom_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_border_bottom_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_border_serialize(property, cb, ctx); +} + +/* Border-left. */ + +void * +lxb_css_property_border_left_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_border_left_t)); +} + +void * +lxb_css_property_border_left_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_border_left_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_border_serialize(property, cb, ctx); +} + +void * +lxb_css_property_border_top_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_border_top_color_t)); +} + +void * +lxb_css_property_border_top_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_border_top_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_color_serialize(style, cb, ctx); +} + +void * +lxb_css_property_border_right_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_border_right_color_t)); +} + +void * +lxb_css_property_border_right_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_border_right_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_color_serialize(style, cb, ctx); +} + +void * +lxb_css_property_border_bottom_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_border_bottom_color_t)); +} + +void * +lxb_css_property_border_bottom_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_border_bottom_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_color_serialize(style, cb, ctx); +} + +void * +lxb_css_property_border_left_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_border_left_color_t)); +} + +void * +lxb_css_property_border_left_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_border_left_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_color_serialize(style, cb, ctx); +} + +void * +lxb_css_property_background_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_background_color_t)); +} + +void * +lxb_css_property_background_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_background_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_color_serialize(style, cb, ctx); +} + +/* Color. */ + +void * +lxb_css_property_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_color_t)); +} + +void * +lxb_css_property_color_destroy(lxb_css_memory_t *memory, + void *property, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, property, self_destroy); +} + +lxb_status_t +lxb_css_property_color_serialize(const void *property, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_color_serialize(property, cb, ctx); +} + +void * +lxb_css_property_opacity_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_opacity_t)); +} + +void * +lxb_css_property_opacity_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_opacity_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_number_percentage_sr(style, cb, ctx); +} + +void * +lxb_css_property_position_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_position_t)); +} + +void * +lxb_css_property_position_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_position_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_position_t *position = style; + + return lxb_css_value_serialize(position->type, cb, ctx); +} + +void * +lxb_css_property_top_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_top_t)); +} + +void * +lxb_css_property_top_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_top_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(style, cb, ctx); +} + +void * +lxb_css_property_right_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_right_t)); +} + +void * +lxb_css_property_right_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_right_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +void * +lxb_css_property_bottom_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_bottom_t)); +} + +void * +lxb_css_property_bottom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_bottom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +void * +lxb_css_property_left_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_left_t)); +} + +void * +lxb_css_property_left_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_left_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +void * +lxb_css_property_inset_block_start_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_inset_block_start_t)); +} + +void * +lxb_css_property_inset_block_start_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_inset_block_start_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +void * +lxb_css_property_inset_inline_start_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_inset_inline_start_t)); +} + +void * +lxb_css_property_inset_inline_start_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_inset_inline_start_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +void * +lxb_css_property_inset_block_end_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_inset_block_end_t)); +} + +void * +lxb_css_property_inset_block_end_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_inset_block_end_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +void * +lxb_css_property_inset_inline_end_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_inset_inline_end_t)); +} + +void * +lxb_css_property_inset_inline_end_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_inset_inline_end_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_top_serialize(style, cb, ctx); +} + +/* Text-transform. */ + +LXB_API void * +lxb_css_property_text_transform_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_transform_t)); +} + +LXB_API void * +lxb_css_property_text_transform_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_transform_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + bool ws_print; + lxb_status_t status; + const lxb_css_property_text_transform_t *tt = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + ws_print = false; + + if (tt->type_case != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_serialize(tt->type_case, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ws_print = true; + } + + if (tt->full_width != LXB_CSS_VALUE__UNDEF) { + if (ws_print) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_serialize(tt->full_width, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ws_print = true; + } + + if (tt->full_size_kana != LXB_CSS_VALUE__UNDEF) { + if (ws_print) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_value_serialize(tt->full_size_kana, cb, ctx); + } + + return LXB_STATUS_OK; +} + +/* Text-align. */ + +LXB_API void * +lxb_css_property_text_align_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_align_t)); +} + +LXB_API void * +lxb_css_property_text_align_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_align_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_align_t *ta = style; + + return lxb_css_value_serialize(ta->type, cb, ctx); +} + +/* Text-align-all. */ + +LXB_API void * +lxb_css_property_text_align_all_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_align_all_t)); +} + +LXB_API void * +lxb_css_property_text_align_all_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_align_all_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_align_all_t *taa = style; + + return lxb_css_value_serialize(taa->type, cb, ctx); +} + +/* Text-align-last. */ + +LXB_API void * +lxb_css_property_text_align_last_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_align_last_t)); +} + +LXB_API void * +lxb_css_property_text_align_last_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_align_last_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_align_last_t *tal = style; + + return lxb_css_value_serialize(tal->type, cb, ctx); +} + +/* Text-justify. */ + +LXB_API void * +lxb_css_property_text_justify_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_justify_t)); +} + +LXB_API void * +lxb_css_property_text_justify_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_justify_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_justify_t *tj = style; + + return lxb_css_value_serialize(tj->type, cb, ctx); +} + +/* Text-indent. */ + +LXB_API void * +lxb_css_property_text_indent_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_indent_t)); +} + +LXB_API void * +lxb_css_property_text_indent_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_indent_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_text_indent_t *ti = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + if (ti->type == LXB_CSS_VALUE__LENGTH) { + status = lxb_css_value_length_percentage_sr(&ti->length, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + else if (ti->type != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_serialize(ti->type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + if (ti->hanging != LXB_CSS_VALUE__UNDEF) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + status = lxb_css_value_serialize(ti->hanging, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + if (ti->each_line != LXB_CSS_VALUE__UNDEF) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + return lxb_css_value_serialize(ti->each_line, cb, ctx); + } + + return LXB_STATUS_OK; +} + +/* White-space. */ + +LXB_API void * +lxb_css_property_white_space_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_white_space_t)); +} + +LXB_API void * +lxb_css_property_white_space_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_white_space_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_white_space_t *ws = style; + + return lxb_css_value_serialize(ws->type, cb, ctx); +} + +/* Tab-size. */ + +LXB_API void * +lxb_css_property_tab_size_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_tab_size_t)); +} + +LXB_API void * +lxb_css_property_tab_size_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_tab_size_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_number_length_sr(style, cb, ctx); +} + +/* Word-break. */ + +LXB_API void * +lxb_css_property_word_break_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_word_break_t)); +} + +LXB_API void * +lxb_css_property_word_break_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_word_break_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_word_break_t *wb = style; + + return lxb_css_value_serialize(wb->type, cb, ctx); +} + +/* Line-break. */ + +LXB_API void * +lxb_css_property_line_break_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_line_break_t)); +} + +LXB_API void * +lxb_css_property_line_break_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_line_break_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_line_break_t *lb = style; + + return lxb_css_value_serialize(lb->type, cb, ctx); +} + +/* Hyphens. */ + +LXB_API void * +lxb_css_property_hyphens_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_hyphens_t)); +} + +LXB_API void * +lxb_css_property_hyphens_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_hyphens_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_hyphens_t *hpns = style; + + return lxb_css_value_serialize(hpns->type, cb, ctx); +} + +/* Overflow-wrap. */ + +LXB_API void * +lxb_css_property_overflow_wrap_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_overflow_wrap_t)); +} + +LXB_API void * +lxb_css_property_overflow_wrap_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_overflow_wrap_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_overflow_wrap_t *ow = style; + + return lxb_css_value_serialize(ow->type, cb, ctx); +} + +/* Word-wrap. */ + +LXB_API void * +lxb_css_property_word_wrap_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_word_wrap_t)); +} + +LXB_API void * +lxb_css_property_word_wrap_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_word_wrap_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_word_wrap_t *ww = style; + + return lxb_css_value_serialize(ww->type, cb, ctx); +} + +/* Word-spacing. */ + +LXB_API void * +lxb_css_property_word_spacing_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_word_spacing_t)); +} + +LXB_API void * +lxb_css_property_word_spacing_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_word_spacing_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_type_sr(style, cb, ctx); +} + +/* Letter-spacing. */ + +LXB_API void * +lxb_css_property_letter_spacing_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_letter_spacing_t)); +} + +LXB_API void * +lxb_css_property_letter_spacing_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_letter_spacing_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_type_sr(style, cb, ctx); +} + +/* Hanging-punctuation. */ + +LXB_API void * +lxb_css_property_hanging_punctuation_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_hanging_punctuation_t)); +} + +LXB_API void * +lxb_css_property_hanging_punctuation_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_hanging_punctuation_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + bool ws_print; + lxb_status_t status; + const lxb_css_property_hanging_punctuation_t *hp = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + ws_print = false; + + if (hp->type_first != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_serialize(hp->type_first, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ws_print = true; + } + + if (hp->force_allow != LXB_CSS_VALUE__UNDEF) { + if (ws_print) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_serialize(hp->force_allow, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ws_print = true; + } + + if (hp->last != LXB_CSS_VALUE__UNDEF) { + if (ws_print) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_value_serialize(hp->last, cb, ctx); + } + + return LXB_STATUS_OK; +} + +/* Font-family. */ + +void * +lxb_css_property_font_family_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_font_family_t)); +} + +void * +lxb_css_property_font_family_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + lxb_css_property_font_family_t *ff = style; + lxb_css_property_family_name_t *name, *next; + + name = ff->first; + + while (name != NULL) { + next = name->next; + + if (!name->generic) { + (void) lexbor_str_destroy(&name->u.str, memory->mraw, false); + } + + lexbor_mraw_free(memory->mraw, name); + + name = next; + } + + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_font_family_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_font_family_t *ff = style; + const lxb_css_property_family_name_t *name; + + static const lexbor_str_t str_comma = lexbor_str(", "); + + name = ff->first; + + while (name != NULL) { + if (name->generic) { + status = lxb_css_value_serialize(name->u.type, cb, ctx); + } + else { + status = lxb_css_syntax_ident_or_string_serialize(name->u.str.data, + name->u.str.length, + cb, ctx); + } + + if (status != LXB_STATUS_OK) { + return status; + } + + name = name->next; + + if (name != NULL) { + lexbor_serialize_write(cb, str_comma.data, str_comma.length, + ctx, status); + } + } + + return LXB_STATUS_OK; +} + +/* Font-weight. */ + +void * +lxb_css_property_font_weight_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_font_weight_t)); +} + +void * +lxb_css_property_font_weight_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_font_weight_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_number_type_sr(style, cb, ctx); +} + +/* Font-stretch. */ + +void * +lxb_css_property_font_stretch_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_font_stretch_t)); +} + +void * +lxb_css_property_font_stretch_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_font_stretch_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_percentage_type_sr(style, cb, ctx); +} + +/* Font-style. */ + +void * +lxb_css_property_font_style_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_font_style_t)); +} + +void * +lxb_css_property_font_style_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +lxb_status_t +lxb_css_property_font_style_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_font_style_t *fs = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + status = lxb_css_value_serialize(fs->type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (fs->angle.unit != (lxb_css_unit_angle_t) LXB_CSS_UNIT__UNDEF) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + status = lxb_css_value_angle_sr(&fs->angle, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + return LXB_STATUS_OK; +} + +/* Font-size. */ + +LXB_API void * +lxb_css_property_font_size_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_font_size_t)); +} + +LXB_API void * +lxb_css_property_font_size_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_font_size_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_type_sr(style, cb, ctx); +} + +/* Float-reference. */ + +LXB_API void * +lxb_css_property_float_reference_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_float_reference_t)); +} + +LXB_API void * +lxb_css_property_float_reference_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_float_reference_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_float_reference_t *fr = style; + + return lxb_css_value_serialize(fr->type, cb, ctx); +} + +/* Float. */ + +LXB_API void * +lxb_css_property_float_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_float_t)); +} + +LXB_API void * +lxb_css_property_float_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_float_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_float_t *flt = style; + + static const lexbor_str_t str_o = lexbor_str("("); + static const lexbor_str_t str_cm = lexbor_str(", "); + static const lexbor_str_t str_c = lexbor_str(")"); + + status = lxb_css_value_serialize(flt->type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (flt->length.type != LXB_CSS_VALUE__LENGTH) { + return LXB_STATUS_OK; + } + + lexbor_serialize_write(cb, str_o.data, str_o.length, ctx, status); + + status = lxb_css_value_length_sr(&flt->length.length, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (flt->snap_type == LXB_CSS_VALUE__UNDEF) { + return cb(str_c.data, str_c.length, ctx); + } + + lexbor_serialize_write(cb, str_cm.data, str_cm.length, ctx, status); + + status = lxb_css_value_serialize(flt->snap_type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb(str_c.data, str_c.length, ctx); +} + +/* Clear. */ + +LXB_API void * +lxb_css_property_clear_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_clear_t)); +} + +LXB_API void * +lxb_css_property_clear_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_clear_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_clear_t *cls = style; + + return lxb_css_value_serialize(cls->type, cb, ctx); +} + +/* Float-defer. */ + +LXB_API void * +lxb_css_property_float_defer_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_float_defer_t)); +} + +LXB_API void * +lxb_css_property_float_defer_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_float_defer_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_float_defer_t *def = style; + + if (def->type == LXB_CSS_FLOAT_DEFER__INTEGER) { + return lxb_css_value_integer_sr(&def->integer, cb, ctx); + } + + return lxb_css_value_serialize(def->type, cb, ctx); +} + +/* Float-offset. */ + +LXB_API void * +lxb_css_property_float_offset_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_float_offset_t)); +} + +LXB_API void * +lxb_css_property_float_offset_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_float_offset_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(style, cb, ctx); +} + +/* Wrap-flow. */ + +LXB_API void * +lxb_css_property_wrap_flow_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_wrap_flow_t)); +} + +LXB_API void * +lxb_css_property_wrap_flow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_wrap_flow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_wrap_flow_t *wf = style; + + return lxb_css_value_serialize(wf->type, cb, ctx); +} + +/* Wrap-through. */ + +LXB_API void * +lxb_css_property_wrap_through_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_wrap_through_t)); +} + +LXB_API void * +lxb_css_property_wrap_through_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_wrap_through_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_wrap_through_t *wt = style; + + return lxb_css_value_serialize(wt->type, cb, ctx); +} + +/* Flex-direction. */ + +LXB_API void * +lxb_css_property_flex_direction_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_flex_direction_t)); +} + +LXB_API void * +lxb_css_property_flex_direction_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_direction_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_flex_direction_t *fd = style; + + return lxb_css_value_serialize(fd->type, cb, ctx); +} + +/* Flex-wrap. */ + +LXB_API void * +lxb_css_property_flex_wrap_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_flex_wrap_t)); +} + +LXB_API void * +lxb_css_property_flex_wrap_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_wrap_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_flex_wrap_t *fw = style; + + return lxb_css_value_serialize(fw->type, cb, ctx); +} + +/* Flex-flow. */ + +LXB_API void * +lxb_css_property_flex_flow_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_flex_flow_t)); +} + +LXB_API void * +lxb_css_property_flex_flow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_flow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_flex_flow_t *ff = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + if (ff->type_direction != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_serialize(ff->type_direction, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + if (ff->wrap != LXB_CSS_VALUE__UNDEF) { + if (ff->type_direction != LXB_CSS_VALUE__UNDEF) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_value_serialize(ff->wrap, cb, ctx); + } + + return LXB_STATUS_OK; +} + +/* Flex. */ + +LXB_API void * +lxb_css_property_flex_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_flex_t)); +} + +LXB_API void * +lxb_css_property_flex_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_flex_t *flex = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + if (flex->type != LXB_CSS_VALUE__UNDEF) { + return lxb_css_value_serialize(flex->type, cb, ctx); + } + + if (flex->grow.type != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_number_sr(&flex->grow.number, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (flex->shrink.type != LXB_CSS_VALUE__UNDEF) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + status = lxb_css_value_number_sr(&flex->shrink.number, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + } + + if (flex->basis.type == LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_OK; + } + + if (flex->grow.type != LXB_CSS_VALUE__UNDEF) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_property_flex_basis_serialize(&flex->basis, cb, ctx); +} + +/* Flex-grow. */ + +LXB_API void * +lxb_css_property_flex_grow_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_flex_grow_t)); +} + +LXB_API void * +lxb_css_property_flex_grow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_grow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_number_type_sr(style, cb, ctx); +} + +/* Flex-shrink. */ + +LXB_API void * +lxb_css_property_flex_shrink_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_flex_shrink_t)); +} + +LXB_API void * +lxb_css_property_flex_shrink_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_shrink_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_number_type_sr(style, cb, ctx); +} + +/* Flex-basis. */ + +LXB_API void * +lxb_css_property_flex_basis_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_flex_basis_t)); +} + +LXB_API void * +lxb_css_property_flex_basis_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_flex_basis_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_width_serialize(style, cb, ctx); +} + +/* Justify-content. */ + +LXB_API void * +lxb_css_property_justify_content_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_justify_content_t)); +} + +LXB_API void * +lxb_css_property_justify_content_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_justify_content_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_justify_content_t *jc = style; + + return lxb_css_value_serialize(jc->type, cb, ctx); +} + +/* Align-items. */ + +LXB_API void * +lxb_css_property_align_items_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_align_items_t)); +} + +LXB_API void * +lxb_css_property_align_items_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_align_items_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_align_items_t *ai = style; + + return lxb_css_value_serialize(ai->type, cb, ctx); +} + +/* Align-self. */ + +LXB_API void * +lxb_css_property_align_self_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_align_self_t)); +} + +LXB_API void * +lxb_css_property_align_self_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_align_self_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_align_self_t *as = style; + + return lxb_css_value_serialize(as->type, cb, ctx); +} + +/* Align-content. */ + +LXB_API void * +lxb_css_property_align_content_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_align_content_t)); +} + +LXB_API void * +lxb_css_property_align_content_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_align_content_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_align_content_t *ac = style; + + return lxb_css_value_serialize(ac->type, cb, ctx); +} + +/* Dominant-baseline. */ + +LXB_API void * +lxb_css_property_dominant_baseline_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_dominant_baseline_t)); +} + +LXB_API void * +lxb_css_property_dominant_baseline_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_dominant_baseline_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_dominant_baseline_t *db = style; + + return lxb_css_value_serialize(db->type, cb, ctx); +} + +/* Vertical-align. */ + +LXB_API void * +lxb_css_property_vertical_align_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_vertical_align_t)); +} + +LXB_API void * +lxb_css_property_vertical_align_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_vertical_align_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + bool is; + lxb_status_t status; + const lxb_css_property_vertical_align_t *va = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + is = false; + + if (va->type != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_serialize(va->type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + is = true; + } + + if (va->alignment.type != LXB_CSS_VALUE__UNDEF) { + if (is) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_serialize(va->alignment.type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + is = true; + } + + if (va->shift.type != LXB_CSS_VALUE__UNDEF) { + if (is) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_length_percentage_sr(&va->shift, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + return LXB_STATUS_OK; +} + +/* Baseline-source. */ + +LXB_API void * +lxb_css_property_baseline_source_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_baseline_source_t)); +} + +LXB_API void * +lxb_css_property_baseline_source_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_baseline_source_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_baseline_source_t *bs = style; + + return lxb_css_value_serialize(bs->type, cb, ctx); +} + +/* Alignment-baseline. */ + +LXB_API void * +lxb_css_property_alignment_baseline_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_alignment_baseline_t)); +} + +LXB_API void * +lxb_css_property_alignment_baseline_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_alignment_baseline_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_alignment_baseline_t *ab = style; + + return lxb_css_value_serialize(ab->type, cb, ctx); +} + +/* Baseline-shift. */ + +LXB_API void * +lxb_css_property_baseline_shift_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_baseline_shift_t)); +} + +LXB_API void * +lxb_css_property_baseline_shift_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_baseline_shift_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_length_percentage_sr(style, cb, ctx); +} + +/* Line-height. */ + +LXB_API void * +lxb_css_property_line_height_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_line_height_t)); +} + +LXB_API void * +lxb_css_property_line_height_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_line_height_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_number_length_percentage_type_sr(style, cb, ctx); +} + +/* Z-index. */ + +LXB_API void * +lxb_css_property_z_index_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_property_z_index_t)); +} + +LXB_API void * +lxb_css_property_z_index_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_z_index_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_value_integer_type_sr(style, cb, ctx); +} + +/* Direction. */ + +LXB_API void * +lxb_css_property_direction_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_direction_t)); +} + +LXB_API void * +lxb_css_property_direction_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_direction_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_direction_t *dr = style; + + return lxb_css_value_serialize(dr->type, cb, ctx); +} + +/* Unicode-bidi. */ + +LXB_API void * +lxb_css_property_unicode_bidi_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_unicode_bidi_t)); +} + +LXB_API void * +lxb_css_property_unicode_bidi_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_unicode_bidi_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_unicode_bidi_t *ub = style; + + return lxb_css_value_serialize(ub->type, cb, ctx); +} + +/* Writing-mode. */ + +LXB_API void * +lxb_css_property_writing_mode_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_writing_mode_t)); +} + +LXB_API void * +lxb_css_property_writing_mode_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_writing_mode_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_writing_mode_t *wm = style; + + return lxb_css_value_serialize(wm->type, cb, ctx); +} + +/* Text-orientation. */ + +LXB_API void * +lxb_css_property_text_orientation_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_orientation_t)); +} + +LXB_API void * +lxb_css_property_text_orientation_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_orientation_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_orientation_t *to = style; + + return lxb_css_value_serialize(to->type, cb, ctx); +} + +/* Text-combine-upright. */ + +LXB_API void * +lxb_css_property_text_combine_upright_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_combine_upright_t)); +} + +LXB_API void * +lxb_css_property_text_combine_upright_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_combine_upright_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_property_text_combine_upright_t *tcu = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + if (tcu->type == LXB_CSS_TEXT_COMBINE_UPRIGHT_DIGITS) { + status = lxb_css_value_serialize(tcu->type, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (tcu->digits.num != 0) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + + return lxb_css_value_integer_sr(&tcu->digits, cb, ctx); + } + + return LXB_STATUS_OK; + } + + return lxb_css_value_serialize(tcu->type, cb, ctx); +} + +/* Overflow-x. */ + +LXB_API void * +lxb_css_property_overflow_x_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_overflow_x_t)); +} + +LXB_API void * +lxb_css_property_overflow_x_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_overflow_x_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_overflow_x_t *ox = style; + + return lxb_css_value_serialize(ox->type, cb, ctx); +} + +/* Overflow-y. */ + +LXB_API void * +lxb_css_property_overflow_y_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_overflow_y_t)); +} + +LXB_API void * +lxb_css_property_overflow_y_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_overflow_y_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_overflow_y_t *oy = style; + + return lxb_css_value_serialize(oy->type, cb, ctx); +} + +/* Overflow-block. */ + +LXB_API void * +lxb_css_property_overflow_block_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_overflow_block_t)); +} + +LXB_API void * +lxb_css_property_overflow_block_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_overflow_block_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_overflow_block_t *ob = style; + + return lxb_css_value_serialize(ob->type, cb, ctx); +} + +/* Overflow-inline. */ + +LXB_API void * +lxb_css_property_overflow_inline_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_overflow_inline_t)); +} + +LXB_API void * +lxb_css_property_overflow_inline_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_overflow_inline_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_overflow_inline_t *oi = style; + + return lxb_css_value_serialize(oi->type, cb, ctx); +} + +/* Text-overflow. */ + +LXB_API void * +lxb_css_property_text_overflow_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_overflow_t)); +} + +LXB_API void * +lxb_css_property_text_overflow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_overflow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_overflow_t *to = style; + + return lxb_css_value_serialize(to->type, cb, ctx); +} + +/* Text-decoration-line. */ + +LXB_API void * +lxb_css_property_text_decoration_line_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_decoration_line_t)); +} + +LXB_API void * +lxb_css_property_text_decoration_line_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_decoration_line_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + bool itis; + lxb_status_t status; + const lxb_css_property_text_decoration_line_t *tdl = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + itis = false; + + if (tdl->underline != LXB_CSS_VALUE__UNDEF) { + status = lxb_css_value_serialize(tdl->underline, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + itis = true; + } + + if (tdl->overline != LXB_CSS_VALUE__UNDEF) { + if (itis) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_serialize(tdl->overline, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + itis = true; + } + + if (tdl->line_through != LXB_CSS_VALUE__UNDEF) { + if (itis) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_value_serialize(tdl->line_through, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + itis = true; + } + + if (tdl->blink != LXB_CSS_VALUE__UNDEF) { + if (itis) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_value_serialize(tdl->blink, cb, ctx); + } + + if (itis) { + return LXB_STATUS_OK; + } + + return lxb_css_value_serialize(tdl->type, cb, ctx); +} + +/* Text-decoration-style. */ + +LXB_API void * +lxb_css_property_text_decoration_style_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_decoration_style_t)); +} + +LXB_API void * +lxb_css_property_text_decoration_style_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_decoration_style_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_property_text_decoration_style_t *tds = style; + + return lxb_css_value_serialize(tds->type, cb, ctx); +} + +/* Text-decoration-color. */ + +LXB_API void * +lxb_css_property_text_decoration_color_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_decoration_color_t)); +} + +LXB_API void * +lxb_css_property_text_decoration_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_decoration_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_color_serialize(style, cb, ctx); +} + +/* Text-decoration. */ + +LXB_API void * +lxb_css_property_text_decoration_create(lxb_css_memory_t *memory) +{ + return lexbor_mraw_calloc(memory->mraw, + sizeof(lxb_css_property_text_decoration_t)); +} + +LXB_API void * +lxb_css_property_text_decoration_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy) +{ + return lxb_css_property__undef_destroy(memory, style, self_destroy); +} + +LXB_API lxb_status_t +lxb_css_property_text_decoration_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + bool itis; + lxb_status_t status; + const lxb_css_property_text_decoration_t *td = style; + + static const lexbor_str_t str_ws = lexbor_str(" "); + + itis = false; + + if (td->line.type != LXB_CSS_VALUE__UNDEF + || td->line.underline != LXB_CSS_VALUE__UNDEF + || td->line.overline != LXB_CSS_VALUE__UNDEF + || td->line.line_through != LXB_CSS_VALUE__UNDEF + || td->line.blink != LXB_CSS_VALUE__UNDEF) + { + status = lxb_css_property_text_decoration_line_serialize(&td->line, + cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + itis = true; + } + + if (td->style.type != LXB_CSS_VALUE__UNDEF) { + if (itis) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + status = lxb_css_property_text_decoration_style_serialize(&td->style, + cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + itis = true; + } + + if (td->color.type != LXB_CSS_VALUE__UNDEF) { + if (itis) { + lexbor_serialize_write(cb, str_ws.data, str_ws.length, ctx, status); + } + + return lxb_css_property_text_decoration_color_serialize(&td->color, + cb, ctx); + } + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property.h new file mode 100644 index 0000000..fb02c2e --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property.h @@ -0,0 +1,1754 @@ +/* + * Copyright (C) 2021-2023 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_PROPERTY_H +#define LXB_CSS_PROPERTY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/serialize.h" +#include "lexbor/core/array_obj.h" +#include "lexbor/css/base.h" +#include "lexbor/css/value.h" +#include "lexbor/css/unit/const.h" +#include "lexbor/css/property/const.h" + + +typedef struct { + lxb_css_property_type_t type; + lexbor_str_t value; +} +lxb_css_property__undef_t; + +typedef struct { + lexbor_str_t name; + lexbor_str_t value; +} +lxb_css_property__custom_t; + +typedef struct { + lxb_css_display_type_t a; + lxb_css_display_type_t b; + lxb_css_display_type_t c; +} +lxb_css_property_display_t; + +typedef lxb_css_value_integer_type_t lxb_css_property_order_t; + +typedef struct { + lxb_css_visibility_type_t type; +} +lxb_css_property_visibility_t; + +typedef lxb_css_value_length_percentage_t lxb_css_property_width_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_height_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_min_width_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_min_height_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_max_width_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_max_height_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_margin_top_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_margin_right_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_margin_bottom_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_margin_left_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_padding_top_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_padding_right_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_padding_bottom_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_padding_left_t; + +typedef struct { + lxb_css_box_sizing_type_t type; +} +lxb_css_property_box_sizing_t; + +typedef struct { + lxb_css_property_margin_top_t top; + lxb_css_property_margin_right_t right; + lxb_css_property_margin_bottom_t bottom; + lxb_css_property_margin_left_t left; +} +lxb_css_property_margin_t; + +typedef struct { + lxb_css_property_padding_top_t top; + lxb_css_property_padding_right_t right; + lxb_css_property_padding_bottom_t bottom; + lxb_css_property_padding_left_t left; +} +lxb_css_property_padding_t; + +typedef struct { + lxb_css_value_type_t style; + lxb_css_value_length_type_t width; + lxb_css_value_color_t color; +} +lxb_css_property_border_t; + +typedef lxb_css_property_border_t lxb_css_property_border_top_t; +typedef lxb_css_property_border_t lxb_css_property_border_right_t; +typedef lxb_css_property_border_t lxb_css_property_border_bottom_t; +typedef lxb_css_property_border_t lxb_css_property_border_left_t; + +typedef lxb_css_value_color_t lxb_css_property_border_top_color_t; +typedef lxb_css_value_color_t lxb_css_property_border_right_color_t; +typedef lxb_css_value_color_t lxb_css_property_border_bottom_color_t; +typedef lxb_css_value_color_t lxb_css_property_border_left_color_t; + +typedef lxb_css_value_color_t lxb_css_property_background_color_t; + +typedef lxb_css_value_color_t lxb_css_property_color_t; +typedef lxb_css_value_number_percentage_t lxb_css_property_opacity_t; + +typedef struct { + lxb_css_position_type_t type; +} +lxb_css_property_position_t; + +typedef lxb_css_value_length_percentage_t lxb_css_property_top_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_right_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_bottom_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_left_t; + +typedef lxb_css_value_length_percentage_t lxb_css_property_inset_block_start_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_inset_inline_start_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_inset_block_end_t; +typedef lxb_css_value_length_percentage_t lxb_css_property_inset_inline_end_t; + +typedef struct { + lxb_css_text_transform_type_t type_case; + lxb_css_text_transform_type_t full_width; + lxb_css_text_transform_type_t full_size_kana; +} +lxb_css_property_text_transform_t; + +typedef struct { + lxb_css_text_align_type_t type; +} +lxb_css_property_text_align_t; + +typedef struct { + lxb_css_text_align_all_type_t type; +} +lxb_css_property_text_align_all_t; + +typedef struct { + lxb_css_text_align_last_type_t type; +} +lxb_css_property_text_align_last_t; + +typedef struct { + lxb_css_text_justify_type_t type; +} +lxb_css_property_text_justify_t; + +typedef struct { + lxb_css_value_length_percentage_t length; + lxb_css_text_indent_type_t type; + lxb_css_text_indent_type_t hanging; + lxb_css_text_indent_type_t each_line; +} +lxb_css_property_text_indent_t; + +typedef struct { + lxb_css_white_space_type_t type; +} +lxb_css_property_white_space_t; + +typedef lxb_css_value_number_length_t lxb_css_property_tab_size_t; + +typedef struct { + lxb_css_word_break_type_t type; +} +lxb_css_property_word_break_t; + +typedef struct { + lxb_css_line_break_type_t type; +} +lxb_css_property_line_break_t; + +typedef struct { + lxb_css_hyphens_type_t type; +} +lxb_css_property_hyphens_t; + +typedef struct { + lxb_css_overflow_wrap_type_t type; +} +lxb_css_property_overflow_wrap_t; + +typedef struct { + lxb_css_word_wrap_type_t type; +} +lxb_css_property_word_wrap_t; + +typedef lxb_css_value_length_type_t lxb_css_property_word_spacing_t; +typedef lxb_css_value_length_type_t lxb_css_property_letter_spacing_t; + +typedef struct { + lxb_css_hanging_punctuation_type_t type_first; + lxb_css_hanging_punctuation_type_t force_allow; + lxb_css_hanging_punctuation_type_t last; +} +lxb_css_property_hanging_punctuation_t; + +typedef struct lxb_css_property_family_name lxb_css_property_family_name_t; + +struct lxb_css_property_family_name { + bool generic; + + union { + lxb_css_font_family_type_t type; + lexbor_str_t str; + } u; + + lxb_css_property_family_name_t *next; + lxb_css_property_family_name_t *prev; +}; + +typedef struct { + lxb_css_property_family_name_t *first; + lxb_css_property_family_name_t *last; + + size_t count; +} +lxb_css_property_font_family_t; + +typedef lxb_css_value_number_type_t lxb_css_property_font_weight_t; +typedef lxb_css_value_percentage_type_t lxb_css_property_font_stretch_t; +typedef lxb_css_value_angle_type_t lxb_css_property_font_style_t; +typedef lxb_css_value_length_percentage_type_t lxb_css_property_font_size_t; + +typedef struct { + lxb_css_float_reference_type_t type; +} +lxb_css_property_float_reference_t; + +typedef struct { + lxb_css_float_type_t type; + lxb_css_value_length_type_t length; + lxb_css_float_type_t snap_type; +} +lxb_css_property_float_t; + +typedef struct { + lxb_css_clear_type_t type; +} +lxb_css_property_clear_t; + +typedef lxb_css_value_length_percentage_t lxb_css_property_float_offset_t; +typedef lxb_css_value_integer_type_t lxb_css_property_float_defer_t; + +typedef struct { + lxb_css_wrap_flow_type_t type; +} +lxb_css_property_wrap_flow_t; + +typedef struct { + lxb_css_wrap_through_type_t type; +} +lxb_css_property_wrap_through_t; + +typedef struct { + lxb_css_flex_direction_type_t type; +} +lxb_css_property_flex_direction_t; + +typedef struct { + lxb_css_flex_wrap_type_t type; +} +lxb_css_property_flex_wrap_t; + +typedef struct { + lxb_css_flex_direction_type_t type_direction; + lxb_css_flex_wrap_type_t wrap; +} +lxb_css_property_flex_flow_t; + +typedef lxb_css_value_number_type_t lxb_css_property_flex_grow_t; +typedef lxb_css_value_number_type_t lxb_css_property_flex_shrink_t; +typedef lxb_css_property_width_t lxb_css_property_flex_basis_t; + +typedef struct { + lxb_css_flex_type_t type; + lxb_css_property_flex_grow_t grow; + lxb_css_property_flex_shrink_t shrink; + lxb_css_property_flex_basis_t basis; +} +lxb_css_property_flex_t; + +typedef struct { + lxb_css_justify_content_type_t type; +} +lxb_css_property_justify_content_t; + +typedef struct { + lxb_css_align_items_type_t type; +} +lxb_css_property_align_items_t; + +typedef struct { + lxb_css_align_self_type_t type; +} +lxb_css_property_align_self_t; + +typedef struct { + lxb_css_align_content_type_t type; +} +lxb_css_property_align_content_t; + +typedef struct { + lxb_css_dominant_baseline_type_t type; +} +lxb_css_property_dominant_baseline_t; + +typedef struct { + lxb_css_baseline_source_type_t type; +} +lxb_css_property_baseline_source_t; + +typedef struct { + lxb_css_alignment_baseline_type_t type; +} +lxb_css_property_alignment_baseline_t; + +typedef lxb_css_value_length_percentage_t lxb_css_property_baseline_shift_t; + +typedef struct { + lxb_css_vertical_align_type_t type; + lxb_css_property_alignment_baseline_t alignment; + lxb_css_property_baseline_shift_t shift; +} +lxb_css_property_vertical_align_t; + +typedef lxb_css_value_number_length_percentage_t lxb_css_property_line_height_t; + +typedef lxb_css_value_integer_type_t lxb_css_property_z_index_t; + +typedef struct { + lxb_css_direction_type_t type; +} +lxb_css_property_direction_t; + +typedef struct { + lxb_css_unicode_bidi_type_t type; +} +lxb_css_property_unicode_bidi_t; + +typedef struct { + lxb_css_writing_mode_type_t type; +} +lxb_css_property_writing_mode_t; + +typedef struct { + lxb_css_text_orientation_type_t type; +} +lxb_css_property_text_orientation_t; + +typedef struct { + lxb_css_text_combine_upright_type_t type; + /* + * If the integer is omitted, it computes to 2. + * Integers outside the range 2-4 are invalid. + */ + lxb_css_value_integer_t digits; +} +lxb_css_property_text_combine_upright_t; + +typedef struct { + lxb_css_overflow_x_type_t type; +} +lxb_css_property_overflow_x_t; + +typedef struct { + lxb_css_overflow_y_type_t type; +} +lxb_css_property_overflow_y_t; + +typedef struct { + lxb_css_overflow_block_type_t type; +} +lxb_css_property_overflow_block_t; + +typedef struct { + lxb_css_overflow_inline_type_t type; +} +lxb_css_property_overflow_inline_t; + +typedef struct { + lxb_css_text_overflow_type_t type; +} +lxb_css_property_text_overflow_t; + +typedef struct { + lxb_css_text_decoration_line_type_t type; + lxb_css_text_decoration_line_type_t underline; + lxb_css_text_decoration_line_type_t overline; + lxb_css_text_decoration_line_type_t line_through; + lxb_css_text_decoration_line_type_t blink; +} +lxb_css_property_text_decoration_line_t; + +typedef struct { + lxb_css_text_decoration_style_type_t type; +} +lxb_css_property_text_decoration_style_t; + +typedef lxb_css_value_color_t lxb_css_property_text_decoration_color_t; + +typedef struct { + lxb_css_property_text_decoration_line_t line; + lxb_css_property_text_decoration_style_t style; + lxb_css_property_text_decoration_color_t color; +} +lxb_css_property_text_decoration_t; + + +LXB_API const lxb_css_entry_data_t * +lxb_css_property_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_entry_data_t * +lxb_css_property_by_id(uintptr_t id); + +LXB_API const void * +lxb_css_property_initial_by_id(uintptr_t id); + +LXB_API void * +lxb_css_property_destroy(lxb_css_memory_t *memory, void *style, + lxb_css_property_type_t type, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_serialize(const void *style, lxb_css_property_type_t type, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_property_serialize_str(const void *style, lxb_css_property_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str); + +LXB_API lxb_status_t +lxb_css_property_serialize_name(const void *style, lxb_css_property_type_t type, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_property_serialize_name_str(const void *style, lxb_css_property_type_t type, + lexbor_mraw_t *mraw, lexbor_str_t *str); + +/* _undef. */ + +LXB_API void * +lxb_css_property__undef_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property__undef_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property__undef_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_property__undef_serialize_name(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_property__undef_serialize_value(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* _custom. */ + +LXB_API void * +lxb_css_property__custom_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property__custom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property__custom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); +LXB_API lxb_status_t +lxb_css_property__custom_serialize_name(const void *style, + lexbor_serialize_cb_f cb, void *ctx); +LXB_API lxb_status_t +lxb_css_property__custom_serialize_value(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Display. */ + +LXB_API void * +lxb_css_property_display_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_display_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_display_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Order. */ + +LXB_API void * +lxb_css_property_order_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_order_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_order_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Visibility. */ + +LXB_API void * +lxb_css_property_visibility_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_visibility_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_visibility_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Width. */ + +LXB_API void * +lxb_css_property_width_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_width_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_width_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Height. */ + +LXB_API void * +lxb_css_property_height_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_height_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_height_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Box-sizing. */ + +LXB_API void * +lxb_css_property_box_sizing_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_box_sizing_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_box_sizing_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Min-width. */ + +LXB_API void * +lxb_css_property_min_width_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_min_width_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_min_width_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Min-height. */ + +LXB_API void * +lxb_css_property_min_height_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_min_height_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_min_height_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Max-width. */ + +LXB_API void * +lxb_css_property_max_width_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_max_width_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_max_width_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Max-height. */ + +LXB_API void * +lxb_css_property_max_height_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_max_height_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_max_height_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Margin. */ + +LXB_API void * +lxb_css_property_margin_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_margin_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_margin_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Margin-top. */ + +LXB_API void * +lxb_css_property_margin_top_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_margin_top_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_margin_top_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Margin-right. */ + +LXB_API void * +lxb_css_property_margin_right_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_margin_right_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_margin_right_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Margin-bottom. */ + +LXB_API void * +lxb_css_property_margin_bottom_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_margin_bottom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_margin_bottom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Margin-left. */ + +LXB_API void * +lxb_css_property_margin_left_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_margin_left_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_margin_left_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Padding. */ + +LXB_API void * +lxb_css_property_padding_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_padding_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_padding_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Padding-top. */ + +LXB_API void * +lxb_css_property_padding_top_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_padding_top_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_padding_top_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Padding-right. */ + +LXB_API void * +lxb_css_property_padding_right_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_padding_right_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_padding_right_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Padding-bottom. */ + +LXB_API void * +lxb_css_property_padding_bottom_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_padding_bottom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_padding_bottom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Padding-left. */ + +LXB_API void * +lxb_css_property_padding_left_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_padding_left_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_padding_left_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border. */ + +LXB_API void * +lxb_css_property_border_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-top. */ + +LXB_API void * +lxb_css_property_border_top_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_top_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_top_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-right. */ + +LXB_API void * +lxb_css_property_border_right_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_right_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_right_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-bottom. */ + +LXB_API void * +lxb_css_property_border_bottom_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_bottom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_bottom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-left. */ + +LXB_API void * +lxb_css_property_border_left_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_left_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_left_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-top-color. */ + +LXB_API void * +lxb_css_property_border_top_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_top_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_top_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-right-color. */ + +LXB_API void * +lxb_css_property_border_right_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_right_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_right_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-bottom-color. */ + +LXB_API void * +lxb_css_property_border_bottom_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_bottom_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_bottom_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Border-left-color. */ + +LXB_API void * +lxb_css_property_border_left_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_border_left_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_border_left_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Background-color. */ + +LXB_API void * +lxb_css_property_background_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_background_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_background_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Color. */ + +LXB_API void * +lxb_css_property_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Opacity. */ + +LXB_API void * +lxb_css_property_opacity_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_opacity_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_opacity_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Position. */ + +LXB_API void * +lxb_css_property_position_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_position_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_position_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Top. */ + +LXB_API void * +lxb_css_property_top_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_top_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_top_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Right. */ + +LXB_API void * +lxb_css_property_right_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_right_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_right_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Bottom. */ + +LXB_API void * +lxb_css_property_bottom_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_bottom_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_bottom_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Left. */ + +LXB_API void * +lxb_css_property_left_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_left_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_left_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Inset-block-start. */ + +LXB_API void * +lxb_css_property_inset_block_start_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_inset_block_start_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_inset_block_start_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Inset-inline-start. */ + +LXB_API void * +lxb_css_property_inset_inline_start_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_inset_inline_start_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_inset_inline_start_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Inset-block-end. */ + +LXB_API void * +lxb_css_property_inset_block_end_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_inset_block_end_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_inset_block_end_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Inset-inline-end. */ + +LXB_API void * +lxb_css_property_inset_inline_end_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_inset_inline_end_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); +LXB_API lxb_status_t +lxb_css_property_inset_inline_end_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-transform. */ + +LXB_API void * +lxb_css_property_text_transform_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_transform_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_transform_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-align. */ + +LXB_API void * +lxb_css_property_text_align_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_align_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_align_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-align-all. */ + +LXB_API void * +lxb_css_property_text_align_all_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_align_all_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_align_all_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-align-last. */ + +LXB_API void * +lxb_css_property_text_align_last_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_align_last_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_align_last_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-justify. */ + +LXB_API void * +lxb_css_property_text_justify_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_justify_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_justify_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-indent. */ + +LXB_API void * +lxb_css_property_text_indent_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_indent_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_indent_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* White-space. */ + +LXB_API void * +lxb_css_property_white_space_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_white_space_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_white_space_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Tab-size. */ + +LXB_API void * +lxb_css_property_tab_size_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_tab_size_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_tab_size_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Word-break. */ + +LXB_API void * +lxb_css_property_word_break_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_word_break_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_word_break_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Line-break. */ + +LXB_API void * +lxb_css_property_line_break_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_line_break_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_line_break_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Hyphens. */ + +LXB_API void * +lxb_css_property_hyphens_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_hyphens_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_hyphens_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Overflow-wrap. */ + +LXB_API void * +lxb_css_property_overflow_wrap_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_overflow_wrap_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_overflow_wrap_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Word-wrap. */ + +LXB_API void * +lxb_css_property_word_wrap_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_word_wrap_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_word_wrap_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Word-spacing. */ + +LXB_API void * +lxb_css_property_word_spacing_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_word_spacing_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_word_spacing_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Letter-spacing. */ + +LXB_API void * +lxb_css_property_letter_spacing_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_letter_spacing_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_letter_spacing_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Hanging-punctuation. */ + +LXB_API void * +lxb_css_property_hanging_punctuation_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_hanging_punctuation_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_hanging_punctuation_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Font-family. */ + +LXB_API void * +lxb_css_property_font_family_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_font_family_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_font_family_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Font-weight. */ + +LXB_API void * +lxb_css_property_font_weight_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_font_weight_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_font_weight_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Font-stretch. */ + +LXB_API void * +lxb_css_property_font_stretch_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_font_stretch_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_font_stretch_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Font-style. */ + +LXB_API void * +lxb_css_property_font_style_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_font_style_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_font_style_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Font-size. */ + +LXB_API void * +lxb_css_property_font_size_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_font_size_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_font_size_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Float-reference. */ + +LXB_API void * +lxb_css_property_float_reference_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_float_reference_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_float_reference_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Float. */ + +LXB_API void * +lxb_css_property_float_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_float_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_float_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Clear. */ + +LXB_API void * +lxb_css_property_clear_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_clear_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_clear_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Float-defer. */ + +LXB_API void * +lxb_css_property_float_defer_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_float_defer_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_float_defer_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Float-offset. */ + +LXB_API void * +lxb_css_property_float_offset_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_float_offset_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_float_offset_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Wrap-flow. */ + +LXB_API void * +lxb_css_property_wrap_flow_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_wrap_flow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_wrap_flow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Wrap-through. */ + +LXB_API void * +lxb_css_property_wrap_through_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_wrap_through_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_wrap_through_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex-direction. */ + +LXB_API void * +lxb_css_property_flex_direction_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_direction_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_direction_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex-wrap. */ + +LXB_API void * +lxb_css_property_flex_wrap_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_wrap_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_wrap_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex-flow. */ + +LXB_API void * +lxb_css_property_flex_flow_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_flow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_flow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex. */ + +LXB_API void * +lxb_css_property_flex_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex-grow. */ + +LXB_API void * +lxb_css_property_flex_grow_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_grow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_grow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex-shrink. */ + +LXB_API void * +lxb_css_property_flex_shrink_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_shrink_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_shrink_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Flex-basis. */ + +LXB_API void * +lxb_css_property_flex_basis_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_flex_basis_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_flex_basis_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Justify-content. */ + +LXB_API void * +lxb_css_property_justify_content_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_justify_content_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_justify_content_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Align-items. */ + +LXB_API void * +lxb_css_property_align_items_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_align_items_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_align_items_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Align-self. */ + +LXB_API void * +lxb_css_property_align_self_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_align_self_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_align_self_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Align-content. */ + +LXB_API void * +lxb_css_property_align_content_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_align_content_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_align_content_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Dominant-baseline. */ + +LXB_API void * +lxb_css_property_dominant_baseline_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_dominant_baseline_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_dominant_baseline_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Vertical-align. */ + +LXB_API void * +lxb_css_property_vertical_align_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_vertical_align_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_vertical_align_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Baseline-source. */ + +LXB_API void * +lxb_css_property_baseline_source_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_baseline_source_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_baseline_source_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Alignment-baseline. */ + +LXB_API void * +lxb_css_property_alignment_baseline_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_alignment_baseline_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_alignment_baseline_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Baseline-shift. */ + +LXB_API void * +lxb_css_property_baseline_shift_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_baseline_shift_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_baseline_shift_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Line-height. */ + +LXB_API void * +lxb_css_property_line_height_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_line_height_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_line_height_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Z-index. */ + +LXB_API void * +lxb_css_property_z_index_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_z_index_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_z_index_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Direction. */ + +LXB_API void * +lxb_css_property_direction_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_direction_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_direction_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Unicode-bidi. */ + +LXB_API void * +lxb_css_property_unicode_bidi_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_unicode_bidi_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_unicode_bidi_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Writing-mode. */ + +LXB_API void * +lxb_css_property_writing_mode_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_writing_mode_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_writing_mode_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-orientation. */ + +LXB_API void * +lxb_css_property_text_orientation_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_orientation_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_orientation_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-combine-upright. */ + +LXB_API void * +lxb_css_property_text_combine_upright_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_combine_upright_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_combine_upright_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Overflow-x. */ + +LXB_API void * +lxb_css_property_overflow_x_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_overflow_x_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_overflow_x_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Overflow-y. */ + +LXB_API void * +lxb_css_property_overflow_y_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_overflow_y_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_overflow_y_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Overflow-block. */ + +LXB_API void * +lxb_css_property_overflow_block_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_overflow_block_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_overflow_block_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Overflow-inline. */ + +LXB_API void * +lxb_css_property_overflow_inline_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_overflow_inline_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_overflow_inline_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-overflow. */ + +LXB_API void * +lxb_css_property_text_overflow_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_overflow_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_overflow_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-decoration-line. */ + +LXB_API void * +lxb_css_property_text_decoration_line_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_decoration_line_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_decoration_line_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-decoration-style. */ + +LXB_API void * +lxb_css_property_text_decoration_style_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_decoration_style_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_decoration_style_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-decoration-color. */ + +LXB_API void * +lxb_css_property_text_decoration_color_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_decoration_color_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_decoration_color_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + +/* Text-decoration. */ + +LXB_API void * +lxb_css_property_text_decoration_create(lxb_css_memory_t *memory); + +LXB_API void * +lxb_css_property_text_decoration_destroy(lxb_css_memory_t *memory, + void *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_property_text_decoration_serialize(const void *style, + lexbor_serialize_cb_f cb, void *ctx); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_PROPERTY_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/const.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/const.h new file mode 100644 index 0000000..4f90bc1 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/const.h @@ -0,0 +1,1180 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_PROPERTY_CONST_H +#define LXB_CSS_PROPERTY_CONST_H + + +#include "lexbor/css/value/const.h" + + +enum { + LXB_CSS_PROPERTY__UNDEF = 0x0000, + LXB_CSS_PROPERTY__CUSTOM = 0x0001, + LXB_CSS_PROPERTY_ALIGN_CONTENT = 0x0002, + LXB_CSS_PROPERTY_ALIGN_ITEMS = 0x0003, + LXB_CSS_PROPERTY_ALIGN_SELF = 0x0004, + LXB_CSS_PROPERTY_ALIGNMENT_BASELINE = 0x0005, + LXB_CSS_PROPERTY_BACKGROUND_COLOR = 0x0006, + LXB_CSS_PROPERTY_BASELINE_SHIFT = 0x0007, + LXB_CSS_PROPERTY_BASELINE_SOURCE = 0x0008, + LXB_CSS_PROPERTY_BORDER = 0x0009, + LXB_CSS_PROPERTY_BORDER_BOTTOM = 0x000a, + LXB_CSS_PROPERTY_BORDER_BOTTOM_COLOR = 0x000b, + LXB_CSS_PROPERTY_BORDER_LEFT = 0x000c, + LXB_CSS_PROPERTY_BORDER_LEFT_COLOR = 0x000d, + LXB_CSS_PROPERTY_BORDER_RIGHT = 0x000e, + LXB_CSS_PROPERTY_BORDER_RIGHT_COLOR = 0x000f, + LXB_CSS_PROPERTY_BORDER_TOP = 0x0010, + LXB_CSS_PROPERTY_BORDER_TOP_COLOR = 0x0011, + LXB_CSS_PROPERTY_BOTTOM = 0x0012, + LXB_CSS_PROPERTY_BOX_SIZING = 0x0013, + LXB_CSS_PROPERTY_CLEAR = 0x0014, + LXB_CSS_PROPERTY_COLOR = 0x0015, + LXB_CSS_PROPERTY_DIRECTION = 0x0016, + LXB_CSS_PROPERTY_DISPLAY = 0x0017, + LXB_CSS_PROPERTY_DOMINANT_BASELINE = 0x0018, + LXB_CSS_PROPERTY_FLEX = 0x0019, + LXB_CSS_PROPERTY_FLEX_BASIS = 0x001a, + LXB_CSS_PROPERTY_FLEX_DIRECTION = 0x001b, + LXB_CSS_PROPERTY_FLEX_FLOW = 0x001c, + LXB_CSS_PROPERTY_FLEX_GROW = 0x001d, + LXB_CSS_PROPERTY_FLEX_SHRINK = 0x001e, + LXB_CSS_PROPERTY_FLEX_WRAP = 0x001f, + LXB_CSS_PROPERTY_FLOAT = 0x0020, + LXB_CSS_PROPERTY_FLOAT_DEFER = 0x0021, + LXB_CSS_PROPERTY_FLOAT_OFFSET = 0x0022, + LXB_CSS_PROPERTY_FLOAT_REFERENCE = 0x0023, + LXB_CSS_PROPERTY_FONT_FAMILY = 0x0024, + LXB_CSS_PROPERTY_FONT_SIZE = 0x0025, + LXB_CSS_PROPERTY_FONT_STRETCH = 0x0026, + LXB_CSS_PROPERTY_FONT_STYLE = 0x0027, + LXB_CSS_PROPERTY_FONT_WEIGHT = 0x0028, + LXB_CSS_PROPERTY_HANGING_PUNCTUATION = 0x0029, + LXB_CSS_PROPERTY_HEIGHT = 0x002a, + LXB_CSS_PROPERTY_HYPHENS = 0x002b, + LXB_CSS_PROPERTY_INSET_BLOCK_END = 0x002c, + LXB_CSS_PROPERTY_INSET_BLOCK_START = 0x002d, + LXB_CSS_PROPERTY_INSET_INLINE_END = 0x002e, + LXB_CSS_PROPERTY_INSET_INLINE_START = 0x002f, + LXB_CSS_PROPERTY_JUSTIFY_CONTENT = 0x0030, + LXB_CSS_PROPERTY_LEFT = 0x0031, + LXB_CSS_PROPERTY_LETTER_SPACING = 0x0032, + LXB_CSS_PROPERTY_LINE_BREAK = 0x0033, + LXB_CSS_PROPERTY_LINE_HEIGHT = 0x0034, + LXB_CSS_PROPERTY_MARGIN = 0x0035, + LXB_CSS_PROPERTY_MARGIN_BOTTOM = 0x0036, + LXB_CSS_PROPERTY_MARGIN_LEFT = 0x0037, + LXB_CSS_PROPERTY_MARGIN_RIGHT = 0x0038, + LXB_CSS_PROPERTY_MARGIN_TOP = 0x0039, + LXB_CSS_PROPERTY_MAX_HEIGHT = 0x003a, + LXB_CSS_PROPERTY_MAX_WIDTH = 0x003b, + LXB_CSS_PROPERTY_MIN_HEIGHT = 0x003c, + LXB_CSS_PROPERTY_MIN_WIDTH = 0x003d, + LXB_CSS_PROPERTY_OPACITY = 0x003e, + LXB_CSS_PROPERTY_ORDER = 0x003f, + LXB_CSS_PROPERTY_OVERFLOW_BLOCK = 0x0040, + LXB_CSS_PROPERTY_OVERFLOW_INLINE = 0x0041, + LXB_CSS_PROPERTY_OVERFLOW_WRAP = 0x0042, + LXB_CSS_PROPERTY_OVERFLOW_X = 0x0043, + LXB_CSS_PROPERTY_OVERFLOW_Y = 0x0044, + LXB_CSS_PROPERTY_PADDING = 0x0045, + LXB_CSS_PROPERTY_PADDING_BOTTOM = 0x0046, + LXB_CSS_PROPERTY_PADDING_LEFT = 0x0047, + LXB_CSS_PROPERTY_PADDING_RIGHT = 0x0048, + LXB_CSS_PROPERTY_PADDING_TOP = 0x0049, + LXB_CSS_PROPERTY_POSITION = 0x004a, + LXB_CSS_PROPERTY_RIGHT = 0x004b, + LXB_CSS_PROPERTY_TAB_SIZE = 0x004c, + LXB_CSS_PROPERTY_TEXT_ALIGN = 0x004d, + LXB_CSS_PROPERTY_TEXT_ALIGN_ALL = 0x004e, + LXB_CSS_PROPERTY_TEXT_ALIGN_LAST = 0x004f, + LXB_CSS_PROPERTY_TEXT_COMBINE_UPRIGHT = 0x0050, + LXB_CSS_PROPERTY_TEXT_DECORATION = 0x0051, + LXB_CSS_PROPERTY_TEXT_DECORATION_COLOR = 0x0052, + LXB_CSS_PROPERTY_TEXT_DECORATION_LINE = 0x0053, + LXB_CSS_PROPERTY_TEXT_DECORATION_STYLE = 0x0054, + LXB_CSS_PROPERTY_TEXT_INDENT = 0x0055, + LXB_CSS_PROPERTY_TEXT_JUSTIFY = 0x0056, + LXB_CSS_PROPERTY_TEXT_ORIENTATION = 0x0057, + LXB_CSS_PROPERTY_TEXT_OVERFLOW = 0x0058, + LXB_CSS_PROPERTY_TEXT_TRANSFORM = 0x0059, + LXB_CSS_PROPERTY_TOP = 0x005a, + LXB_CSS_PROPERTY_UNICODE_BIDI = 0x005b, + LXB_CSS_PROPERTY_VERTICAL_ALIGN = 0x005c, + LXB_CSS_PROPERTY_VISIBILITY = 0x005d, + LXB_CSS_PROPERTY_WHITE_SPACE = 0x005e, + LXB_CSS_PROPERTY_WIDTH = 0x005f, + LXB_CSS_PROPERTY_WORD_BREAK = 0x0060, + LXB_CSS_PROPERTY_WORD_SPACING = 0x0061, + LXB_CSS_PROPERTY_WORD_WRAP = 0x0062, + LXB_CSS_PROPERTY_WRAP_FLOW = 0x0063, + LXB_CSS_PROPERTY_WRAP_THROUGH = 0x0064, + LXB_CSS_PROPERTY_WRITING_MODE = 0x0065, + LXB_CSS_PROPERTY_Z_INDEX = 0x0066, + LXB_CSS_PROPERTY__LAST_ENTRY = 0x0067 +}; +typedef uintptr_t lxb_css_property_type_t; + +enum { + LXB_CSS_ALIGN_CONTENT_FLEX_START = LXB_CSS_VALUE_FLEX_START, + LXB_CSS_ALIGN_CONTENT_FLEX_END = LXB_CSS_VALUE_FLEX_END, + LXB_CSS_ALIGN_CONTENT_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_ALIGN_CONTENT_SPACE_BETWEEN = LXB_CSS_VALUE_SPACE_BETWEEN, + LXB_CSS_ALIGN_CONTENT_SPACE_AROUND = LXB_CSS_VALUE_SPACE_AROUND, + LXB_CSS_ALIGN_CONTENT_STRETCH = LXB_CSS_VALUE_STRETCH +}; +typedef unsigned int lxb_css_align_content_type_t; + +enum { + LXB_CSS_ALIGN_ITEMS_FLEX_START = LXB_CSS_VALUE_FLEX_START, + LXB_CSS_ALIGN_ITEMS_FLEX_END = LXB_CSS_VALUE_FLEX_END, + LXB_CSS_ALIGN_ITEMS_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_ALIGN_ITEMS_BASELINE = LXB_CSS_VALUE_BASELINE, + LXB_CSS_ALIGN_ITEMS_STRETCH = LXB_CSS_VALUE_STRETCH +}; +typedef unsigned int lxb_css_align_items_type_t; + +enum { + LXB_CSS_ALIGN_SELF_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_ALIGN_SELF_FLEX_START = LXB_CSS_VALUE_FLEX_START, + LXB_CSS_ALIGN_SELF_FLEX_END = LXB_CSS_VALUE_FLEX_END, + LXB_CSS_ALIGN_SELF_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_ALIGN_SELF_BASELINE = LXB_CSS_VALUE_BASELINE, + LXB_CSS_ALIGN_SELF_STRETCH = LXB_CSS_VALUE_STRETCH +}; +typedef unsigned int lxb_css_align_self_type_t; + +enum { + LXB_CSS_ALIGNMENT_BASELINE_BASELINE = LXB_CSS_VALUE_BASELINE, + LXB_CSS_ALIGNMENT_BASELINE_TEXT_BOTTOM = LXB_CSS_VALUE_TEXT_BOTTOM, + LXB_CSS_ALIGNMENT_BASELINE_ALPHABETIC = LXB_CSS_VALUE_ALPHABETIC, + LXB_CSS_ALIGNMENT_BASELINE_IDEOGRAPHIC = LXB_CSS_VALUE_IDEOGRAPHIC, + LXB_CSS_ALIGNMENT_BASELINE_MIDDLE = LXB_CSS_VALUE_MIDDLE, + LXB_CSS_ALIGNMENT_BASELINE_CENTRAL = LXB_CSS_VALUE_CENTRAL, + LXB_CSS_ALIGNMENT_BASELINE_MATHEMATICAL = LXB_CSS_VALUE_MATHEMATICAL, + LXB_CSS_ALIGNMENT_BASELINE_TEXT_TOP = LXB_CSS_VALUE_TEXT_TOP +}; +typedef unsigned int lxb_css_alignment_baseline_type_t; + + + +enum { + LXB_CSS_BASELINE_SHIFT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_BASELINE_SHIFT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_BASELINE_SHIFT_SUB = LXB_CSS_VALUE_SUB, + LXB_CSS_BASELINE_SHIFT_SUPER = LXB_CSS_VALUE_SUPER, + LXB_CSS_BASELINE_SHIFT_TOP = LXB_CSS_VALUE_TOP, + LXB_CSS_BASELINE_SHIFT_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_BASELINE_SHIFT_BOTTOM = LXB_CSS_VALUE_BOTTOM +}; +typedef unsigned int lxb_css_baseline_shift_type_t; + +enum { + LXB_CSS_BASELINE_SOURCE_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_BASELINE_SOURCE_FIRST = LXB_CSS_VALUE_FIRST, + LXB_CSS_BASELINE_SOURCE_LAST = LXB_CSS_VALUE_LAST +}; +typedef unsigned int lxb_css_baseline_source_type_t; + +enum { + LXB_CSS_BORDER_THIN = LXB_CSS_VALUE_THIN, + LXB_CSS_BORDER_MEDIUM = LXB_CSS_VALUE_MEDIUM, + LXB_CSS_BORDER_THICK = LXB_CSS_VALUE_THICK, + LXB_CSS_BORDER_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_BORDER_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_BORDER_DOTTED = LXB_CSS_VALUE_DOTTED, + LXB_CSS_BORDER_DASHED = LXB_CSS_VALUE_DASHED, + LXB_CSS_BORDER_SOLID = LXB_CSS_VALUE_SOLID, + LXB_CSS_BORDER_DOUBLE = LXB_CSS_VALUE_DOUBLE, + LXB_CSS_BORDER_GROOVE = LXB_CSS_VALUE_GROOVE, + LXB_CSS_BORDER_RIDGE = LXB_CSS_VALUE_RIDGE, + LXB_CSS_BORDER_INSET = LXB_CSS_VALUE_INSET, + LXB_CSS_BORDER_OUTSET = LXB_CSS_VALUE_OUTSET, + LXB_CSS_BORDER__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_border_type_t; + +enum { + LXB_CSS_BORDER_BOTTOM_THIN = LXB_CSS_VALUE_THIN, + LXB_CSS_BORDER_BOTTOM_MEDIUM = LXB_CSS_VALUE_MEDIUM, + LXB_CSS_BORDER_BOTTOM_THICK = LXB_CSS_VALUE_THICK, + LXB_CSS_BORDER_BOTTOM_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_BORDER_BOTTOM_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_BORDER_BOTTOM_DOTTED = LXB_CSS_VALUE_DOTTED, + LXB_CSS_BORDER_BOTTOM_DASHED = LXB_CSS_VALUE_DASHED, + LXB_CSS_BORDER_BOTTOM_SOLID = LXB_CSS_VALUE_SOLID, + LXB_CSS_BORDER_BOTTOM_DOUBLE = LXB_CSS_VALUE_DOUBLE, + LXB_CSS_BORDER_BOTTOM_GROOVE = LXB_CSS_VALUE_GROOVE, + LXB_CSS_BORDER_BOTTOM_RIDGE = LXB_CSS_VALUE_RIDGE, + LXB_CSS_BORDER_BOTTOM_INSET = LXB_CSS_VALUE_INSET, + LXB_CSS_BORDER_BOTTOM_OUTSET = LXB_CSS_VALUE_OUTSET, + LXB_CSS_BORDER_BOTTOM__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_border_bottom_type_t; + + + +enum { + LXB_CSS_BORDER_LEFT_THIN = LXB_CSS_VALUE_THIN, + LXB_CSS_BORDER_LEFT_MEDIUM = LXB_CSS_VALUE_MEDIUM, + LXB_CSS_BORDER_LEFT_THICK = LXB_CSS_VALUE_THICK, + LXB_CSS_BORDER_LEFT_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_BORDER_LEFT_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_BORDER_LEFT_DOTTED = LXB_CSS_VALUE_DOTTED, + LXB_CSS_BORDER_LEFT_DASHED = LXB_CSS_VALUE_DASHED, + LXB_CSS_BORDER_LEFT_SOLID = LXB_CSS_VALUE_SOLID, + LXB_CSS_BORDER_LEFT_DOUBLE = LXB_CSS_VALUE_DOUBLE, + LXB_CSS_BORDER_LEFT_GROOVE = LXB_CSS_VALUE_GROOVE, + LXB_CSS_BORDER_LEFT_RIDGE = LXB_CSS_VALUE_RIDGE, + LXB_CSS_BORDER_LEFT_INSET = LXB_CSS_VALUE_INSET, + LXB_CSS_BORDER_LEFT_OUTSET = LXB_CSS_VALUE_OUTSET, + LXB_CSS_BORDER_LEFT__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_border_left_type_t; + + + +enum { + LXB_CSS_BORDER_RIGHT_THIN = LXB_CSS_VALUE_THIN, + LXB_CSS_BORDER_RIGHT_MEDIUM = LXB_CSS_VALUE_MEDIUM, + LXB_CSS_BORDER_RIGHT_THICK = LXB_CSS_VALUE_THICK, + LXB_CSS_BORDER_RIGHT_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_BORDER_RIGHT_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_BORDER_RIGHT_DOTTED = LXB_CSS_VALUE_DOTTED, + LXB_CSS_BORDER_RIGHT_DASHED = LXB_CSS_VALUE_DASHED, + LXB_CSS_BORDER_RIGHT_SOLID = LXB_CSS_VALUE_SOLID, + LXB_CSS_BORDER_RIGHT_DOUBLE = LXB_CSS_VALUE_DOUBLE, + LXB_CSS_BORDER_RIGHT_GROOVE = LXB_CSS_VALUE_GROOVE, + LXB_CSS_BORDER_RIGHT_RIDGE = LXB_CSS_VALUE_RIDGE, + LXB_CSS_BORDER_RIGHT_INSET = LXB_CSS_VALUE_INSET, + LXB_CSS_BORDER_RIGHT_OUTSET = LXB_CSS_VALUE_OUTSET, + LXB_CSS_BORDER_RIGHT__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_border_right_type_t; + + + +enum { + LXB_CSS_BORDER_TOP_THIN = LXB_CSS_VALUE_THIN, + LXB_CSS_BORDER_TOP_MEDIUM = LXB_CSS_VALUE_MEDIUM, + LXB_CSS_BORDER_TOP_THICK = LXB_CSS_VALUE_THICK, + LXB_CSS_BORDER_TOP_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_BORDER_TOP_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_BORDER_TOP_DOTTED = LXB_CSS_VALUE_DOTTED, + LXB_CSS_BORDER_TOP_DASHED = LXB_CSS_VALUE_DASHED, + LXB_CSS_BORDER_TOP_SOLID = LXB_CSS_VALUE_SOLID, + LXB_CSS_BORDER_TOP_DOUBLE = LXB_CSS_VALUE_DOUBLE, + LXB_CSS_BORDER_TOP_GROOVE = LXB_CSS_VALUE_GROOVE, + LXB_CSS_BORDER_TOP_RIDGE = LXB_CSS_VALUE_RIDGE, + LXB_CSS_BORDER_TOP_INSET = LXB_CSS_VALUE_INSET, + LXB_CSS_BORDER_TOP_OUTSET = LXB_CSS_VALUE_OUTSET, + LXB_CSS_BORDER_TOP__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_border_top_type_t; + + + +enum { + LXB_CSS_BOTTOM_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_BOTTOM__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_BOTTOM__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_bottom_type_t; + +enum { + LXB_CSS_BOX_SIZING_CONTENT_BOX = LXB_CSS_VALUE_CONTENT_BOX, + LXB_CSS_BOX_SIZING_BORDER_BOX = LXB_CSS_VALUE_BORDER_BOX +}; +typedef unsigned int lxb_css_box_sizing_type_t; + +enum { + LXB_CSS_CLEAR_INLINE_START = LXB_CSS_VALUE_INLINE_START, + LXB_CSS_CLEAR_INLINE_END = LXB_CSS_VALUE_INLINE_END, + LXB_CSS_CLEAR_BLOCK_START = LXB_CSS_VALUE_BLOCK_START, + LXB_CSS_CLEAR_BLOCK_END = LXB_CSS_VALUE_BLOCK_END, + LXB_CSS_CLEAR_LEFT = LXB_CSS_VALUE_LEFT, + LXB_CSS_CLEAR_RIGHT = LXB_CSS_VALUE_RIGHT, + LXB_CSS_CLEAR_TOP = LXB_CSS_VALUE_TOP, + LXB_CSS_CLEAR_BOTTOM = LXB_CSS_VALUE_BOTTOM, + LXB_CSS_CLEAR_NONE = LXB_CSS_VALUE_NONE +}; +typedef unsigned int lxb_css_clear_type_t; + +enum { + LXB_CSS_COLOR_CURRENTCOLOR = LXB_CSS_VALUE_CURRENTCOLOR, + LXB_CSS_COLOR_TRANSPARENT = LXB_CSS_VALUE_TRANSPARENT, + LXB_CSS_COLOR_HEX = LXB_CSS_VALUE_HEX, + LXB_CSS_COLOR_ALICEBLUE = LXB_CSS_VALUE_ALICEBLUE, + LXB_CSS_COLOR_ANTIQUEWHITE = LXB_CSS_VALUE_ANTIQUEWHITE, + LXB_CSS_COLOR_AQUA = LXB_CSS_VALUE_AQUA, + LXB_CSS_COLOR_AQUAMARINE = LXB_CSS_VALUE_AQUAMARINE, + LXB_CSS_COLOR_AZURE = LXB_CSS_VALUE_AZURE, + LXB_CSS_COLOR_BEIGE = LXB_CSS_VALUE_BEIGE, + LXB_CSS_COLOR_BISQUE = LXB_CSS_VALUE_BISQUE, + LXB_CSS_COLOR_BLACK = LXB_CSS_VALUE_BLACK, + LXB_CSS_COLOR_BLANCHEDALMOND = LXB_CSS_VALUE_BLANCHEDALMOND, + LXB_CSS_COLOR_BLUE = LXB_CSS_VALUE_BLUE, + LXB_CSS_COLOR_BLUEVIOLET = LXB_CSS_VALUE_BLUEVIOLET, + LXB_CSS_COLOR_BROWN = LXB_CSS_VALUE_BROWN, + LXB_CSS_COLOR_BURLYWOOD = LXB_CSS_VALUE_BURLYWOOD, + LXB_CSS_COLOR_CADETBLUE = LXB_CSS_VALUE_CADETBLUE, + LXB_CSS_COLOR_CHARTREUSE = LXB_CSS_VALUE_CHARTREUSE, + LXB_CSS_COLOR_CHOCOLATE = LXB_CSS_VALUE_CHOCOLATE, + LXB_CSS_COLOR_CORAL = LXB_CSS_VALUE_CORAL, + LXB_CSS_COLOR_CORNFLOWERBLUE = LXB_CSS_VALUE_CORNFLOWERBLUE, + LXB_CSS_COLOR_CORNSILK = LXB_CSS_VALUE_CORNSILK, + LXB_CSS_COLOR_CRIMSON = LXB_CSS_VALUE_CRIMSON, + LXB_CSS_COLOR_CYAN = LXB_CSS_VALUE_CYAN, + LXB_CSS_COLOR_DARKBLUE = LXB_CSS_VALUE_DARKBLUE, + LXB_CSS_COLOR_DARKCYAN = LXB_CSS_VALUE_DARKCYAN, + LXB_CSS_COLOR_DARKGOLDENROD = LXB_CSS_VALUE_DARKGOLDENROD, + LXB_CSS_COLOR_DARKGRAY = LXB_CSS_VALUE_DARKGRAY, + LXB_CSS_COLOR_DARKGREEN = LXB_CSS_VALUE_DARKGREEN, + LXB_CSS_COLOR_DARKGREY = LXB_CSS_VALUE_DARKGREY, + LXB_CSS_COLOR_DARKKHAKI = LXB_CSS_VALUE_DARKKHAKI, + LXB_CSS_COLOR_DARKMAGENTA = LXB_CSS_VALUE_DARKMAGENTA, + LXB_CSS_COLOR_DARKOLIVEGREEN = LXB_CSS_VALUE_DARKOLIVEGREEN, + LXB_CSS_COLOR_DARKORANGE = LXB_CSS_VALUE_DARKORANGE, + LXB_CSS_COLOR_DARKORCHID = LXB_CSS_VALUE_DARKORCHID, + LXB_CSS_COLOR_DARKRED = LXB_CSS_VALUE_DARKRED, + LXB_CSS_COLOR_DARKSALMON = LXB_CSS_VALUE_DARKSALMON, + LXB_CSS_COLOR_DARKSEAGREEN = LXB_CSS_VALUE_DARKSEAGREEN, + LXB_CSS_COLOR_DARKSLATEBLUE = LXB_CSS_VALUE_DARKSLATEBLUE, + LXB_CSS_COLOR_DARKSLATEGRAY = LXB_CSS_VALUE_DARKSLATEGRAY, + LXB_CSS_COLOR_DARKSLATEGREY = LXB_CSS_VALUE_DARKSLATEGREY, + LXB_CSS_COLOR_DARKTURQUOISE = LXB_CSS_VALUE_DARKTURQUOISE, + LXB_CSS_COLOR_DARKVIOLET = LXB_CSS_VALUE_DARKVIOLET, + LXB_CSS_COLOR_DEEPPINK = LXB_CSS_VALUE_DEEPPINK, + LXB_CSS_COLOR_DEEPSKYBLUE = LXB_CSS_VALUE_DEEPSKYBLUE, + LXB_CSS_COLOR_DIMGRAY = LXB_CSS_VALUE_DIMGRAY, + LXB_CSS_COLOR_DIMGREY = LXB_CSS_VALUE_DIMGREY, + LXB_CSS_COLOR_DODGERBLUE = LXB_CSS_VALUE_DODGERBLUE, + LXB_CSS_COLOR_FIREBRICK = LXB_CSS_VALUE_FIREBRICK, + LXB_CSS_COLOR_FLORALWHITE = LXB_CSS_VALUE_FLORALWHITE, + LXB_CSS_COLOR_FORESTGREEN = LXB_CSS_VALUE_FORESTGREEN, + LXB_CSS_COLOR_FUCHSIA = LXB_CSS_VALUE_FUCHSIA, + LXB_CSS_COLOR_GAINSBORO = LXB_CSS_VALUE_GAINSBORO, + LXB_CSS_COLOR_GHOSTWHITE = LXB_CSS_VALUE_GHOSTWHITE, + LXB_CSS_COLOR_GOLD = LXB_CSS_VALUE_GOLD, + LXB_CSS_COLOR_GOLDENROD = LXB_CSS_VALUE_GOLDENROD, + LXB_CSS_COLOR_GRAY = LXB_CSS_VALUE_GRAY, + LXB_CSS_COLOR_GREEN = LXB_CSS_VALUE_GREEN, + LXB_CSS_COLOR_GREENYELLOW = LXB_CSS_VALUE_GREENYELLOW, + LXB_CSS_COLOR_GREY = LXB_CSS_VALUE_GREY, + LXB_CSS_COLOR_HONEYDEW = LXB_CSS_VALUE_HONEYDEW, + LXB_CSS_COLOR_HOTPINK = LXB_CSS_VALUE_HOTPINK, + LXB_CSS_COLOR_INDIANRED = LXB_CSS_VALUE_INDIANRED, + LXB_CSS_COLOR_INDIGO = LXB_CSS_VALUE_INDIGO, + LXB_CSS_COLOR_IVORY = LXB_CSS_VALUE_IVORY, + LXB_CSS_COLOR_KHAKI = LXB_CSS_VALUE_KHAKI, + LXB_CSS_COLOR_LAVENDER = LXB_CSS_VALUE_LAVENDER, + LXB_CSS_COLOR_LAVENDERBLUSH = LXB_CSS_VALUE_LAVENDERBLUSH, + LXB_CSS_COLOR_LAWNGREEN = LXB_CSS_VALUE_LAWNGREEN, + LXB_CSS_COLOR_LEMONCHIFFON = LXB_CSS_VALUE_LEMONCHIFFON, + LXB_CSS_COLOR_LIGHTBLUE = LXB_CSS_VALUE_LIGHTBLUE, + LXB_CSS_COLOR_LIGHTCORAL = LXB_CSS_VALUE_LIGHTCORAL, + LXB_CSS_COLOR_LIGHTCYAN = LXB_CSS_VALUE_LIGHTCYAN, + LXB_CSS_COLOR_LIGHTGOLDENRODYELLOW = LXB_CSS_VALUE_LIGHTGOLDENRODYELLOW, + LXB_CSS_COLOR_LIGHTGRAY = LXB_CSS_VALUE_LIGHTGRAY, + LXB_CSS_COLOR_LIGHTGREEN = LXB_CSS_VALUE_LIGHTGREEN, + LXB_CSS_COLOR_LIGHTGREY = LXB_CSS_VALUE_LIGHTGREY, + LXB_CSS_COLOR_LIGHTPINK = LXB_CSS_VALUE_LIGHTPINK, + LXB_CSS_COLOR_LIGHTSALMON = LXB_CSS_VALUE_LIGHTSALMON, + LXB_CSS_COLOR_LIGHTSEAGREEN = LXB_CSS_VALUE_LIGHTSEAGREEN, + LXB_CSS_COLOR_LIGHTSKYBLUE = LXB_CSS_VALUE_LIGHTSKYBLUE, + LXB_CSS_COLOR_LIGHTSLATEGRAY = LXB_CSS_VALUE_LIGHTSLATEGRAY, + LXB_CSS_COLOR_LIGHTSLATEGREY = LXB_CSS_VALUE_LIGHTSLATEGREY, + LXB_CSS_COLOR_LIGHTSTEELBLUE = LXB_CSS_VALUE_LIGHTSTEELBLUE, + LXB_CSS_COLOR_LIGHTYELLOW = LXB_CSS_VALUE_LIGHTYELLOW, + LXB_CSS_COLOR_LIME = LXB_CSS_VALUE_LIME, + LXB_CSS_COLOR_LIMEGREEN = LXB_CSS_VALUE_LIMEGREEN, + LXB_CSS_COLOR_LINEN = LXB_CSS_VALUE_LINEN, + LXB_CSS_COLOR_MAGENTA = LXB_CSS_VALUE_MAGENTA, + LXB_CSS_COLOR_MAROON = LXB_CSS_VALUE_MAROON, + LXB_CSS_COLOR_MEDIUMAQUAMARINE = LXB_CSS_VALUE_MEDIUMAQUAMARINE, + LXB_CSS_COLOR_MEDIUMBLUE = LXB_CSS_VALUE_MEDIUMBLUE, + LXB_CSS_COLOR_MEDIUMORCHID = LXB_CSS_VALUE_MEDIUMORCHID, + LXB_CSS_COLOR_MEDIUMPURPLE = LXB_CSS_VALUE_MEDIUMPURPLE, + LXB_CSS_COLOR_MEDIUMSEAGREEN = LXB_CSS_VALUE_MEDIUMSEAGREEN, + LXB_CSS_COLOR_MEDIUMSLATEBLUE = LXB_CSS_VALUE_MEDIUMSLATEBLUE, + LXB_CSS_COLOR_MEDIUMSPRINGGREEN = LXB_CSS_VALUE_MEDIUMSPRINGGREEN, + LXB_CSS_COLOR_MEDIUMTURQUOISE = LXB_CSS_VALUE_MEDIUMTURQUOISE, + LXB_CSS_COLOR_MEDIUMVIOLETRED = LXB_CSS_VALUE_MEDIUMVIOLETRED, + LXB_CSS_COLOR_MIDNIGHTBLUE = LXB_CSS_VALUE_MIDNIGHTBLUE, + LXB_CSS_COLOR_MINTCREAM = LXB_CSS_VALUE_MINTCREAM, + LXB_CSS_COLOR_MISTYROSE = LXB_CSS_VALUE_MISTYROSE, + LXB_CSS_COLOR_MOCCASIN = LXB_CSS_VALUE_MOCCASIN, + LXB_CSS_COLOR_NAVAJOWHITE = LXB_CSS_VALUE_NAVAJOWHITE, + LXB_CSS_COLOR_NAVY = LXB_CSS_VALUE_NAVY, + LXB_CSS_COLOR_OLDLACE = LXB_CSS_VALUE_OLDLACE, + LXB_CSS_COLOR_OLIVE = LXB_CSS_VALUE_OLIVE, + LXB_CSS_COLOR_OLIVEDRAB = LXB_CSS_VALUE_OLIVEDRAB, + LXB_CSS_COLOR_ORANGE = LXB_CSS_VALUE_ORANGE, + LXB_CSS_COLOR_ORANGERED = LXB_CSS_VALUE_ORANGERED, + LXB_CSS_COLOR_ORCHID = LXB_CSS_VALUE_ORCHID, + LXB_CSS_COLOR_PALEGOLDENROD = LXB_CSS_VALUE_PALEGOLDENROD, + LXB_CSS_COLOR_PALEGREEN = LXB_CSS_VALUE_PALEGREEN, + LXB_CSS_COLOR_PALETURQUOISE = LXB_CSS_VALUE_PALETURQUOISE, + LXB_CSS_COLOR_PALEVIOLETRED = LXB_CSS_VALUE_PALEVIOLETRED, + LXB_CSS_COLOR_PAPAYAWHIP = LXB_CSS_VALUE_PAPAYAWHIP, + LXB_CSS_COLOR_PEACHPUFF = LXB_CSS_VALUE_PEACHPUFF, + LXB_CSS_COLOR_PERU = LXB_CSS_VALUE_PERU, + LXB_CSS_COLOR_PINK = LXB_CSS_VALUE_PINK, + LXB_CSS_COLOR_PLUM = LXB_CSS_VALUE_PLUM, + LXB_CSS_COLOR_POWDERBLUE = LXB_CSS_VALUE_POWDERBLUE, + LXB_CSS_COLOR_PURPLE = LXB_CSS_VALUE_PURPLE, + LXB_CSS_COLOR_REBECCAPURPLE = LXB_CSS_VALUE_REBECCAPURPLE, + LXB_CSS_COLOR_RED = LXB_CSS_VALUE_RED, + LXB_CSS_COLOR_ROSYBROWN = LXB_CSS_VALUE_ROSYBROWN, + LXB_CSS_COLOR_ROYALBLUE = LXB_CSS_VALUE_ROYALBLUE, + LXB_CSS_COLOR_SADDLEBROWN = LXB_CSS_VALUE_SADDLEBROWN, + LXB_CSS_COLOR_SALMON = LXB_CSS_VALUE_SALMON, + LXB_CSS_COLOR_SANDYBROWN = LXB_CSS_VALUE_SANDYBROWN, + LXB_CSS_COLOR_SEAGREEN = LXB_CSS_VALUE_SEAGREEN, + LXB_CSS_COLOR_SEASHELL = LXB_CSS_VALUE_SEASHELL, + LXB_CSS_COLOR_SIENNA = LXB_CSS_VALUE_SIENNA, + LXB_CSS_COLOR_SILVER = LXB_CSS_VALUE_SILVER, + LXB_CSS_COLOR_SKYBLUE = LXB_CSS_VALUE_SKYBLUE, + LXB_CSS_COLOR_SLATEBLUE = LXB_CSS_VALUE_SLATEBLUE, + LXB_CSS_COLOR_SLATEGRAY = LXB_CSS_VALUE_SLATEGRAY, + LXB_CSS_COLOR_SLATEGREY = LXB_CSS_VALUE_SLATEGREY, + LXB_CSS_COLOR_SNOW = LXB_CSS_VALUE_SNOW, + LXB_CSS_COLOR_SPRINGGREEN = LXB_CSS_VALUE_SPRINGGREEN, + LXB_CSS_COLOR_STEELBLUE = LXB_CSS_VALUE_STEELBLUE, + LXB_CSS_COLOR_TAN = LXB_CSS_VALUE_TAN, + LXB_CSS_COLOR_TEAL = LXB_CSS_VALUE_TEAL, + LXB_CSS_COLOR_THISTLE = LXB_CSS_VALUE_THISTLE, + LXB_CSS_COLOR_TOMATO = LXB_CSS_VALUE_TOMATO, + LXB_CSS_COLOR_TURQUOISE = LXB_CSS_VALUE_TURQUOISE, + LXB_CSS_COLOR_VIOLET = LXB_CSS_VALUE_VIOLET, + LXB_CSS_COLOR_WHEAT = LXB_CSS_VALUE_WHEAT, + LXB_CSS_COLOR_WHITE = LXB_CSS_VALUE_WHITE, + LXB_CSS_COLOR_WHITESMOKE = LXB_CSS_VALUE_WHITESMOKE, + LXB_CSS_COLOR_YELLOW = LXB_CSS_VALUE_YELLOW, + LXB_CSS_COLOR_YELLOWGREEN = LXB_CSS_VALUE_YELLOWGREEN, + LXB_CSS_COLOR_CANVAS = LXB_CSS_VALUE_CANVAS, + LXB_CSS_COLOR_CANVASTEXT = LXB_CSS_VALUE_CANVASTEXT, + LXB_CSS_COLOR_LINKTEXT = LXB_CSS_VALUE_LINKTEXT, + LXB_CSS_COLOR_VISITEDTEXT = LXB_CSS_VALUE_VISITEDTEXT, + LXB_CSS_COLOR_ACTIVETEXT = LXB_CSS_VALUE_ACTIVETEXT, + LXB_CSS_COLOR_BUTTONFACE = LXB_CSS_VALUE_BUTTONFACE, + LXB_CSS_COLOR_BUTTONTEXT = LXB_CSS_VALUE_BUTTONTEXT, + LXB_CSS_COLOR_BUTTONBORDER = LXB_CSS_VALUE_BUTTONBORDER, + LXB_CSS_COLOR_FIELD = LXB_CSS_VALUE_FIELD, + LXB_CSS_COLOR_FIELDTEXT = LXB_CSS_VALUE_FIELDTEXT, + LXB_CSS_COLOR_HIGHLIGHT = LXB_CSS_VALUE_HIGHLIGHT, + LXB_CSS_COLOR_HIGHLIGHTTEXT = LXB_CSS_VALUE_HIGHLIGHTTEXT, + LXB_CSS_COLOR_SELECTEDITEM = LXB_CSS_VALUE_SELECTEDITEM, + LXB_CSS_COLOR_SELECTEDITEMTEXT = LXB_CSS_VALUE_SELECTEDITEMTEXT, + LXB_CSS_COLOR_MARK = LXB_CSS_VALUE_MARK, + LXB_CSS_COLOR_MARKTEXT = LXB_CSS_VALUE_MARKTEXT, + LXB_CSS_COLOR_GRAYTEXT = LXB_CSS_VALUE_GRAYTEXT, + LXB_CSS_COLOR_ACCENTCOLOR = LXB_CSS_VALUE_ACCENTCOLOR, + LXB_CSS_COLOR_ACCENTCOLORTEXT = LXB_CSS_VALUE_ACCENTCOLORTEXT, + LXB_CSS_COLOR_RGB = LXB_CSS_VALUE_RGB, + LXB_CSS_COLOR_RGBA = LXB_CSS_VALUE_RGBA, + LXB_CSS_COLOR_HSL = LXB_CSS_VALUE_HSL, + LXB_CSS_COLOR_HSLA = LXB_CSS_VALUE_HSLA, + LXB_CSS_COLOR_HWB = LXB_CSS_VALUE_HWB, + LXB_CSS_COLOR_LAB = LXB_CSS_VALUE_LAB, + LXB_CSS_COLOR_LCH = LXB_CSS_VALUE_LCH, + LXB_CSS_COLOR_OKLAB = LXB_CSS_VALUE_OKLAB, + LXB_CSS_COLOR_OKLCH = LXB_CSS_VALUE_OKLCH, + LXB_CSS_COLOR_COLOR = LXB_CSS_VALUE_COLOR +}; +typedef unsigned int lxb_css_color_type_t; + +enum { + LXB_CSS_DIRECTION_LTR = LXB_CSS_VALUE_LTR, + LXB_CSS_DIRECTION_RTL = LXB_CSS_VALUE_RTL +}; +typedef unsigned int lxb_css_direction_type_t; + +enum { + LXB_CSS_DISPLAY_BLOCK = LXB_CSS_VALUE_BLOCK, + LXB_CSS_DISPLAY_INLINE = LXB_CSS_VALUE_INLINE, + LXB_CSS_DISPLAY_RUN_IN = LXB_CSS_VALUE_RUN_IN, + LXB_CSS_DISPLAY_FLOW = LXB_CSS_VALUE_FLOW, + LXB_CSS_DISPLAY_FLOW_ROOT = LXB_CSS_VALUE_FLOW_ROOT, + LXB_CSS_DISPLAY_TABLE = LXB_CSS_VALUE_TABLE, + LXB_CSS_DISPLAY_FLEX = LXB_CSS_VALUE_FLEX, + LXB_CSS_DISPLAY_GRID = LXB_CSS_VALUE_GRID, + LXB_CSS_DISPLAY_RUBY = LXB_CSS_VALUE_RUBY, + LXB_CSS_DISPLAY_LIST_ITEM = LXB_CSS_VALUE_LIST_ITEM, + LXB_CSS_DISPLAY_TABLE_ROW_GROUP = LXB_CSS_VALUE_TABLE_ROW_GROUP, + LXB_CSS_DISPLAY_TABLE_HEADER_GROUP = LXB_CSS_VALUE_TABLE_HEADER_GROUP, + LXB_CSS_DISPLAY_TABLE_FOOTER_GROUP = LXB_CSS_VALUE_TABLE_FOOTER_GROUP, + LXB_CSS_DISPLAY_TABLE_ROW = LXB_CSS_VALUE_TABLE_ROW, + LXB_CSS_DISPLAY_TABLE_CELL = LXB_CSS_VALUE_TABLE_CELL, + LXB_CSS_DISPLAY_TABLE_COLUMN_GROUP = LXB_CSS_VALUE_TABLE_COLUMN_GROUP, + LXB_CSS_DISPLAY_TABLE_COLUMN = LXB_CSS_VALUE_TABLE_COLUMN, + LXB_CSS_DISPLAY_TABLE_CAPTION = LXB_CSS_VALUE_TABLE_CAPTION, + LXB_CSS_DISPLAY_RUBY_BASE = LXB_CSS_VALUE_RUBY_BASE, + LXB_CSS_DISPLAY_RUBY_TEXT = LXB_CSS_VALUE_RUBY_TEXT, + LXB_CSS_DISPLAY_RUBY_BASE_CONTAINER = LXB_CSS_VALUE_RUBY_BASE_CONTAINER, + LXB_CSS_DISPLAY_RUBY_TEXT_CONTAINER = LXB_CSS_VALUE_RUBY_TEXT_CONTAINER, + LXB_CSS_DISPLAY_CONTENTS = LXB_CSS_VALUE_CONTENTS, + LXB_CSS_DISPLAY_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_DISPLAY_INLINE_BLOCK = LXB_CSS_VALUE_INLINE_BLOCK, + LXB_CSS_DISPLAY_INLINE_TABLE = LXB_CSS_VALUE_INLINE_TABLE, + LXB_CSS_DISPLAY_INLINE_FLEX = LXB_CSS_VALUE_INLINE_FLEX, + LXB_CSS_DISPLAY_INLINE_GRID = LXB_CSS_VALUE_INLINE_GRID +}; +typedef unsigned int lxb_css_display_type_t; + +enum { + LXB_CSS_DOMINANT_BASELINE_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_DOMINANT_BASELINE_TEXT_BOTTOM = LXB_CSS_VALUE_TEXT_BOTTOM, + LXB_CSS_DOMINANT_BASELINE_ALPHABETIC = LXB_CSS_VALUE_ALPHABETIC, + LXB_CSS_DOMINANT_BASELINE_IDEOGRAPHIC = LXB_CSS_VALUE_IDEOGRAPHIC, + LXB_CSS_DOMINANT_BASELINE_MIDDLE = LXB_CSS_VALUE_MIDDLE, + LXB_CSS_DOMINANT_BASELINE_CENTRAL = LXB_CSS_VALUE_CENTRAL, + LXB_CSS_DOMINANT_BASELINE_MATHEMATICAL = LXB_CSS_VALUE_MATHEMATICAL, + LXB_CSS_DOMINANT_BASELINE_HANGING = LXB_CSS_VALUE_HANGING, + LXB_CSS_DOMINANT_BASELINE_TEXT_TOP = LXB_CSS_VALUE_TEXT_TOP +}; +typedef unsigned int lxb_css_dominant_baseline_type_t; + +enum { + LXB_CSS_FLEX_NONE = LXB_CSS_VALUE_NONE +}; +typedef unsigned int lxb_css_flex_type_t; + +enum { + LXB_CSS_FLEX_BASIS_CONTENT = LXB_CSS_VALUE_CONTENT +}; +typedef unsigned int lxb_css_flex_basis_type_t; + +enum { + LXB_CSS_FLEX_DIRECTION_ROW = LXB_CSS_VALUE_ROW, + LXB_CSS_FLEX_DIRECTION_ROW_REVERSE = LXB_CSS_VALUE_ROW_REVERSE, + LXB_CSS_FLEX_DIRECTION_COLUMN = LXB_CSS_VALUE_COLUMN, + LXB_CSS_FLEX_DIRECTION_COLUMN_REVERSE = LXB_CSS_VALUE_COLUMN_REVERSE +}; +typedef unsigned int lxb_css_flex_direction_type_t; + + + +enum { + LXB_CSS_FLEX_GROW__NUMBER = LXB_CSS_VALUE__NUMBER +}; +typedef unsigned int lxb_css_flex_grow_type_t; + +enum { + LXB_CSS_FLEX_SHRINK__NUMBER = LXB_CSS_VALUE__NUMBER +}; +typedef unsigned int lxb_css_flex_shrink_type_t; + +enum { + LXB_CSS_FLEX_WRAP_NOWRAP = LXB_CSS_VALUE_NOWRAP, + LXB_CSS_FLEX_WRAP_WRAP = LXB_CSS_VALUE_WRAP, + LXB_CSS_FLEX_WRAP_WRAP_REVERSE = LXB_CSS_VALUE_WRAP_REVERSE +}; +typedef unsigned int lxb_css_flex_wrap_type_t; + +enum { + LXB_CSS_FLOAT_BLOCK_START = LXB_CSS_VALUE_BLOCK_START, + LXB_CSS_FLOAT_BLOCK_END = LXB_CSS_VALUE_BLOCK_END, + LXB_CSS_FLOAT_INLINE_START = LXB_CSS_VALUE_INLINE_START, + LXB_CSS_FLOAT_INLINE_END = LXB_CSS_VALUE_INLINE_END, + LXB_CSS_FLOAT_SNAP_BLOCK = LXB_CSS_VALUE_SNAP_BLOCK, + LXB_CSS_FLOAT_START = LXB_CSS_VALUE_START, + LXB_CSS_FLOAT_END = LXB_CSS_VALUE_END, + LXB_CSS_FLOAT_NEAR = LXB_CSS_VALUE_NEAR, + LXB_CSS_FLOAT_SNAP_INLINE = LXB_CSS_VALUE_SNAP_INLINE, + LXB_CSS_FLOAT_LEFT = LXB_CSS_VALUE_LEFT, + LXB_CSS_FLOAT_RIGHT = LXB_CSS_VALUE_RIGHT, + LXB_CSS_FLOAT_TOP = LXB_CSS_VALUE_TOP, + LXB_CSS_FLOAT_BOTTOM = LXB_CSS_VALUE_BOTTOM, + LXB_CSS_FLOAT_NONE = LXB_CSS_VALUE_NONE +}; +typedef unsigned int lxb_css_float_type_t; + +enum { + LXB_CSS_FLOAT_DEFER__INTEGER = LXB_CSS_VALUE__INTEGER, + LXB_CSS_FLOAT_DEFER_LAST = LXB_CSS_VALUE_LAST, + LXB_CSS_FLOAT_DEFER_NONE = LXB_CSS_VALUE_NONE +}; +typedef unsigned int lxb_css_float_defer_type_t; + +enum { + LXB_CSS_FLOAT_OFFSET__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_FLOAT_OFFSET__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_float_offset_type_t; + +enum { + LXB_CSS_FLOAT_REFERENCE_INLINE = LXB_CSS_VALUE_INLINE, + LXB_CSS_FLOAT_REFERENCE_COLUMN = LXB_CSS_VALUE_COLUMN, + LXB_CSS_FLOAT_REFERENCE_REGION = LXB_CSS_VALUE_REGION, + LXB_CSS_FLOAT_REFERENCE_PAGE = LXB_CSS_VALUE_PAGE +}; +typedef unsigned int lxb_css_float_reference_type_t; + +enum { + LXB_CSS_FONT_FAMILY_SERIF = LXB_CSS_VALUE_SERIF, + LXB_CSS_FONT_FAMILY_SANS_SERIF = LXB_CSS_VALUE_SANS_SERIF, + LXB_CSS_FONT_FAMILY_CURSIVE = LXB_CSS_VALUE_CURSIVE, + LXB_CSS_FONT_FAMILY_FANTASY = LXB_CSS_VALUE_FANTASY, + LXB_CSS_FONT_FAMILY_MONOSPACE = LXB_CSS_VALUE_MONOSPACE, + LXB_CSS_FONT_FAMILY_SYSTEM_UI = LXB_CSS_VALUE_SYSTEM_UI, + LXB_CSS_FONT_FAMILY_EMOJI = LXB_CSS_VALUE_EMOJI, + LXB_CSS_FONT_FAMILY_MATH = LXB_CSS_VALUE_MATH, + LXB_CSS_FONT_FAMILY_FANGSONG = LXB_CSS_VALUE_FANGSONG, + LXB_CSS_FONT_FAMILY_UI_SERIF = LXB_CSS_VALUE_UI_SERIF, + LXB_CSS_FONT_FAMILY_UI_SANS_SERIF = LXB_CSS_VALUE_UI_SANS_SERIF, + LXB_CSS_FONT_FAMILY_UI_MONOSPACE = LXB_CSS_VALUE_UI_MONOSPACE, + LXB_CSS_FONT_FAMILY_UI_ROUNDED = LXB_CSS_VALUE_UI_ROUNDED +}; +typedef unsigned int lxb_css_font_family_type_t; + +enum { + LXB_CSS_FONT_SIZE_XX_SMALL = LXB_CSS_VALUE_XX_SMALL, + LXB_CSS_FONT_SIZE_X_SMALL = LXB_CSS_VALUE_X_SMALL, + LXB_CSS_FONT_SIZE_SMALL = LXB_CSS_VALUE_SMALL, + LXB_CSS_FONT_SIZE_MEDIUM = LXB_CSS_VALUE_MEDIUM, + LXB_CSS_FONT_SIZE_LARGE = LXB_CSS_VALUE_LARGE, + LXB_CSS_FONT_SIZE_X_LARGE = LXB_CSS_VALUE_X_LARGE, + LXB_CSS_FONT_SIZE_XX_LARGE = LXB_CSS_VALUE_XX_LARGE, + LXB_CSS_FONT_SIZE_XXX_LARGE = LXB_CSS_VALUE_XXX_LARGE, + LXB_CSS_FONT_SIZE_LARGER = LXB_CSS_VALUE_LARGER, + LXB_CSS_FONT_SIZE_SMALLER = LXB_CSS_VALUE_SMALLER, + LXB_CSS_FONT_SIZE_MATH = LXB_CSS_VALUE_MATH, + LXB_CSS_FONT_SIZE__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_font_size_type_t; + +enum { + LXB_CSS_FONT_STRETCH_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_FONT_STRETCH__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_FONT_STRETCH_ULTRA_CONDENSED = LXB_CSS_VALUE_ULTRA_CONDENSED, + LXB_CSS_FONT_STRETCH_EXTRA_CONDENSED = LXB_CSS_VALUE_EXTRA_CONDENSED, + LXB_CSS_FONT_STRETCH_CONDENSED = LXB_CSS_VALUE_CONDENSED, + LXB_CSS_FONT_STRETCH_SEMI_CONDENSED = LXB_CSS_VALUE_SEMI_CONDENSED, + LXB_CSS_FONT_STRETCH_SEMI_EXPANDED = LXB_CSS_VALUE_SEMI_EXPANDED, + LXB_CSS_FONT_STRETCH_EXPANDED = LXB_CSS_VALUE_EXPANDED, + LXB_CSS_FONT_STRETCH_EXTRA_EXPANDED = LXB_CSS_VALUE_EXTRA_EXPANDED, + LXB_CSS_FONT_STRETCH_ULTRA_EXPANDED = LXB_CSS_VALUE_ULTRA_EXPANDED +}; +typedef unsigned int lxb_css_font_stretch_type_t; + +enum { + LXB_CSS_FONT_STYLE_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_FONT_STYLE_ITALIC = LXB_CSS_VALUE_ITALIC, + LXB_CSS_FONT_STYLE_OBLIQUE = LXB_CSS_VALUE_OBLIQUE +}; +typedef unsigned int lxb_css_font_style_type_t; + +enum { + LXB_CSS_FONT_WEIGHT_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_FONT_WEIGHT_BOLD = LXB_CSS_VALUE_BOLD, + LXB_CSS_FONT_WEIGHT__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_FONT_WEIGHT_BOLDER = LXB_CSS_VALUE_BOLDER, + LXB_CSS_FONT_WEIGHT_LIGHTER = LXB_CSS_VALUE_LIGHTER +}; +typedef unsigned int lxb_css_font_weight_type_t; + +enum { + LXB_CSS_HANGING_PUNCTUATION_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_HANGING_PUNCTUATION_FIRST = LXB_CSS_VALUE_FIRST, + LXB_CSS_HANGING_PUNCTUATION_FORCE_END = LXB_CSS_VALUE_FORCE_END, + LXB_CSS_HANGING_PUNCTUATION_ALLOW_END = LXB_CSS_VALUE_ALLOW_END, + LXB_CSS_HANGING_PUNCTUATION_LAST = LXB_CSS_VALUE_LAST +}; +typedef unsigned int lxb_css_hanging_punctuation_type_t; + +enum { + LXB_CSS_HEIGHT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_HEIGHT_MIN_CONTENT = LXB_CSS_VALUE_MIN_CONTENT, + LXB_CSS_HEIGHT_MAX_CONTENT = LXB_CSS_VALUE_MAX_CONTENT, + LXB_CSS_HEIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_HEIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_HEIGHT__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_HEIGHT__ANGLE = LXB_CSS_VALUE__ANGLE +}; +typedef unsigned int lxb_css_height_type_t; + +enum { + LXB_CSS_HYPHENS_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_HYPHENS_MANUAL = LXB_CSS_VALUE_MANUAL, + LXB_CSS_HYPHENS_AUTO = LXB_CSS_VALUE_AUTO +}; +typedef unsigned int lxb_css_hyphens_type_t; + +enum { + LXB_CSS_INSET_BLOCK_END_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_INSET_BLOCK_END__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_INSET_BLOCK_END__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_inset_block_end_type_t; + +enum { + LXB_CSS_INSET_BLOCK_START_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_INSET_BLOCK_START__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_INSET_BLOCK_START__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_inset_block_start_type_t; + +enum { + LXB_CSS_INSET_INLINE_END_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_INSET_INLINE_END__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_INSET_INLINE_END__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_inset_inline_end_type_t; + +enum { + LXB_CSS_INSET_INLINE_START_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_INSET_INLINE_START__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_INSET_INLINE_START__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_inset_inline_start_type_t; + +enum { + LXB_CSS_JUSTIFY_CONTENT_FLEX_START = LXB_CSS_VALUE_FLEX_START, + LXB_CSS_JUSTIFY_CONTENT_FLEX_END = LXB_CSS_VALUE_FLEX_END, + LXB_CSS_JUSTIFY_CONTENT_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_JUSTIFY_CONTENT_SPACE_BETWEEN = LXB_CSS_VALUE_SPACE_BETWEEN, + LXB_CSS_JUSTIFY_CONTENT_SPACE_AROUND = LXB_CSS_VALUE_SPACE_AROUND +}; +typedef unsigned int lxb_css_justify_content_type_t; + +enum { + LXB_CSS_LEFT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_LEFT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_LEFT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_left_type_t; + +enum { + LXB_CSS_LETTER_SPACING_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_LETTER_SPACING__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_letter_spacing_type_t; + +enum { + LXB_CSS_LINE_BREAK_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_LINE_BREAK_LOOSE = LXB_CSS_VALUE_LOOSE, + LXB_CSS_LINE_BREAK_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_LINE_BREAK_STRICT = LXB_CSS_VALUE_STRICT, + LXB_CSS_LINE_BREAK_ANYWHERE = LXB_CSS_VALUE_ANYWHERE +}; +typedef unsigned int lxb_css_line_break_type_t; + +enum { + LXB_CSS_LINE_HEIGHT_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_LINE_HEIGHT__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_LINE_HEIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_LINE_HEIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_line_height_type_t; + +enum { + LXB_CSS_MARGIN_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MARGIN__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MARGIN__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_margin_type_t; + +enum { + LXB_CSS_MARGIN_BOTTOM_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MARGIN_BOTTOM__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MARGIN_BOTTOM__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_margin_bottom_type_t; + +enum { + LXB_CSS_MARGIN_LEFT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MARGIN_LEFT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MARGIN_LEFT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_margin_left_type_t; + +enum { + LXB_CSS_MARGIN_RIGHT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MARGIN_RIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MARGIN_RIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_margin_right_type_t; + +enum { + LXB_CSS_MARGIN_TOP_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MARGIN_TOP__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MARGIN_TOP__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_margin_top_type_t; + +enum { + LXB_CSS_MAX_HEIGHT_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_MAX_HEIGHT_MIN_CONTENT = LXB_CSS_VALUE_MIN_CONTENT, + LXB_CSS_MAX_HEIGHT_MAX_CONTENT = LXB_CSS_VALUE_MAX_CONTENT, + LXB_CSS_MAX_HEIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MAX_HEIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_MAX_HEIGHT__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_MAX_HEIGHT__ANGLE = LXB_CSS_VALUE__ANGLE +}; +typedef unsigned int lxb_css_max_height_type_t; + +enum { + LXB_CSS_MAX_WIDTH_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_MAX_WIDTH_MIN_CONTENT = LXB_CSS_VALUE_MIN_CONTENT, + LXB_CSS_MAX_WIDTH_MAX_CONTENT = LXB_CSS_VALUE_MAX_CONTENT, + LXB_CSS_MAX_WIDTH__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MAX_WIDTH__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_MAX_WIDTH__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_MAX_WIDTH__ANGLE = LXB_CSS_VALUE__ANGLE +}; +typedef unsigned int lxb_css_max_width_type_t; + +enum { + LXB_CSS_MIN_HEIGHT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MIN_HEIGHT_MIN_CONTENT = LXB_CSS_VALUE_MIN_CONTENT, + LXB_CSS_MIN_HEIGHT_MAX_CONTENT = LXB_CSS_VALUE_MAX_CONTENT, + LXB_CSS_MIN_HEIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MIN_HEIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_MIN_HEIGHT__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_MIN_HEIGHT__ANGLE = LXB_CSS_VALUE__ANGLE +}; +typedef unsigned int lxb_css_min_height_type_t; + +enum { + LXB_CSS_MIN_WIDTH_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_MIN_WIDTH_MIN_CONTENT = LXB_CSS_VALUE_MIN_CONTENT, + LXB_CSS_MIN_WIDTH_MAX_CONTENT = LXB_CSS_VALUE_MAX_CONTENT, + LXB_CSS_MIN_WIDTH__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_MIN_WIDTH__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_MIN_WIDTH__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_MIN_WIDTH__ANGLE = LXB_CSS_VALUE__ANGLE +}; +typedef unsigned int lxb_css_min_width_type_t; + +enum { + LXB_CSS_OPACITY__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_OPACITY__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_opacity_type_t; + +enum { + LXB_CSS_ORDER__INTEGER = LXB_CSS_VALUE__INTEGER +}; +typedef unsigned int lxb_css_order_type_t; + +enum { + LXB_CSS_OVERFLOW_BLOCK_VISIBLE = LXB_CSS_VALUE_VISIBLE, + LXB_CSS_OVERFLOW_BLOCK_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_OVERFLOW_BLOCK_CLIP = LXB_CSS_VALUE_CLIP, + LXB_CSS_OVERFLOW_BLOCK_SCROLL = LXB_CSS_VALUE_SCROLL, + LXB_CSS_OVERFLOW_BLOCK_AUTO = LXB_CSS_VALUE_AUTO +}; +typedef unsigned int lxb_css_overflow_block_type_t; + +enum { + LXB_CSS_OVERFLOW_INLINE_VISIBLE = LXB_CSS_VALUE_VISIBLE, + LXB_CSS_OVERFLOW_INLINE_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_OVERFLOW_INLINE_CLIP = LXB_CSS_VALUE_CLIP, + LXB_CSS_OVERFLOW_INLINE_SCROLL = LXB_CSS_VALUE_SCROLL, + LXB_CSS_OVERFLOW_INLINE_AUTO = LXB_CSS_VALUE_AUTO +}; +typedef unsigned int lxb_css_overflow_inline_type_t; + +enum { + LXB_CSS_OVERFLOW_WRAP_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_OVERFLOW_WRAP_BREAK_WORD = LXB_CSS_VALUE_BREAK_WORD, + LXB_CSS_OVERFLOW_WRAP_ANYWHERE = LXB_CSS_VALUE_ANYWHERE +}; +typedef unsigned int lxb_css_overflow_wrap_type_t; + +enum { + LXB_CSS_OVERFLOW_X_VISIBLE = LXB_CSS_VALUE_VISIBLE, + LXB_CSS_OVERFLOW_X_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_OVERFLOW_X_CLIP = LXB_CSS_VALUE_CLIP, + LXB_CSS_OVERFLOW_X_SCROLL = LXB_CSS_VALUE_SCROLL, + LXB_CSS_OVERFLOW_X_AUTO = LXB_CSS_VALUE_AUTO +}; +typedef unsigned int lxb_css_overflow_x_type_t; + +enum { + LXB_CSS_OVERFLOW_Y_VISIBLE = LXB_CSS_VALUE_VISIBLE, + LXB_CSS_OVERFLOW_Y_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_OVERFLOW_Y_CLIP = LXB_CSS_VALUE_CLIP, + LXB_CSS_OVERFLOW_Y_SCROLL = LXB_CSS_VALUE_SCROLL, + LXB_CSS_OVERFLOW_Y_AUTO = LXB_CSS_VALUE_AUTO +}; +typedef unsigned int lxb_css_overflow_y_type_t; + +enum { + LXB_CSS_PADDING_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_PADDING__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_PADDING__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_padding_type_t; + +enum { + LXB_CSS_PADDING_BOTTOM_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_PADDING_BOTTOM__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_PADDING_BOTTOM__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_padding_bottom_type_t; + +enum { + LXB_CSS_PADDING_LEFT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_PADDING_LEFT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_PADDING_LEFT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_padding_left_type_t; + +enum { + LXB_CSS_PADDING_RIGHT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_PADDING_RIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_PADDING_RIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_padding_right_type_t; + +enum { + LXB_CSS_PADDING_TOP_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_PADDING_TOP__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_PADDING_TOP__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_padding_top_type_t; + +enum { + LXB_CSS_POSITION_STATIC = LXB_CSS_VALUE_STATIC, + LXB_CSS_POSITION_RELATIVE = LXB_CSS_VALUE_RELATIVE, + LXB_CSS_POSITION_ABSOLUTE = LXB_CSS_VALUE_ABSOLUTE, + LXB_CSS_POSITION_STICKY = LXB_CSS_VALUE_STICKY, + LXB_CSS_POSITION_FIXED = LXB_CSS_VALUE_FIXED +}; +typedef unsigned int lxb_css_position_type_t; + +enum { + LXB_CSS_RIGHT_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_RIGHT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_RIGHT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_right_type_t; + +enum { + LXB_CSS_TAB_SIZE__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_TAB_SIZE__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_tab_size_type_t; + +enum { + LXB_CSS_TEXT_ALIGN_START = LXB_CSS_VALUE_START, + LXB_CSS_TEXT_ALIGN_END = LXB_CSS_VALUE_END, + LXB_CSS_TEXT_ALIGN_LEFT = LXB_CSS_VALUE_LEFT, + LXB_CSS_TEXT_ALIGN_RIGHT = LXB_CSS_VALUE_RIGHT, + LXB_CSS_TEXT_ALIGN_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_TEXT_ALIGN_JUSTIFY = LXB_CSS_VALUE_JUSTIFY, + LXB_CSS_TEXT_ALIGN_MATCH_PARENT = LXB_CSS_VALUE_MATCH_PARENT, + LXB_CSS_TEXT_ALIGN_JUSTIFY_ALL = LXB_CSS_VALUE_JUSTIFY_ALL +}; +typedef unsigned int lxb_css_text_align_type_t; + +enum { + LXB_CSS_TEXT_ALIGN_ALL_START = LXB_CSS_VALUE_START, + LXB_CSS_TEXT_ALIGN_ALL_END = LXB_CSS_VALUE_END, + LXB_CSS_TEXT_ALIGN_ALL_LEFT = LXB_CSS_VALUE_LEFT, + LXB_CSS_TEXT_ALIGN_ALL_RIGHT = LXB_CSS_VALUE_RIGHT, + LXB_CSS_TEXT_ALIGN_ALL_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_TEXT_ALIGN_ALL_JUSTIFY = LXB_CSS_VALUE_JUSTIFY, + LXB_CSS_TEXT_ALIGN_ALL_MATCH_PARENT = LXB_CSS_VALUE_MATCH_PARENT +}; +typedef unsigned int lxb_css_text_align_all_type_t; + +enum { + LXB_CSS_TEXT_ALIGN_LAST_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_TEXT_ALIGN_LAST_START = LXB_CSS_VALUE_START, + LXB_CSS_TEXT_ALIGN_LAST_END = LXB_CSS_VALUE_END, + LXB_CSS_TEXT_ALIGN_LAST_LEFT = LXB_CSS_VALUE_LEFT, + LXB_CSS_TEXT_ALIGN_LAST_RIGHT = LXB_CSS_VALUE_RIGHT, + LXB_CSS_TEXT_ALIGN_LAST_CENTER = LXB_CSS_VALUE_CENTER, + LXB_CSS_TEXT_ALIGN_LAST_JUSTIFY = LXB_CSS_VALUE_JUSTIFY, + LXB_CSS_TEXT_ALIGN_LAST_MATCH_PARENT = LXB_CSS_VALUE_MATCH_PARENT +}; +typedef unsigned int lxb_css_text_align_last_type_t; + +enum { + LXB_CSS_TEXT_COMBINE_UPRIGHT_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_TEXT_COMBINE_UPRIGHT_ALL = LXB_CSS_VALUE_ALL, + LXB_CSS_TEXT_COMBINE_UPRIGHT_DIGITS = LXB_CSS_VALUE_DIGITS +}; +typedef unsigned int lxb_css_text_combine_upright_type_t; + + + + + +enum { + LXB_CSS_TEXT_DECORATION_LINE_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_TEXT_DECORATION_LINE_UNDERLINE = LXB_CSS_VALUE_UNDERLINE, + LXB_CSS_TEXT_DECORATION_LINE_OVERLINE = LXB_CSS_VALUE_OVERLINE, + LXB_CSS_TEXT_DECORATION_LINE_LINE_THROUGH = LXB_CSS_VALUE_LINE_THROUGH, + LXB_CSS_TEXT_DECORATION_LINE_BLINK = LXB_CSS_VALUE_BLINK +}; +typedef unsigned int lxb_css_text_decoration_line_type_t; + +enum { + LXB_CSS_TEXT_DECORATION_STYLE_SOLID = LXB_CSS_VALUE_SOLID, + LXB_CSS_TEXT_DECORATION_STYLE_DOUBLE = LXB_CSS_VALUE_DOUBLE, + LXB_CSS_TEXT_DECORATION_STYLE_DOTTED = LXB_CSS_VALUE_DOTTED, + LXB_CSS_TEXT_DECORATION_STYLE_DASHED = LXB_CSS_VALUE_DASHED, + LXB_CSS_TEXT_DECORATION_STYLE_WAVY = LXB_CSS_VALUE_WAVY +}; +typedef unsigned int lxb_css_text_decoration_style_type_t; + +enum { + LXB_CSS_TEXT_INDENT__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_TEXT_INDENT__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_TEXT_INDENT_HANGING = LXB_CSS_VALUE_HANGING, + LXB_CSS_TEXT_INDENT_EACH_LINE = LXB_CSS_VALUE_EACH_LINE +}; +typedef unsigned int lxb_css_text_indent_type_t; + +enum { + LXB_CSS_TEXT_JUSTIFY_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_TEXT_JUSTIFY_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_TEXT_JUSTIFY_INTER_WORD = LXB_CSS_VALUE_INTER_WORD, + LXB_CSS_TEXT_JUSTIFY_INTER_CHARACTER = LXB_CSS_VALUE_INTER_CHARACTER +}; +typedef unsigned int lxb_css_text_justify_type_t; + +enum { + LXB_CSS_TEXT_ORIENTATION_MIXED = LXB_CSS_VALUE_MIXED, + LXB_CSS_TEXT_ORIENTATION_UPRIGHT = LXB_CSS_VALUE_UPRIGHT, + LXB_CSS_TEXT_ORIENTATION_SIDEWAYS = LXB_CSS_VALUE_SIDEWAYS +}; +typedef unsigned int lxb_css_text_orientation_type_t; + +enum { + LXB_CSS_TEXT_OVERFLOW_CLIP = LXB_CSS_VALUE_CLIP, + LXB_CSS_TEXT_OVERFLOW_ELLIPSIS = LXB_CSS_VALUE_ELLIPSIS +}; +typedef unsigned int lxb_css_text_overflow_type_t; + +enum { + LXB_CSS_TEXT_TRANSFORM_NONE = LXB_CSS_VALUE_NONE, + LXB_CSS_TEXT_TRANSFORM_CAPITALIZE = LXB_CSS_VALUE_CAPITALIZE, + LXB_CSS_TEXT_TRANSFORM_UPPERCASE = LXB_CSS_VALUE_UPPERCASE, + LXB_CSS_TEXT_TRANSFORM_LOWERCASE = LXB_CSS_VALUE_LOWERCASE, + LXB_CSS_TEXT_TRANSFORM_FULL_WIDTH = LXB_CSS_VALUE_FULL_WIDTH, + LXB_CSS_TEXT_TRANSFORM_FULL_SIZE_KANA = LXB_CSS_VALUE_FULL_SIZE_KANA +}; +typedef unsigned int lxb_css_text_transform_type_t; + +enum { + LXB_CSS_TOP_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_TOP__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_TOP__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE +}; +typedef unsigned int lxb_css_top_type_t; + +enum { + LXB_CSS_UNICODE_BIDI_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_UNICODE_BIDI_EMBED = LXB_CSS_VALUE_EMBED, + LXB_CSS_UNICODE_BIDI_ISOLATE = LXB_CSS_VALUE_ISOLATE, + LXB_CSS_UNICODE_BIDI_BIDI_OVERRIDE = LXB_CSS_VALUE_BIDI_OVERRIDE, + LXB_CSS_UNICODE_BIDI_ISOLATE_OVERRIDE = LXB_CSS_VALUE_ISOLATE_OVERRIDE, + LXB_CSS_UNICODE_BIDI_PLAINTEXT = LXB_CSS_VALUE_PLAINTEXT +}; +typedef unsigned int lxb_css_unicode_bidi_type_t; + +enum { + LXB_CSS_VERTICAL_ALIGN_FIRST = LXB_CSS_VALUE_FIRST, + LXB_CSS_VERTICAL_ALIGN_LAST = LXB_CSS_VALUE_LAST +}; +typedef unsigned int lxb_css_vertical_align_type_t; + +enum { + LXB_CSS_VISIBILITY_VISIBLE = LXB_CSS_VALUE_VISIBLE, + LXB_CSS_VISIBILITY_HIDDEN = LXB_CSS_VALUE_HIDDEN, + LXB_CSS_VISIBILITY_COLLAPSE = LXB_CSS_VALUE_COLLAPSE +}; +typedef unsigned int lxb_css_visibility_type_t; + +enum { + LXB_CSS_WHITE_SPACE_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_WHITE_SPACE_PRE = LXB_CSS_VALUE_PRE, + LXB_CSS_WHITE_SPACE_NOWRAP = LXB_CSS_VALUE_NOWRAP, + LXB_CSS_WHITE_SPACE_PRE_WRAP = LXB_CSS_VALUE_PRE_WRAP, + LXB_CSS_WHITE_SPACE_BREAK_SPACES = LXB_CSS_VALUE_BREAK_SPACES, + LXB_CSS_WHITE_SPACE_PRE_LINE = LXB_CSS_VALUE_PRE_LINE +}; +typedef unsigned int lxb_css_white_space_type_t; + +enum { + LXB_CSS_WIDTH_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_WIDTH_MIN_CONTENT = LXB_CSS_VALUE_MIN_CONTENT, + LXB_CSS_WIDTH_MAX_CONTENT = LXB_CSS_VALUE_MAX_CONTENT, + LXB_CSS_WIDTH__LENGTH = LXB_CSS_VALUE__LENGTH, + LXB_CSS_WIDTH__PERCENTAGE = LXB_CSS_VALUE__PERCENTAGE, + LXB_CSS_WIDTH__NUMBER = LXB_CSS_VALUE__NUMBER, + LXB_CSS_WIDTH__ANGLE = LXB_CSS_VALUE__ANGLE +}; +typedef unsigned int lxb_css_width_type_t; + +enum { + LXB_CSS_WORD_BREAK_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_WORD_BREAK_KEEP_ALL = LXB_CSS_VALUE_KEEP_ALL, + LXB_CSS_WORD_BREAK_BREAK_ALL = LXB_CSS_VALUE_BREAK_ALL, + LXB_CSS_WORD_BREAK_BREAK_WORD = LXB_CSS_VALUE_BREAK_WORD +}; +typedef unsigned int lxb_css_word_break_type_t; + +enum { + LXB_CSS_WORD_SPACING_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_WORD_SPACING__LENGTH = LXB_CSS_VALUE__LENGTH +}; +typedef unsigned int lxb_css_word_spacing_type_t; + +enum { + LXB_CSS_WORD_WRAP_NORMAL = LXB_CSS_VALUE_NORMAL, + LXB_CSS_WORD_WRAP_BREAK_WORD = LXB_CSS_VALUE_BREAK_WORD, + LXB_CSS_WORD_WRAP_ANYWHERE = LXB_CSS_VALUE_ANYWHERE +}; +typedef unsigned int lxb_css_word_wrap_type_t; + +enum { + LXB_CSS_WRAP_FLOW_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_WRAP_FLOW_BOTH = LXB_CSS_VALUE_BOTH, + LXB_CSS_WRAP_FLOW_START = LXB_CSS_VALUE_START, + LXB_CSS_WRAP_FLOW_END = LXB_CSS_VALUE_END, + LXB_CSS_WRAP_FLOW_MINIMUM = LXB_CSS_VALUE_MINIMUM, + LXB_CSS_WRAP_FLOW_MAXIMUM = LXB_CSS_VALUE_MAXIMUM, + LXB_CSS_WRAP_FLOW_CLEAR = LXB_CSS_VALUE_CLEAR +}; +typedef unsigned int lxb_css_wrap_flow_type_t; + +enum { + LXB_CSS_WRAP_THROUGH_WRAP = LXB_CSS_VALUE_WRAP, + LXB_CSS_WRAP_THROUGH_NONE = LXB_CSS_VALUE_NONE +}; +typedef unsigned int lxb_css_wrap_through_type_t; + +enum { + LXB_CSS_WRITING_MODE_HORIZONTAL_TB = LXB_CSS_VALUE_HORIZONTAL_TB, + LXB_CSS_WRITING_MODE_VERTICAL_RL = LXB_CSS_VALUE_VERTICAL_RL, + LXB_CSS_WRITING_MODE_VERTICAL_LR = LXB_CSS_VALUE_VERTICAL_LR, + LXB_CSS_WRITING_MODE_SIDEWAYS_RL = LXB_CSS_VALUE_SIDEWAYS_RL, + LXB_CSS_WRITING_MODE_SIDEWAYS_LR = LXB_CSS_VALUE_SIDEWAYS_LR +}; +typedef unsigned int lxb_css_writing_mode_type_t; + +enum { + LXB_CSS_Z_INDEX_AUTO = LXB_CSS_VALUE_AUTO, + LXB_CSS_Z_INDEX__INTEGER = LXB_CSS_VALUE__INTEGER +}; +typedef unsigned int lxb_css_z_index_type_t; + + +#endif /* LXB_CSS_PROPERTY_CONST_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/res.h new file mode 100644 index 0000000..eb5b903 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/res.h @@ -0,0 +1,524 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_PROPERTY_RES_H +#define LXB_CSS_PROPERTY_RES_H + +#include "lexbor/core/shs.h" +#include "lexbor/css/property/const.h" + + +static const lxb_css_entry_data_t lxb_css_property_data[LXB_CSS_PROPERTY__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_PROPERTY__UNDEF, lxb_css_property_state__undef, + lxb_css_property__undef_create, lxb_css_property__undef_destroy, lxb_css_property__undef_serialize, (void *) (uintptr_t) LXB_CSS_PROPERTY__UNDEF}, + {(lxb_char_t *) "#сustom", 7, LXB_CSS_PROPERTY__CUSTOM, lxb_css_property_state__custom, + lxb_css_property__custom_create, lxb_css_property__custom_destroy, lxb_css_property__custom_serialize, (void *) (uintptr_t) LXB_CSS_PROPERTY__CUSTOM}, + {(lxb_char_t *) "align-content", 13, LXB_CSS_PROPERTY_ALIGN_CONTENT, lxb_css_property_state_align_content, + lxb_css_property_align_content_create, lxb_css_property_align_content_destroy, lxb_css_property_align_content_serialize, + &(lxb_css_property_align_content_t) {.type = LXB_CSS_ALIGN_CONTENT_STRETCH}}, + {(lxb_char_t *) "align-items", 11, LXB_CSS_PROPERTY_ALIGN_ITEMS, lxb_css_property_state_align_items, + lxb_css_property_align_items_create, lxb_css_property_align_items_destroy, lxb_css_property_align_items_serialize, + &(lxb_css_property_align_items_t) {.type = LXB_CSS_ALIGN_ITEMS_STRETCH}}, + {(lxb_char_t *) "align-self", 10, LXB_CSS_PROPERTY_ALIGN_SELF, lxb_css_property_state_align_self, + lxb_css_property_align_self_create, lxb_css_property_align_self_destroy, lxb_css_property_align_self_serialize, + &(lxb_css_property_align_self_t) {.type = LXB_CSS_ALIGN_SELF_AUTO}}, + {(lxb_char_t *) "alignment-baseline", 18, LXB_CSS_PROPERTY_ALIGNMENT_BASELINE, lxb_css_property_state_alignment_baseline, + lxb_css_property_alignment_baseline_create, lxb_css_property_alignment_baseline_destroy, lxb_css_property_alignment_baseline_serialize, + &(lxb_css_property_alignment_baseline_t) {.type = LXB_CSS_ALIGNMENT_BASELINE_BASELINE}}, + {(lxb_char_t *) "background-color", 16, LXB_CSS_PROPERTY_BACKGROUND_COLOR, lxb_css_property_state_background_color, + lxb_css_property_background_color_create, lxb_css_property_background_color_destroy, lxb_css_property_background_color_serialize, + &(lxb_css_property_background_color_t) {.type = LXB_CSS_COLOR_TRANSPARENT}}, + {(lxb_char_t *) "baseline-shift", 14, LXB_CSS_PROPERTY_BASELINE_SHIFT, lxb_css_property_state_baseline_shift, + lxb_css_property_baseline_shift_create, lxb_css_property_baseline_shift_destroy, lxb_css_property_baseline_shift_serialize, + &(lxb_css_property_baseline_shift_t) {.type = LXB_CSS_VALUE__NUMBER, .u = {.length = {.num = 0, .is_float = false, .unit = LXB_CSS_UNIT__UNDEF}}}}, + {(lxb_char_t *) "baseline-source", 15, LXB_CSS_PROPERTY_BASELINE_SOURCE, lxb_css_property_state_baseline_source, + lxb_css_property_baseline_source_create, lxb_css_property_baseline_source_destroy, lxb_css_property_baseline_source_serialize, + &(lxb_css_property_baseline_source_t) {.type = LXB_CSS_BASELINE_SOURCE_AUTO}}, + {(lxb_char_t *) "border", 6, LXB_CSS_PROPERTY_BORDER, lxb_css_property_state_border, + lxb_css_property_border_create, lxb_css_property_border_destroy, lxb_css_property_border_serialize, + &(lxb_css_property_border_t) {.style = LXB_CSS_BORDER_NONE, .width = {.type = LXB_CSS_BORDER_MEDIUM}, .color = {.type = LXB_CSS_COLOR_CURRENTCOLOR}}}, + {(lxb_char_t *) "border-bottom", 13, LXB_CSS_PROPERTY_BORDER_BOTTOM, lxb_css_property_state_border_bottom, + lxb_css_property_border_bottom_create, lxb_css_property_border_bottom_destroy, lxb_css_property_border_bottom_serialize, + &(lxb_css_property_border_bottom_t) {.style = LXB_CSS_BORDER_NONE, .width = {.type = LXB_CSS_BORDER_MEDIUM}, .color = {.type = LXB_CSS_COLOR_CURRENTCOLOR}}}, + {(lxb_char_t *) "border-bottom-color", 19, LXB_CSS_PROPERTY_BORDER_BOTTOM_COLOR, lxb_css_property_state_border_bottom_color, + lxb_css_property_border_bottom_color_create, lxb_css_property_border_bottom_color_destroy, lxb_css_property_border_bottom_color_serialize, + &(lxb_css_property_border_bottom_color_t) {.type = LXB_CSS_COLOR_CURRENTCOLOR}}, + {(lxb_char_t *) "border-left", 11, LXB_CSS_PROPERTY_BORDER_LEFT, lxb_css_property_state_border_left, + lxb_css_property_border_left_create, lxb_css_property_border_left_destroy, lxb_css_property_border_left_serialize, + &(lxb_css_property_border_left_t) {.style = LXB_CSS_BORDER_NONE, .width = {.type = LXB_CSS_BORDER_MEDIUM}, .color = {.type = LXB_CSS_COLOR_CURRENTCOLOR}}}, + {(lxb_char_t *) "border-left-color", 17, LXB_CSS_PROPERTY_BORDER_LEFT_COLOR, lxb_css_property_state_border_left_color, + lxb_css_property_border_left_color_create, lxb_css_property_border_left_color_destroy, lxb_css_property_border_left_color_serialize, + &(lxb_css_property_border_left_color_t) {.type = LXB_CSS_COLOR_CURRENTCOLOR}}, + {(lxb_char_t *) "border-right", 12, LXB_CSS_PROPERTY_BORDER_RIGHT, lxb_css_property_state_border_right, + lxb_css_property_border_right_create, lxb_css_property_border_right_destroy, lxb_css_property_border_right_serialize, + &(lxb_css_property_border_right_t) {.style = LXB_CSS_BORDER_NONE, .width = {.type = LXB_CSS_BORDER_MEDIUM}, .color = {.type = LXB_CSS_COLOR_CURRENTCOLOR}}}, + {(lxb_char_t *) "border-right-color", 18, LXB_CSS_PROPERTY_BORDER_RIGHT_COLOR, lxb_css_property_state_border_right_color, + lxb_css_property_border_right_color_create, lxb_css_property_border_right_color_destroy, lxb_css_property_border_right_color_serialize, + &(lxb_css_property_border_right_color_t) {.type = LXB_CSS_COLOR_CURRENTCOLOR}}, + {(lxb_char_t *) "border-top", 10, LXB_CSS_PROPERTY_BORDER_TOP, lxb_css_property_state_border_top, + lxb_css_property_border_top_create, lxb_css_property_border_top_destroy, lxb_css_property_border_top_serialize, + &(lxb_css_property_border_top_t) {.style = LXB_CSS_BORDER_NONE, .width = {.type = LXB_CSS_BORDER_MEDIUM}, .color = {.type = LXB_CSS_COLOR_CURRENTCOLOR}}}, + {(lxb_char_t *) "border-top-color", 16, LXB_CSS_PROPERTY_BORDER_TOP_COLOR, lxb_css_property_state_border_top_color, + lxb_css_property_border_top_color_create, lxb_css_property_border_top_color_destroy, lxb_css_property_border_top_color_serialize, + &(lxb_css_property_border_top_color_t) {.type = LXB_CSS_COLOR_CURRENTCOLOR}}, + {(lxb_char_t *) "bottom", 6, LXB_CSS_PROPERTY_BOTTOM, lxb_css_property_state_bottom, + lxb_css_property_bottom_create, lxb_css_property_bottom_destroy, lxb_css_property_bottom_serialize, + &(lxb_css_property_bottom_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "box-sizing", 10, LXB_CSS_PROPERTY_BOX_SIZING, lxb_css_property_state_box_sizing, + lxb_css_property_box_sizing_create, lxb_css_property_box_sizing_destroy, lxb_css_property_box_sizing_serialize, + &(lxb_css_property_box_sizing_t) {.type = LXB_CSS_BOX_SIZING_CONTENT_BOX}}, + {(lxb_char_t *) "clear", 5, LXB_CSS_PROPERTY_CLEAR, lxb_css_property_state_clear, + lxb_css_property_clear_create, lxb_css_property_clear_destroy, lxb_css_property_clear_serialize, + &(lxb_css_property_clear_t) {.type = LXB_CSS_CLEAR_NONE}}, + {(lxb_char_t *) "color", 5, LXB_CSS_PROPERTY_COLOR, lxb_css_property_state_color, + lxb_css_property_color_create, lxb_css_property_color_destroy, lxb_css_property_color_serialize, + &(lxb_css_value_color_t) {.type = LXB_CSS_COLOR_CURRENTCOLOR}}, + {(lxb_char_t *) "direction", 9, LXB_CSS_PROPERTY_DIRECTION, lxb_css_property_state_direction, + lxb_css_property_direction_create, lxb_css_property_direction_destroy, lxb_css_property_direction_serialize, + &(lxb_css_property_direction_t) {.type = LXB_CSS_DIRECTION_LTR}}, + {(lxb_char_t *) "display", 7, LXB_CSS_PROPERTY_DISPLAY, lxb_css_property_state_display, + lxb_css_property_display_create, lxb_css_property_display_destroy, lxb_css_property_display_serialize, + &(lxb_css_property_display_t) {.a = LXB_CSS_DISPLAY_INLINE, .b = LXB_CSS_PROPERTY__UNDEF, .c = LXB_CSS_PROPERTY__UNDEF}}, + {(lxb_char_t *) "dominant-baseline", 17, LXB_CSS_PROPERTY_DOMINANT_BASELINE, lxb_css_property_state_dominant_baseline, + lxb_css_property_dominant_baseline_create, lxb_css_property_dominant_baseline_destroy, lxb_css_property_dominant_baseline_serialize, + &(lxb_css_property_dominant_baseline_t) {.type = LXB_CSS_DOMINANT_BASELINE_AUTO}}, + {(lxb_char_t *) "flex", 4, LXB_CSS_PROPERTY_FLEX, lxb_css_property_state_flex, + lxb_css_property_flex_create, lxb_css_property_flex_destroy, lxb_css_property_flex_serialize, + &(lxb_css_property_flex_t) {.type = LXB_CSS_VALUE__UNDEF, .grow = {.type = LXB_CSS_FLEX_GROW__NUMBER, .number = {.num = 0, .is_float = false}}, .shrink = {.type = LXB_CSS_FLEX_SHRINK__NUMBER, .number = {.num = 1, .is_float = false}}, .basis = {.type = LXB_CSS_WIDTH_AUTO, .u.length = {.num = 0, .is_float = false}}}}, + {(lxb_char_t *) "flex-basis", 10, LXB_CSS_PROPERTY_FLEX_BASIS, lxb_css_property_state_flex_basis, + lxb_css_property_flex_basis_create, lxb_css_property_flex_basis_destroy, lxb_css_property_flex_basis_serialize, + &(lxb_css_property_flex_basis_t) {.type = LXB_CSS_WIDTH_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "flex-direction", 14, LXB_CSS_PROPERTY_FLEX_DIRECTION, lxb_css_property_state_flex_direction, + lxb_css_property_flex_direction_create, lxb_css_property_flex_direction_destroy, lxb_css_property_flex_direction_serialize, + &(lxb_css_property_flex_direction_t) {.type = LXB_CSS_FLEX_DIRECTION_ROW}}, + {(lxb_char_t *) "flex-flow", 9, LXB_CSS_PROPERTY_FLEX_FLOW, lxb_css_property_state_flex_flow, + lxb_css_property_flex_flow_create, lxb_css_property_flex_flow_destroy, lxb_css_property_flex_flow_serialize, + &(lxb_css_property_flex_flow_t) {.type_direction = LXB_CSS_FLEX_DIRECTION_ROW, .wrap = LXB_CSS_FLEX_WRAP_NOWRAP}}, + {(lxb_char_t *) "flex-grow", 9, LXB_CSS_PROPERTY_FLEX_GROW, lxb_css_property_state_flex_grow, + lxb_css_property_flex_grow_create, lxb_css_property_flex_grow_destroy, lxb_css_property_flex_grow_serialize, + &(lxb_css_property_flex_grow_t) {.type = LXB_CSS_FLEX_GROW__NUMBER, .number = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "flex-shrink", 11, LXB_CSS_PROPERTY_FLEX_SHRINK, lxb_css_property_state_flex_shrink, + lxb_css_property_flex_shrink_create, lxb_css_property_flex_shrink_destroy, lxb_css_property_flex_shrink_serialize, + &(lxb_css_property_flex_shrink_t) {.type = LXB_CSS_FLEX_SHRINK__NUMBER, .number = {.num = 1, .is_float = false}}}, + {(lxb_char_t *) "flex-wrap", 9, LXB_CSS_PROPERTY_FLEX_WRAP, lxb_css_property_state_flex_wrap, + lxb_css_property_flex_wrap_create, lxb_css_property_flex_wrap_destroy, lxb_css_property_flex_wrap_serialize, + &(lxb_css_property_flex_wrap_t) {.type = LXB_CSS_FLEX_WRAP_NOWRAP}}, + {(lxb_char_t *) "float", 5, LXB_CSS_PROPERTY_FLOAT, lxb_css_property_state_float, + lxb_css_property_float_create, lxb_css_property_float_destroy, lxb_css_property_float_serialize, + &(lxb_css_property_float_t) {.type = LXB_CSS_FLOAT_NONE}}, + {(lxb_char_t *) "float-defer", 11, LXB_CSS_PROPERTY_FLOAT_DEFER, lxb_css_property_state_float_defer, + lxb_css_property_float_defer_create, lxb_css_property_float_defer_destroy, lxb_css_property_float_defer_serialize, + &(lxb_css_property_float_defer_t) {.type = LXB_CSS_FLOAT_DEFER_NONE}}, + {(lxb_char_t *) "float-offset", 12, LXB_CSS_PROPERTY_FLOAT_OFFSET, lxb_css_property_state_float_offset, + lxb_css_property_float_offset_create, lxb_css_property_float_offset_destroy, lxb_css_property_float_offset_serialize, + &(lxb_css_property_float_offset_t) {.type = LXB_CSS_VALUE__NUMBER, .u = {.length = {.num = 0, .is_float = false, .unit = LXB_CSS_UNIT__UNDEF}}}}, + {(lxb_char_t *) "float-reference", 15, LXB_CSS_PROPERTY_FLOAT_REFERENCE, lxb_css_property_state_float_reference, + lxb_css_property_float_reference_create, lxb_css_property_float_reference_destroy, lxb_css_property_float_reference_serialize, + &(lxb_css_property_float_reference_t) {.type = LXB_CSS_FLOAT_REFERENCE_INLINE}}, + {(lxb_char_t *) "font-family", 11, LXB_CSS_PROPERTY_FONT_FAMILY, lxb_css_property_state_font_family, + lxb_css_property_font_family_create, lxb_css_property_font_family_destroy, lxb_css_property_font_family_serialize, + NULL}, + {(lxb_char_t *) "font-size", 9, LXB_CSS_PROPERTY_FONT_SIZE, lxb_css_property_state_font_size, + lxb_css_property_font_size_create, lxb_css_property_font_size_destroy, lxb_css_property_font_size_serialize, + &(lxb_css_property_font_size_t) {.type = LXB_CSS_FONT_SIZE_MEDIUM}}, + {(lxb_char_t *) "font-stretch", 12, LXB_CSS_PROPERTY_FONT_STRETCH, lxb_css_property_state_font_stretch, + lxb_css_property_font_stretch_create, lxb_css_property_font_stretch_destroy, lxb_css_property_font_stretch_serialize, + &(lxb_css_property_font_stretch_t) {.type = LXB_CSS_FONT_STRETCH_NORMAL}}, + {(lxb_char_t *) "font-style", 10, LXB_CSS_PROPERTY_FONT_STYLE, lxb_css_property_state_font_style, + lxb_css_property_font_style_create, lxb_css_property_font_style_destroy, lxb_css_property_font_style_serialize, + &(lxb_css_property_font_style_t) {.type = LXB_CSS_FONT_STYLE_NORMAL}}, + {(lxb_char_t *) "font-weight", 11, LXB_CSS_PROPERTY_FONT_WEIGHT, lxb_css_property_state_font_weight, + lxb_css_property_font_weight_create, lxb_css_property_font_weight_destroy, lxb_css_property_font_weight_serialize, + &(lxb_css_property_font_weight_t) {.type = LXB_CSS_FONT_WEIGHT_NORMAL}}, + {(lxb_char_t *) "hanging-punctuation", 19, LXB_CSS_PROPERTY_HANGING_PUNCTUATION, lxb_css_property_state_hanging_punctuation, + lxb_css_property_hanging_punctuation_create, lxb_css_property_hanging_punctuation_destroy, lxb_css_property_hanging_punctuation_serialize, + &(lxb_css_property_hanging_punctuation_t) {.type_first = LXB_CSS_HANGING_PUNCTUATION_NONE}}, + {(lxb_char_t *) "height", 6, LXB_CSS_PROPERTY_HEIGHT, lxb_css_property_state_height, + lxb_css_property_height_create, lxb_css_property_height_destroy, lxb_css_property_height_serialize, + &(lxb_css_property_height_t) {.type = LXB_CSS_HEIGHT_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "hyphens", 7, LXB_CSS_PROPERTY_HYPHENS, lxb_css_property_state_hyphens, + lxb_css_property_hyphens_create, lxb_css_property_hyphens_destroy, lxb_css_property_hyphens_serialize, + &(lxb_css_property_hyphens_t) {.type = LXB_CSS_HYPHENS_MANUAL}}, + {(lxb_char_t *) "inset-block-end", 15, LXB_CSS_PROPERTY_INSET_BLOCK_END, lxb_css_property_state_inset_block_end, + lxb_css_property_inset_block_end_create, lxb_css_property_inset_block_end_destroy, lxb_css_property_inset_block_end_serialize, + &(lxb_css_property_inset_block_end_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "inset-block-start", 17, LXB_CSS_PROPERTY_INSET_BLOCK_START, lxb_css_property_state_inset_block_start, + lxb_css_property_inset_block_start_create, lxb_css_property_inset_block_start_destroy, lxb_css_property_inset_block_start_serialize, + &(lxb_css_property_inset_block_start_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "inset-inline-end", 16, LXB_CSS_PROPERTY_INSET_INLINE_END, lxb_css_property_state_inset_inline_end, + lxb_css_property_inset_inline_end_create, lxb_css_property_inset_inline_end_destroy, lxb_css_property_inset_inline_end_serialize, + &(lxb_css_property_inset_inline_end_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "inset-inline-start", 18, LXB_CSS_PROPERTY_INSET_INLINE_START, lxb_css_property_state_inset_inline_start, + lxb_css_property_inset_inline_start_create, lxb_css_property_inset_inline_start_destroy, lxb_css_property_inset_inline_start_serialize, + &(lxb_css_property_inset_inline_start_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "justify-content", 15, LXB_CSS_PROPERTY_JUSTIFY_CONTENT, lxb_css_property_state_justify_content, + lxb_css_property_justify_content_create, lxb_css_property_justify_content_destroy, lxb_css_property_justify_content_serialize, + &(lxb_css_property_justify_content_t) {.type = LXB_CSS_JUSTIFY_CONTENT_FLEX_START}}, + {(lxb_char_t *) "left", 4, LXB_CSS_PROPERTY_LEFT, lxb_css_property_state_left, + lxb_css_property_left_create, lxb_css_property_left_destroy, lxb_css_property_left_serialize, + &(lxb_css_property_left_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "letter-spacing", 14, LXB_CSS_PROPERTY_LETTER_SPACING, lxb_css_property_state_letter_spacing, + lxb_css_property_letter_spacing_create, lxb_css_property_letter_spacing_destroy, lxb_css_property_letter_spacing_serialize, + &(lxb_css_property_letter_spacing_t) {.type = LXB_CSS_LETTER_SPACING_NORMAL}}, + {(lxb_char_t *) "line-break", 10, LXB_CSS_PROPERTY_LINE_BREAK, lxb_css_property_state_line_break, + lxb_css_property_line_break_create, lxb_css_property_line_break_destroy, lxb_css_property_line_break_serialize, + &(lxb_css_property_line_break_t) {.type = LXB_CSS_LINE_BREAK_AUTO}}, + {(lxb_char_t *) "line-height", 11, LXB_CSS_PROPERTY_LINE_HEIGHT, lxb_css_property_state_line_height, + lxb_css_property_line_height_create, lxb_css_property_line_height_destroy, lxb_css_property_line_height_serialize, + &(lxb_css_property_line_height_t) {.type = LXB_CSS_LINE_HEIGHT_NORMAL}}, + {(lxb_char_t *) "margin", 6, LXB_CSS_PROPERTY_MARGIN, lxb_css_property_state_margin, + lxb_css_property_margin_create, lxb_css_property_margin_destroy, lxb_css_property_margin_serialize, + &(lxb_css_property_margin_t) {.top = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}, .right = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}, .bottom = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}, .left = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}}, + {(lxb_char_t *) "margin-bottom", 13, LXB_CSS_PROPERTY_MARGIN_BOTTOM, lxb_css_property_state_margin_bottom, + lxb_css_property_margin_bottom_create, lxb_css_property_margin_bottom_destroy, lxb_css_property_margin_bottom_serialize, + &(lxb_css_property_margin_bottom_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "margin-left", 11, LXB_CSS_PROPERTY_MARGIN_LEFT, lxb_css_property_state_margin_left, + lxb_css_property_margin_left_create, lxb_css_property_margin_left_destroy, lxb_css_property_margin_left_serialize, + &(lxb_css_property_margin_left_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "margin-right", 12, LXB_CSS_PROPERTY_MARGIN_RIGHT, lxb_css_property_state_margin_right, + lxb_css_property_margin_right_create, lxb_css_property_margin_right_destroy, lxb_css_property_margin_right_serialize, + &(lxb_css_property_margin_right_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "margin-top", 10, LXB_CSS_PROPERTY_MARGIN_TOP, lxb_css_property_state_margin_top, + lxb_css_property_margin_top_create, lxb_css_property_margin_top_destroy, lxb_css_property_margin_top_serialize, + &(lxb_css_property_margin_top_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "max-height", 10, LXB_CSS_PROPERTY_MAX_HEIGHT, lxb_css_property_state_max_height, + lxb_css_property_max_height_create, lxb_css_property_max_height_destroy, lxb_css_property_max_height_serialize, + &(lxb_css_property_max_height_t) {.type = LXB_CSS_MAX_HEIGHT_NONE, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "max-width", 9, LXB_CSS_PROPERTY_MAX_WIDTH, lxb_css_property_state_max_width, + lxb_css_property_max_width_create, lxb_css_property_max_width_destroy, lxb_css_property_max_width_serialize, + &(lxb_css_property_max_width_t) {.type = LXB_CSS_MAX_WIDTH_NONE, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "min-height", 10, LXB_CSS_PROPERTY_MIN_HEIGHT, lxb_css_property_state_min_height, + lxb_css_property_min_height_create, lxb_css_property_min_height_destroy, lxb_css_property_min_height_serialize, + &(lxb_css_property_min_height_t) {.type = LXB_CSS_MIN_HEIGHT_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "min-width", 9, LXB_CSS_PROPERTY_MIN_WIDTH, lxb_css_property_state_min_width, + lxb_css_property_min_width_create, lxb_css_property_min_width_destroy, lxb_css_property_min_width_serialize, + &(lxb_css_property_min_width_t) {.type = LXB_CSS_MIN_WIDTH_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "opacity", 7, LXB_CSS_PROPERTY_OPACITY, lxb_css_property_state_opacity, + lxb_css_property_opacity_create, lxb_css_property_opacity_destroy, lxb_css_property_opacity_serialize, + &(lxb_css_property_opacity_t) {.type = LXB_CSS_OPACITY__NUMBER, .u = {.number = {.num = 1, .is_float = false}}}}, + {(lxb_char_t *) "order", 5, LXB_CSS_PROPERTY_ORDER, lxb_css_property_state_order, + lxb_css_property_order_create, lxb_css_property_order_destroy, lxb_css_property_order_serialize, + &(lxb_css_property_order_t) {.type = LXB_CSS_ORDER__INTEGER, .integer = {.num = 0}}}, + {(lxb_char_t *) "overflow-block", 14, LXB_CSS_PROPERTY_OVERFLOW_BLOCK, lxb_css_property_state_overflow_block, + lxb_css_property_overflow_block_create, lxb_css_property_overflow_block_destroy, lxb_css_property_overflow_block_serialize, + &(lxb_css_property_overflow_block_t) {.type = LXB_CSS_OVERFLOW_BLOCK_VISIBLE}}, + {(lxb_char_t *) "overflow-inline", 15, LXB_CSS_PROPERTY_OVERFLOW_INLINE, lxb_css_property_state_overflow_inline, + lxb_css_property_overflow_inline_create, lxb_css_property_overflow_inline_destroy, lxb_css_property_overflow_inline_serialize, + &(lxb_css_property_overflow_inline_t) {.type = LXB_CSS_OVERFLOW_INLINE_VISIBLE}}, + {(lxb_char_t *) "overflow-wrap", 13, LXB_CSS_PROPERTY_OVERFLOW_WRAP, lxb_css_property_state_overflow_wrap, + lxb_css_property_overflow_wrap_create, lxb_css_property_overflow_wrap_destroy, lxb_css_property_overflow_wrap_serialize, + &(lxb_css_property_overflow_wrap_t) {.type = LXB_CSS_OVERFLOW_WRAP_NORMAL}}, + {(lxb_char_t *) "overflow-x", 10, LXB_CSS_PROPERTY_OVERFLOW_X, lxb_css_property_state_overflow_x, + lxb_css_property_overflow_x_create, lxb_css_property_overflow_x_destroy, lxb_css_property_overflow_x_serialize, + &(lxb_css_property_overflow_x_t) {.type = LXB_CSS_OVERFLOW_X_VISIBLE}}, + {(lxb_char_t *) "overflow-y", 10, LXB_CSS_PROPERTY_OVERFLOW_Y, lxb_css_property_state_overflow_y, + lxb_css_property_overflow_y_create, lxb_css_property_overflow_y_destroy, lxb_css_property_overflow_y_serialize, + &(lxb_css_property_overflow_y_t) {.type = LXB_CSS_OVERFLOW_Y_VISIBLE}}, + {(lxb_char_t *) "padding", 7, LXB_CSS_PROPERTY_PADDING, lxb_css_property_state_padding, + lxb_css_property_padding_create, lxb_css_property_padding_destroy, lxb_css_property_padding_serialize, + &(lxb_css_property_padding_t) {.top = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}, .right = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}, .bottom = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}, .left = {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}}, + {(lxb_char_t *) "padding-bottom", 14, LXB_CSS_PROPERTY_PADDING_BOTTOM, lxb_css_property_state_padding_bottom, + lxb_css_property_padding_bottom_create, lxb_css_property_padding_bottom_destroy, lxb_css_property_padding_bottom_serialize, + &(lxb_css_property_padding_bottom_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "padding-left", 12, LXB_CSS_PROPERTY_PADDING_LEFT, lxb_css_property_state_padding_left, + lxb_css_property_padding_left_create, lxb_css_property_padding_left_destroy, lxb_css_property_padding_left_serialize, + &(lxb_css_property_padding_left_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "padding-right", 13, LXB_CSS_PROPERTY_PADDING_RIGHT, lxb_css_property_state_padding_right, + lxb_css_property_padding_right_create, lxb_css_property_padding_right_destroy, lxb_css_property_padding_right_serialize, + &(lxb_css_property_padding_right_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "padding-top", 11, LXB_CSS_PROPERTY_PADDING_TOP, lxb_css_property_state_padding_top, + lxb_css_property_padding_top_create, lxb_css_property_padding_top_destroy, lxb_css_property_padding_top_serialize, + &(lxb_css_property_padding_top_t) {.type = LXB_CSS_VALUE__LENGTH, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "position", 8, LXB_CSS_PROPERTY_POSITION, lxb_css_property_state_position, + lxb_css_property_position_create, lxb_css_property_position_destroy, lxb_css_property_position_serialize, + &(lxb_css_property_position_t) {.type = LXB_CSS_POSITION_STATIC}}, + {(lxb_char_t *) "right", 5, LXB_CSS_PROPERTY_RIGHT, lxb_css_property_state_right, + lxb_css_property_right_create, lxb_css_property_right_destroy, lxb_css_property_right_serialize, + &(lxb_css_property_right_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "tab-size", 8, LXB_CSS_PROPERTY_TAB_SIZE, lxb_css_property_state_tab_size, + lxb_css_property_tab_size_create, lxb_css_property_tab_size_destroy, lxb_css_property_tab_size_serialize, + &(lxb_css_property_tab_size_t) {.type = LXB_CSS_VALUE__NUMBER, .u = {.number = {.num = 8, .is_float = false}}}}, + {(lxb_char_t *) "text-align", 10, LXB_CSS_PROPERTY_TEXT_ALIGN, lxb_css_property_state_text_align, + lxb_css_property_text_align_create, lxb_css_property_text_align_destroy, lxb_css_property_text_align_serialize, + &(lxb_css_property_text_align_t) {.type = LXB_CSS_TEXT_ALIGN_START}}, + {(lxb_char_t *) "text-align-all", 14, LXB_CSS_PROPERTY_TEXT_ALIGN_ALL, lxb_css_property_state_text_align_all, + lxb_css_property_text_align_all_create, lxb_css_property_text_align_all_destroy, lxb_css_property_text_align_all_serialize, + &(lxb_css_property_text_align_all_t) {.type = LXB_CSS_TEXT_ALIGN_ALL_START}}, + {(lxb_char_t *) "text-align-last", 15, LXB_CSS_PROPERTY_TEXT_ALIGN_LAST, lxb_css_property_state_text_align_last, + lxb_css_property_text_align_last_create, lxb_css_property_text_align_last_destroy, lxb_css_property_text_align_last_serialize, + &(lxb_css_property_text_align_last_t) {.type = LXB_CSS_TEXT_ALIGN_LAST_AUTO}}, + {(lxb_char_t *) "text-combine-upright", 20, LXB_CSS_PROPERTY_TEXT_COMBINE_UPRIGHT, lxb_css_property_state_text_combine_upright, + lxb_css_property_text_combine_upright_create, lxb_css_property_text_combine_upright_destroy, lxb_css_property_text_combine_upright_serialize, + &(lxb_css_property_text_combine_upright_t) {.type = LXB_CSS_TEXT_COMBINE_UPRIGHT_NONE}}, + {(lxb_char_t *) "text-decoration", 15, LXB_CSS_PROPERTY_TEXT_DECORATION, lxb_css_property_state_text_decoration, + lxb_css_property_text_decoration_create, lxb_css_property_text_decoration_destroy, lxb_css_property_text_decoration_serialize, + &(lxb_css_property_text_decoration_t) {.line = {.type = LXB_CSS_TEXT_DECORATION_LINE_NONE}, .style = {.type = LXB_CSS_TEXT_DECORATION_STYLE_SOLID}, .color = {.type = LXB_CSS_COLOR_CURRENTCOLOR}}}, + {(lxb_char_t *) "text-decoration-color", 21, LXB_CSS_PROPERTY_TEXT_DECORATION_COLOR, lxb_css_property_state_text_decoration_color, + lxb_css_property_text_decoration_color_create, lxb_css_property_text_decoration_color_destroy, lxb_css_property_text_decoration_color_serialize, + &(lxb_css_property_text_decoration_color_t) {.type = LXB_CSS_COLOR_CURRENTCOLOR}}, + {(lxb_char_t *) "text-decoration-line", 20, LXB_CSS_PROPERTY_TEXT_DECORATION_LINE, lxb_css_property_state_text_decoration_line, + lxb_css_property_text_decoration_line_create, lxb_css_property_text_decoration_line_destroy, lxb_css_property_text_decoration_line_serialize, + &(lxb_css_property_text_decoration_line_t) {.type = LXB_CSS_TEXT_DECORATION_LINE_NONE}}, + {(lxb_char_t *) "text-decoration-style", 21, LXB_CSS_PROPERTY_TEXT_DECORATION_STYLE, lxb_css_property_state_text_decoration_style, + lxb_css_property_text_decoration_style_create, lxb_css_property_text_decoration_style_destroy, lxb_css_property_text_decoration_style_serialize, + &(lxb_css_property_text_decoration_style_t) {.type = LXB_CSS_TEXT_DECORATION_STYLE_SOLID}}, + {(lxb_char_t *) "text-indent", 11, LXB_CSS_PROPERTY_TEXT_INDENT, lxb_css_property_state_text_indent, + lxb_css_property_text_indent_create, lxb_css_property_text_indent_destroy, lxb_css_property_text_indent_serialize, + &(lxb_css_property_text_indent_t) {.length = {.type = LXB_CSS_VALUE__LENGTH, .u = {.length = {.num = 0, .is_float = false, .unit = LXB_CSS_UNIT__UNDEF}}}}}, + {(lxb_char_t *) "text-justify", 12, LXB_CSS_PROPERTY_TEXT_JUSTIFY, lxb_css_property_state_text_justify, + lxb_css_property_text_justify_create, lxb_css_property_text_justify_destroy, lxb_css_property_text_justify_serialize, + &(lxb_css_property_text_justify_t) {.type = LXB_CSS_TEXT_JUSTIFY_AUTO}}, + {(lxb_char_t *) "text-orientation", 16, LXB_CSS_PROPERTY_TEXT_ORIENTATION, lxb_css_property_state_text_orientation, + lxb_css_property_text_orientation_create, lxb_css_property_text_orientation_destroy, lxb_css_property_text_orientation_serialize, + &(lxb_css_property_text_orientation_t) {.type = LXB_CSS_TEXT_ORIENTATION_MIXED}}, + {(lxb_char_t *) "text-overflow", 13, LXB_CSS_PROPERTY_TEXT_OVERFLOW, lxb_css_property_state_text_overflow, + lxb_css_property_text_overflow_create, lxb_css_property_text_overflow_destroy, lxb_css_property_text_overflow_serialize, + &(lxb_css_property_text_overflow_t) {.type = LXB_CSS_TEXT_OVERFLOW_CLIP}}, + {(lxb_char_t *) "text-transform", 14, LXB_CSS_PROPERTY_TEXT_TRANSFORM, lxb_css_property_state_text_transform, + lxb_css_property_text_transform_create, lxb_css_property_text_transform_destroy, lxb_css_property_text_transform_serialize, + &(lxb_css_property_text_transform_t) {.type_case = LXB_CSS_TEXT_TRANSFORM_NONE, .full_width = LXB_CSS_PROPERTY__UNDEF, .full_size_kana = LXB_CSS_PROPERTY__UNDEF}}, + {(lxb_char_t *) "top", 3, LXB_CSS_PROPERTY_TOP, lxb_css_property_state_top, + lxb_css_property_top_create, lxb_css_property_top_destroy, lxb_css_property_top_serialize, + &(lxb_css_property_top_t) {.type = LXB_CSS_VALUE_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "unicode-bidi", 12, LXB_CSS_PROPERTY_UNICODE_BIDI, lxb_css_property_state_unicode_bidi, + lxb_css_property_unicode_bidi_create, lxb_css_property_unicode_bidi_destroy, lxb_css_property_unicode_bidi_serialize, + &(lxb_css_property_unicode_bidi_t) {.type = LXB_CSS_UNICODE_BIDI_NORMAL}}, + {(lxb_char_t *) "vertical-align", 14, LXB_CSS_PROPERTY_VERTICAL_ALIGN, lxb_css_property_state_vertical_align, + lxb_css_property_vertical_align_create, lxb_css_property_vertical_align_destroy, lxb_css_property_vertical_align_serialize, + &(lxb_css_property_vertical_align_t) {.type = LXB_CSS_ALIGNMENT_BASELINE_BASELINE}}, + {(lxb_char_t *) "visibility", 10, LXB_CSS_PROPERTY_VISIBILITY, lxb_css_property_state_visibility, + lxb_css_property_visibility_create, lxb_css_property_visibility_destroy, lxb_css_property_visibility_serialize, + &(lxb_css_property_visibility_t) {.type = LXB_CSS_VISIBILITY_VISIBLE}}, + {(lxb_char_t *) "white-space", 11, LXB_CSS_PROPERTY_WHITE_SPACE, lxb_css_property_state_white_space, + lxb_css_property_white_space_create, lxb_css_property_white_space_destroy, lxb_css_property_white_space_serialize, + &(lxb_css_property_white_space_t) {.type = LXB_CSS_WHITE_SPACE_NORMAL}}, + {(lxb_char_t *) "width", 5, LXB_CSS_PROPERTY_WIDTH, lxb_css_property_state_width, + lxb_css_property_width_create, lxb_css_property_width_destroy, lxb_css_property_width_serialize, + &(lxb_css_property_width_t) {.type = LXB_CSS_WIDTH_AUTO, .u.length = {.num = 0, .is_float = false}}}, + {(lxb_char_t *) "word-break", 10, LXB_CSS_PROPERTY_WORD_BREAK, lxb_css_property_state_word_break, + lxb_css_property_word_break_create, lxb_css_property_word_break_destroy, lxb_css_property_word_break_serialize, + &(lxb_css_property_word_break_t) {.type = LXB_CSS_WORD_BREAK_NORMAL}}, + {(lxb_char_t *) "word-spacing", 12, LXB_CSS_PROPERTY_WORD_SPACING, lxb_css_property_state_word_spacing, + lxb_css_property_word_spacing_create, lxb_css_property_word_spacing_destroy, lxb_css_property_word_spacing_serialize, + &(lxb_css_property_word_spacing_t) {.type = LXB_CSS_WORD_SPACING_NORMAL}}, + {(lxb_char_t *) "word-wrap", 9, LXB_CSS_PROPERTY_WORD_WRAP, lxb_css_property_state_word_wrap, + lxb_css_property_word_wrap_create, lxb_css_property_word_wrap_destroy, lxb_css_property_word_wrap_serialize, + &(lxb_css_property_word_wrap_t) {.type = LXB_CSS_WORD_WRAP_NORMAL}}, + {(lxb_char_t *) "wrap-flow", 9, LXB_CSS_PROPERTY_WRAP_FLOW, lxb_css_property_state_wrap_flow, + lxb_css_property_wrap_flow_create, lxb_css_property_wrap_flow_destroy, lxb_css_property_wrap_flow_serialize, + &(lxb_css_property_wrap_flow_t) {.type = LXB_CSS_WRAP_FLOW_AUTO}}, + {(lxb_char_t *) "wrap-through", 12, LXB_CSS_PROPERTY_WRAP_THROUGH, lxb_css_property_state_wrap_through, + lxb_css_property_wrap_through_create, lxb_css_property_wrap_through_destroy, lxb_css_property_wrap_through_serialize, + &(lxb_css_property_wrap_through_t) {.type = LXB_CSS_WRAP_THROUGH_WRAP}}, + {(lxb_char_t *) "writing-mode", 12, LXB_CSS_PROPERTY_WRITING_MODE, lxb_css_property_state_writing_mode, + lxb_css_property_writing_mode_create, lxb_css_property_writing_mode_destroy, lxb_css_property_writing_mode_serialize, + &(lxb_css_property_writing_mode_t) {.type = LXB_CSS_WRITING_MODE_HORIZONTAL_TB}}, + {(lxb_char_t *) "z-index", 7, LXB_CSS_PROPERTY_Z_INDEX, lxb_css_property_state_z_index, + lxb_css_property_z_index_create, lxb_css_property_z_index_destroy, lxb_css_property_z_index_serialize, + &(lxb_css_property_z_index_t) {.type = LXB_CSS_Z_INDEX_AUTO}} +}; + +static const lexbor_shs_entry_t lxb_css_property_shs[187] = +{ + {NULL, NULL, 186, 0}, + {"wrap-through", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WRAP_THROUGH], 12, 0}, + {"width", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WIDTH], 5, 0}, + {"color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_COLOR], 5, 0}, + {"text-overflow", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_OVERFLOW], 13, 0}, + {"text-combine-upright", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_COMBINE_UPRIGHT], 20, 0}, + {"direction", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_DIRECTION], 9, 0}, + {"baseline-source", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BASELINE_SOURCE], 15, 0}, + {"min-width", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MIN_WIDTH], 9, 0}, + {"wrap-flow", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WRAP_FLOW], 9, 1}, + {"align-content", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_ALIGN_CONTENT], 13, 0}, + {"padding-left", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_PADDING_LEFT], 12, 0}, + {"right", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_RIGHT], 5, 0}, + {"font-stretch", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FONT_STRETCH], 12, 0}, + {"flex-grow", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX_GROW], 9, 0}, + {"border-top-color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_TOP_COLOR], 16, 0}, + {"border-left-color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_LEFT_COLOR], 17, 0}, + {"overflow-x", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_OVERFLOW_X], 10, 0}, + {"clear", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_CLEAR], 5, 3}, + {"padding-top", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_PADDING_TOP], 11, 0}, + {"word-wrap", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WORD_WRAP], 9, 0}, + {"border-top", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_TOP], 10, 0}, + {"font-style", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FONT_STYLE], 10, 0}, + {"text-transform", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_TRANSFORM], 14, 0}, + {"white-space", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WHITE_SPACE], 11, 0}, + {"padding-bottom", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_PADDING_BOTTOM], 14, 0}, + {"vertical-align", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_VERTICAL_ALIGN], 14, 0}, + {"visibility", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_VISIBILITY], 10, 0}, + {"min-height", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MIN_HEIGHT], 10, 0}, + {"inset-inline-start", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_INSET_INLINE_START], 18, 0}, + {"flex-shrink", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX_SHRINK], 11, 7}, + {NULL, NULL, 0, 0}, + {"overflow-wrap", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_OVERFLOW_WRAP], 13, 0}, + {"letter-spacing", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_LETTER_SPACING], 14, 0}, + {NULL, NULL, 0, 0}, + {"bottom", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BOTTOM], 6, 0}, + {"max-width", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MAX_WIDTH], 9, 8}, + {NULL, NULL, 0, 0}, + {"dominant-baseline", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_DOMINANT_BASELINE], 17, 0}, + {"margin-top", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MARGIN_TOP], 10, 11}, + {"padding-right", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_PADDING_RIGHT], 13, 0}, + {NULL, NULL, 0, 0}, + {"border-bottom", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_BOTTOM], 13, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"text-align-all", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_ALIGN_ALL], 14, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"font-family", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FONT_FAMILY], 11, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"flex", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX], 4, 0}, + {"alignment-baseline", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_ALIGNMENT_BASELINE], 18, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"opacity", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_OPACITY], 7, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"overflow-y", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_OVERFLOW_Y], 10, 0}, + {NULL, NULL, 0, 0}, + {"text-decoration-color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_DECORATION_COLOR], 21, 0}, + {"left", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_LEFT], 4, 0}, + {"hyphens", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_HYPHENS], 7, 0}, + {"border", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER], 6, 13}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"flex-flow", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX_FLOW], 9, 14}, + {NULL, NULL, 0, 0}, + {"line-height", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_LINE_HEIGHT], 11, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"box-sizing", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BOX_SIZING], 10, 0}, + {NULL, NULL, 0, 0}, + {"background-color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BACKGROUND_COLOR], 16, 15}, + {"display", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_DISPLAY], 7, 16}, + {"border-right-color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_RIGHT_COLOR], 18, 0}, + {"border-bottom-color", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_BOTTOM_COLOR], 19, 0}, + {"margin", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MARGIN], 6, 0}, + {"word-break", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WORD_BREAK], 10, 19}, + {NULL, NULL, 0, 0}, + {"padding", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_PADDING], 7, 0}, + {"align-items", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_ALIGN_ITEMS], 11, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"justify-content", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_JUSTIFY_CONTENT], 15, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"height", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_HEIGHT], 6, 0}, + {"inset-block-end", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_INSET_BLOCK_END], 15, 0}, + {"inset-inline-end", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_INSET_INLINE_END], 16, 0}, + {NULL, NULL, 0, 0}, + {"overflow-inline", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_OVERFLOW_INLINE], 15, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"font-size", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FONT_SIZE], 9, 0}, + {"position", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_POSITION], 8, 22}, + {"float", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLOAT], 5, 0}, + {NULL, NULL, 0, 0}, + {"top", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TOP], 3, 0}, + {NULL, NULL, 0, 0}, + {"float-reference", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLOAT_REFERENCE], 15, 0}, + {NULL, NULL, 0, 0}, + {"font-weight", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FONT_WEIGHT], 11, 0}, + {"float-offset", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLOAT_OFFSET], 12, 23}, + {NULL, NULL, 0, 0}, + {"margin-bottom", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MARGIN_BOTTOM], 13, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"order", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_ORDER], 5, 0}, + {NULL, NULL, 0, 0}, + {"z-index", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_Z_INDEX], 7, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"flex-basis", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX_BASIS], 10, 24}, + {"writing-mode", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WRITING_MODE], 12, 0}, + {NULL, NULL, 0, 0}, + {"border-left", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_LEFT], 11, 0}, + {"border-right", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BORDER_RIGHT], 12, 0}, + {"hanging-punctuation", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_HANGING_PUNCTUATION], 19, 0}, + {"baseline-shift", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_BASELINE_SHIFT], 14, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"text-justify", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_JUSTIFY], 12, 26}, + {"float-defer", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLOAT_DEFER], 11, 0}, + {"max-height", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MAX_HEIGHT], 10, 28}, + {"margin-left", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MARGIN_LEFT], 11, 0}, + {"margin-right", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_MARGIN_RIGHT], 12, 0}, + {"unicode-bidi", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_UNICODE_BIDI], 12, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"tab-size", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TAB_SIZE], 8, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"flex-wrap", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX_WRAP], 9, 0}, + {"align-self", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_ALIGN_SELF], 10, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"text-decoration-line", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_DECORATION_LINE], 20, 0}, + {"text-decoration-style", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_DECORATION_STYLE], 21, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"inset-block-start", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_INSET_BLOCK_START], 17, 0}, + {"text-align", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_ALIGN], 10, 29}, + {"word-spacing", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_WORD_SPACING], 12, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"text-decoration", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_DECORATION], 15, 0}, + {"text-orientation", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_ORIENTATION], 16, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"overflow-block", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_OVERFLOW_BLOCK], 14, 0}, + {NULL, NULL, 0, 0}, + {"text-indent", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_INDENT], 11, 0}, + {"flex-direction", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_FLEX_DIRECTION], 14, 0}, + {NULL, NULL, 0, 0}, + {"line-break", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_LINE_BREAK], 10, 0}, + {"text-align-last", (void *) &lxb_css_property_data[LXB_CSS_PROPERTY_TEXT_ALIGN_LAST], 15, 0} +}; + + +#endif /* LXB_CSS_PROPERTY_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/state.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/state.c new file mode 100644 index 0000000..198ef14 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/state.c @@ -0,0 +1,5343 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/property.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/rule.h" +#include "lexbor/css/value.h" +#include "lexbor/css/unit.h" +#include "lexbor/css/property/state.h" +#include "lexbor/css/property/res.h" + + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_map_hex[256]; + LXB_EXTERN const lxb_char_t lexbor_str_res_map_lowercase[256]; +#endif + +#include "lexbor/core/conv.h" + + +#define lxb_css_property_state_check_token(parser, token) \ + if ((token) == NULL) { \ + return lxb_css_parser_memory_fail(parser); \ + } + +#define lxb_css_property_state_get_type(parser, token, type) \ + do { \ + lxb_css_syntax_parser_consume(parser); \ + \ + token = lxb_css_syntax_parser_token_wo_ws(parser); \ + lxb_css_property_state_check_token(parser, token); \ + \ + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { \ + return lxb_css_parser_success(parser); \ + } \ + \ + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, \ + lxb_css_syntax_token_ident(token)->length); \ + } \ + while (false) + +#define LXB_CSS_PROPERTY_STATE_HEX_MASK(n) \ + ((((uint32_t) 1 << (32 - (n))) - 1) << (n)) + + +static bool +lxb_css_property_state_color_rgba_old(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_color_t *color); +static bool +lxb_css_property_state_color_hsla_old(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_color_hsla_t *hsl); + +static bool +lxb_css_property_state_length(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_length_t *length) +{ + const lxb_css_data_t *unit; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + unit = lxb_css_unit_absolute_relative_by_name(lxb_css_syntax_token_dimension(token)->str.data, + lxb_css_syntax_token_dimension(token)->str.length); + if (unit == NULL) { + return false; + } + + length->num = lxb_css_syntax_token_dimension(token)->num.num; + length->is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + length->unit = (lxb_css_unit_t) unit->unique; + break; + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + if (lxb_css_syntax_token_number(token)->num != 0) { + return false; + } + + length->num = lxb_css_syntax_token_number(token)->num; + length->is_float = lxb_css_syntax_token_number(token)->is_float; + length->unit = LXB_CSS_UNIT__UNDEF; + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_length_percentage(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_length_percentage_t *lp) +{ + const lxb_css_data_t *unit; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + unit = lxb_css_unit_absolute_relative_by_name(lxb_css_syntax_token_dimension(token)->str.data, + lxb_css_syntax_token_dimension(token)->str.length); + if (unit == NULL) { + return false; + } + + lp->type = LXB_CSS_VALUE__LENGTH; + lp->u.length.num = lxb_css_syntax_token_dimension(token)->num.num; + lp->u.length.is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + lp->u.length.unit = (lxb_css_unit_t) unit->unique; + break; + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + if (lxb_css_syntax_token_number(token)->num != 0) { + return false; + } + + lp->type = LXB_CSS_VALUE__NUMBER; + lp->u.length.num = lxb_css_syntax_token_number(token)->num; + lp->u.length.is_float = lxb_css_syntax_token_number(token)->is_float; + lp->u.length.unit = LXB_CSS_UNIT__UNDEF; + break; + + case LXB_CSS_SYNTAX_TOKEN_PERCENTAGE: + lp->type = LXB_CSS_VALUE__PERCENTAGE; + lp->u.percentage.num = lxb_css_syntax_token_percentage(token)->num; + lp->u.percentage.is_float = lxb_css_syntax_token_percentage(token)->is_float; + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_number_length_percentage(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_number_length_percentage_t *nlp) +{ + const lxb_css_data_t *unit; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + unit = lxb_css_unit_absolute_relative_by_name(lxb_css_syntax_token_dimension(token)->str.data, + lxb_css_syntax_token_dimension(token)->str.length); + if (unit == NULL) { + return false; + } + + nlp->type = LXB_CSS_VALUE__LENGTH; + nlp->u.length.num = lxb_css_syntax_token_dimension(token)->num.num; + nlp->u.length.is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + nlp->u.length.unit = (lxb_css_unit_t) unit->unique; + break; + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + nlp->type = LXB_CSS_VALUE__NUMBER; + nlp->u.number.num = lxb_css_syntax_token_number(token)->num; + nlp->u.number.is_float = lxb_css_syntax_token_number(token)->is_float; + break; + + case LXB_CSS_SYNTAX_TOKEN_PERCENTAGE: + nlp->type = LXB_CSS_VALUE__PERCENTAGE; + nlp->u.percentage.num = lxb_css_syntax_token_percentage(token)->num; + nlp->u.percentage.is_float = lxb_css_syntax_token_percentage(token)->is_float; + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_number_length(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_number_length_t *nl) +{ + const lxb_css_data_t *unit; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + unit = lxb_css_unit_absolute_relative_by_name(lxb_css_syntax_token_dimension(token)->str.data, + lxb_css_syntax_token_dimension(token)->str.length); + if (unit == NULL) { + return false; + } + + nl->type = LXB_CSS_VALUE__LENGTH; + nl->u.length.num = lxb_css_syntax_token_dimension(token)->num.num; + nl->u.length.is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + nl->u.length.unit = (lxb_css_unit_t) unit->unique; + break; + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + nl->type = LXB_CSS_VALUE__NUMBER; + nl->u.number.num = lxb_css_syntax_token_number(token)->num; + nl->u.number.is_float = lxb_css_syntax_token_number(token)->is_float; + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_number(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_number_t *number) +{ + if (token->type != LXB_CSS_SYNTAX_TOKEN_NUMBER) { + return false; + } + + number->num = lxb_css_syntax_token_number(token)->num; + number->is_float = lxb_css_syntax_token_number(token)->is_float; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_integer(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_integer_t *intg) +{ + long ln; + double num; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_NUMBER) { + return false; + } + + num = lxb_css_syntax_token_number(token)->num; + ln = lexbor_conv_double_to_long(num); + + num = num - (double) ln; + + if (num < 0.0 || num > 0.0) { + return false; + } + + intg->num = ln; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_percentage(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_percentage_t *perc) +{ + if (token->type != LXB_CSS_SYNTAX_TOKEN_PERCENTAGE) { + return false; + } + + perc->num = lxb_css_syntax_token_percentage(token)->num; + perc->is_float = lxb_css_syntax_token_percentage(token)->is_float; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_number_percentage_none(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_number_percentage_t *np) +{ + double num; + lxb_css_value_type_t type; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_NUMBER) { + np->type = LXB_CSS_VALUE__NUMBER; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_PERCENTAGE) { + np->type = LXB_CSS_VALUE__PERCENTAGE; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + if (type != LXB_CSS_VALUE_NONE) { + return false; + } + + np->type = LXB_CSS_VALUE_NONE; + + lxb_css_syntax_parser_consume(parser); + + return true; + } + else { + return false; + } + + num = lxb_css_syntax_token_number(token)->num; + + np->u.number.num = num; + np->u.number.is_float = lxb_css_syntax_token_number(token)->is_float; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_percentage_none(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_percentage_type_t *np) +{ + double num; + lxb_css_value_type_t type; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_PERCENTAGE) { + np->type = LXB_CSS_VALUE__PERCENTAGE; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + if (type != LXB_CSS_VALUE_NONE) { + return false; + } + + np->type = LXB_CSS_VALUE_NONE; + + lxb_css_syntax_parser_consume(parser); + + return true; + } + else { + return false; + } + + num = lxb_css_syntax_token_number(token)->num; + + np->percentage.num = num; + np->percentage.is_float = lxb_css_syntax_token_number(token)->is_float; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_number_percentage(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_number_percentage_t *np) +{ + double num; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_NUMBER) { + np->type = LXB_CSS_VALUE__NUMBER; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_PERCENTAGE) { + np->type = LXB_CSS_VALUE__PERCENTAGE; + } + else { + return false; + } + + num = lxb_css_syntax_token_number(token)->num; + + np->u.number.num = num; + np->u.number.is_float = lxb_css_syntax_token_number(token)->is_float; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_angle(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_angle_t *angle) +{ + const lxb_css_data_t *unit; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_DIMENSION) { + return false; + } + + unit = lxb_css_unit_angle_by_name(lxb_css_syntax_token_dimension(token)->str.data, + lxb_css_syntax_token_dimension(token)->str.length); + if (unit == NULL) { + return false; + } + + angle->num = lxb_css_syntax_token_dimension(token)->num.num; + angle->is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + angle->unit = (lxb_css_unit_angle_t) unit->unique; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +bool +lxb_css_property_state_width_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_width_t *width) +{ + lxb_css_value_type_t type; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_AUTO: + case LXB_CSS_VALUE_MIN_CONTENT: + case LXB_CSS_VALUE_MAX_CONTENT: + width->type = type; + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; + } + + return lxb_css_property_state_length_percentage(parser, token, + (lxb_css_value_length_percentage_t *)width); +} + +static bool +lxb_css_property_state_hue(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_hue_t *hue) +{ + const lxb_css_data_t *unit; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + unit = lxb_css_unit_angle_by_name(lxb_css_syntax_token_dimension(token)->str.data, + lxb_css_syntax_token_dimension(token)->str.length); + if (unit == NULL) { + return false; + } + + hue->type = LXB_CSS_VALUE__ANGLE; + hue->u.angle.num = lxb_css_syntax_token_dimension(token)->num.num; + hue->u.angle.is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + hue->u.angle.unit = (lxb_css_unit_angle_t) unit->unique; + break; + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + hue->type = LXB_CSS_VALUE__NUMBER; + hue->u.number.num = lxb_css_syntax_token_number(token)->num; + hue->u.number.is_float = lxb_css_syntax_token_number(token)->is_float; + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +lxb_inline bool +lxb_css_property_state_hue_none(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_hue_t *hue) +{ + lxb_css_value_type_t type; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_property_state_hue(parser, token, hue); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + if (type != LXB_CSS_VALUE_NONE) { + return false; + } + + hue->type = LXB_CSS_VALUE_NONE; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_color_hex(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_color_t *color) +{ + size_t length; + uint32_t chex; + lxb_char_t ch; + const lxb_char_t *end, *p; + lxb_css_value_color_hex_rgba_t *rgba; + + length = token->types.hash.length; + + if (length > 8) { + return false; + } + + p = token->types.hash.data; + end = p + length; + + chex = 0; + + while (p < end) { + ch = lexbor_str_res_map_lowercase[lexbor_str_res_map_hex[*p]]; + + if (ch == 0xff) { + return false; + } + + chex = chex << 4 | ch; + + p++; + } + + rgba = &color->u.hex.rgba; + + switch (length) { + case 3: + rgba->r = chex >> 8; + rgba->g = chex >> 4 & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(4); + rgba->b = chex & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(4); + rgba->a = 0xff; + + color->u.hex.type = LXB_CSS_PROPERTY_COLOR_HEX_TYPE_3; + break; + + case 4: + rgba->r = chex >> 12; + rgba->g = chex >> 8 & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(4); + rgba->b = chex >> 4 & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(4); + rgba->a = chex & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(4); + + color->u.hex.type = LXB_CSS_PROPERTY_COLOR_HEX_TYPE_4; + break; + + case 6: + rgba->r = chex >> 16; + rgba->g = chex >> 8 & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(8); + rgba->b = chex & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(8); + rgba->a = 0xff; + + color->u.hex.type = LXB_CSS_PROPERTY_COLOR_HEX_TYPE_6; + break; + + case 8: + rgba->r = chex >> 24; + rgba->g = chex >> 16 & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(8); + rgba->b = chex >> 8 & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(8); + rgba->a = chex & ~LXB_CSS_PROPERTY_STATE_HEX_MASK(8); + + color->u.hex.type = LXB_CSS_PROPERTY_COLOR_HEX_TYPE_8; + break; + + default: + return false; + } + + color->type = LXB_CSS_COLOR_HEX; + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_color_rgba(lxb_css_parser_t *parser, + lxb_css_value_color_t *color) +{ + bool res; + lxb_css_color_type_t type; + lxb_css_value_color_rgba_t *rgb; + const lxb_css_syntax_token_t *token; + + rgb = &color->u.rgb; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &rgb->r); + if (res == false) { + return false; + } + + type = rgb->r.type; + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_COMMA) { + /* Deprecated format. */ + + if (type == LXB_CSS_VALUE_NONE) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + rgb->old = true; + + return lxb_css_property_state_color_rgba_old(parser, token, color); + } + + res = lxb_css_property_state_number_percentage_none(parser, token, &rgb->g); + if (res == false) { + return false; + } + + if (type != rgb->g.type) { + if (type == LXB_CSS_VALUE_NONE) { + type = rgb->g.type; + } + else if (rgb->g.type != LXB_CSS_VALUE_NONE) { + return false; + } + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &rgb->b); + if (res == false) { + return false; + } + + if (type != rgb->b.type && type != LXB_CSS_VALUE_NONE + && rgb->b.type != LXB_CSS_VALUE_NONE) + { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM) { + if (lxb_css_syntax_token_delim(token)->character != '/') { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + lxb_css_syntax_parser_consume(parser); + return true; + } + else { + return false; + } + + res = lxb_css_property_state_number_percentage_none(parser, token, &rgb->a); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_color_rgba_old(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_color_t *color) +{ + bool res; + lxb_css_value_color_rgba_t *rgb; + + rgb = &color->u.rgb; + + res = lxb_css_property_state_number_percentage(parser, token, &rgb->g); + if (res == false) { + return false; + } + + if (rgb->r.type != rgb->g.type) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage(parser, token, &rgb->b); + if (res == false) { + return false; + } + + if (rgb->r.type != rgb->b.type) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + lxb_css_syntax_parser_consume(parser); + return true; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage(parser, token, &rgb->a); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_color_hsla(lxb_css_parser_t *parser, + lxb_css_value_color_t *color) +{ + bool res; + lxb_css_value_color_hsla_t *hsl; + const lxb_css_syntax_token_t *token; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + hsl = &color->u.hsl; + + res = lxb_css_property_state_hue_none(parser, token, &hsl->h); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_COMMA) { + /* Deprecated format. */ + + if (hsl->h.type == LXB_CSS_VALUE_NONE) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + hsl->old = true; + + return lxb_css_property_state_color_hsla_old(parser, token, hsl); + } + + res = lxb_css_property_state_percentage_none(parser, token, &hsl->s); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_percentage_none(parser, token, &hsl->l); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM) { + if (lxb_css_syntax_token_delim(token)->character != '/') { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + lxb_css_syntax_parser_consume(parser); + return true; + } + + res = lxb_css_property_state_number_percentage_none(parser, token, &hsl->a); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_color_hsla_old(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_color_hsla_t *hsl) +{ + bool res; + + res = lxb_css_property_state_percentage(parser, token, &hsl->s.percentage); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_percentage(parser, token, &hsl->l.percentage); + if (res == false) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + goto done; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage(parser, token, &hsl->a); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + return false; + } + +done: + + lxb_css_syntax_parser_consume(parser); + + hsl->s.type = LXB_CSS_VALUE__PERCENTAGE; + hsl->l.type = LXB_CSS_VALUE__PERCENTAGE; + + return true; +} + +static bool +lxb_css_property_state_color_lab(lxb_css_parser_t *parser, + lxb_css_value_color_t *color) +{ + bool res; + lxb_css_value_color_lab_t *lab; + const lxb_css_syntax_token_t *token; + + lab = &color->u.lab; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &lab->l); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &lab->a); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &lab->b); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM) { + if (lxb_css_syntax_token_delim(token)->character != '/') { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + lxb_css_syntax_parser_consume(parser); + return true; + } + else { + return false; + } + + res = lxb_css_property_state_number_percentage_none(parser, token, + &lab->alpha); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +static bool +lxb_css_property_state_color_lch(lxb_css_parser_t *parser, + lxb_css_value_color_t *color) +{ + bool res; + lxb_css_value_color_lch_t *lch; + const lxb_css_syntax_token_t *token; + + lch = &color->u.lch; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &lch->l); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number_percentage_none(parser, token, &lch->c); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_hue_none(parser, token, &lch->h); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM) { + if (lxb_css_syntax_token_delim(token)->character != '/') { + return false; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + lxb_css_syntax_parser_consume(parser); + return true; + } + else { + return false; + } + + res = lxb_css_property_state_number_percentage_none(parser, token, &lch->a); + if (res == false) { + return false; + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +/* + * Return: + * true and status always LXB_STATUS_OK — token consumed, ok. + * false and status != LXB_STATUS_OK — token consumed, not ok. + * false and status == LXB_STATUS_OK — token not consumed, not ok. + */ +static bool +lxb_css_property_state_color_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_value_color_t *color, + lxb_status_t *status) +{ + bool res; + lxb_css_value_type_t type; + + *status = LXB_STATUS_OK; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_HASH: + color->type = LXB_CSS_VALUE_HEX; + + return lxb_css_property_state_color_hex(parser, token, color); + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + type = lxb_css_value_by_name(lxb_css_syntax_token_function(token)->data, + lxb_css_syntax_token_function(token)->length); + color->type = type; + + switch (type) { + /* */ + case LXB_CSS_VALUE_RGB: + case LXB_CSS_VALUE_RGBA: + res = lxb_css_property_state_color_rgba(parser, color); + break; + + case LXB_CSS_VALUE_HSL: + case LXB_CSS_VALUE_HSLA: + case LXB_CSS_VALUE_HWB: + res = lxb_css_property_state_color_hsla(parser, color); + break; + + case LXB_CSS_VALUE_LAB: + case LXB_CSS_VALUE_OKLAB: + res = lxb_css_property_state_color_lab(parser, color); + break; + + case LXB_CSS_VALUE_LCH: + case LXB_CSS_VALUE_OKLCH: + res = lxb_css_property_state_color_lch(parser, color); + break; + + case LXB_CSS_VALUE_COLOR: + default: + *status = LXB_STATUS_OK; + return false; + } + + if (!res) { + *status = LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + return res; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* */ + case LXB_CSS_VALUE_CURRENTCOLOR: + /* */ + case LXB_CSS_VALUE_CANVAS: + case LXB_CSS_VALUE_CANVASTEXT: + case LXB_CSS_VALUE_LINKTEXT: + case LXB_CSS_VALUE_VISITEDTEXT: + case LXB_CSS_VALUE_ACTIVETEXT: + case LXB_CSS_VALUE_BUTTONFACE: + case LXB_CSS_VALUE_BUTTONTEXT: + case LXB_CSS_VALUE_BUTTONBORDER: + case LXB_CSS_VALUE_FIELD: + case LXB_CSS_VALUE_FIELDTEXT: + case LXB_CSS_VALUE_HIGHLIGHT: + case LXB_CSS_VALUE_HIGHLIGHTTEXT: + case LXB_CSS_VALUE_SELECTEDITEM: + case LXB_CSS_VALUE_SELECTEDITEMTEXT: + case LXB_CSS_VALUE_MARK: + case LXB_CSS_VALUE_MARKTEXT: + case LXB_CSS_VALUE_GRAYTEXT: + case LXB_CSS_VALUE_ACCENTCOLOR: + case LXB_CSS_VALUE_ACCENTCOLORTEXT: + /* */ + case LXB_CSS_VALUE_TRANSPARENT: + /* */ + case LXB_CSS_VALUE_ALICEBLUE: + case LXB_CSS_VALUE_ANTIQUEWHITE: + case LXB_CSS_VALUE_AQUA: + case LXB_CSS_VALUE_AQUAMARINE: + case LXB_CSS_VALUE_AZURE: + case LXB_CSS_VALUE_BEIGE: + case LXB_CSS_VALUE_BISQUE: + case LXB_CSS_VALUE_BLACK: + case LXB_CSS_VALUE_BLANCHEDALMOND: + case LXB_CSS_VALUE_BLUE: + case LXB_CSS_VALUE_BLUEVIOLET: + case LXB_CSS_VALUE_BROWN: + case LXB_CSS_VALUE_BURLYWOOD: + case LXB_CSS_VALUE_CADETBLUE: + case LXB_CSS_VALUE_CHARTREUSE: + case LXB_CSS_VALUE_CHOCOLATE: + case LXB_CSS_VALUE_CORAL: + case LXB_CSS_VALUE_CORNFLOWERBLUE: + case LXB_CSS_VALUE_CORNSILK: + case LXB_CSS_VALUE_CRIMSON: + case LXB_CSS_VALUE_CYAN: + case LXB_CSS_VALUE_DARKBLUE: + case LXB_CSS_VALUE_DARKCYAN: + case LXB_CSS_VALUE_DARKGOLDENROD: + case LXB_CSS_VALUE_DARKGRAY: + case LXB_CSS_VALUE_DARKGREEN: + case LXB_CSS_VALUE_DARKGREY: + case LXB_CSS_VALUE_DARKKHAKI: + case LXB_CSS_VALUE_DARKMAGENTA: + case LXB_CSS_VALUE_DARKOLIVEGREEN: + case LXB_CSS_VALUE_DARKORANGE: + case LXB_CSS_VALUE_DARKORCHID: + case LXB_CSS_VALUE_DARKRED: + case LXB_CSS_VALUE_DARKSALMON: + case LXB_CSS_VALUE_DARKSEAGREEN: + case LXB_CSS_VALUE_DARKSLATEBLUE: + case LXB_CSS_VALUE_DARKSLATEGRAY: + case LXB_CSS_VALUE_DARKSLATEGREY: + case LXB_CSS_VALUE_DARKTURQUOISE: + case LXB_CSS_VALUE_DARKVIOLET: + case LXB_CSS_VALUE_DEEPPINK: + case LXB_CSS_VALUE_DEEPSKYBLUE: + case LXB_CSS_VALUE_DIMGRAY: + case LXB_CSS_VALUE_DIMGREY: + case LXB_CSS_VALUE_DODGERBLUE: + case LXB_CSS_VALUE_FIREBRICK: + case LXB_CSS_VALUE_FLORALWHITE: + case LXB_CSS_VALUE_FORESTGREEN: + case LXB_CSS_VALUE_FUCHSIA: + case LXB_CSS_VALUE_GAINSBORO: + case LXB_CSS_VALUE_GHOSTWHITE: + case LXB_CSS_VALUE_GOLD: + case LXB_CSS_VALUE_GOLDENROD: + case LXB_CSS_VALUE_GRAY: + case LXB_CSS_VALUE_GREEN: + case LXB_CSS_VALUE_GREENYELLOW: + case LXB_CSS_VALUE_GREY: + case LXB_CSS_VALUE_HONEYDEW: + case LXB_CSS_VALUE_HOTPINK: + case LXB_CSS_VALUE_INDIANRED: + case LXB_CSS_VALUE_INDIGO: + case LXB_CSS_VALUE_IVORY: + case LXB_CSS_VALUE_KHAKI: + case LXB_CSS_VALUE_LAVENDER: + case LXB_CSS_VALUE_LAVENDERBLUSH: + case LXB_CSS_VALUE_LAWNGREEN: + case LXB_CSS_VALUE_LEMONCHIFFON: + case LXB_CSS_VALUE_LIGHTBLUE: + case LXB_CSS_VALUE_LIGHTCORAL: + case LXB_CSS_VALUE_LIGHTCYAN: + case LXB_CSS_VALUE_LIGHTGOLDENRODYELLOW: + case LXB_CSS_VALUE_LIGHTGRAY: + case LXB_CSS_VALUE_LIGHTGREEN: + case LXB_CSS_VALUE_LIGHTGREY: + case LXB_CSS_VALUE_LIGHTPINK: + case LXB_CSS_VALUE_LIGHTSALMON: + case LXB_CSS_VALUE_LIGHTSEAGREEN: + case LXB_CSS_VALUE_LIGHTSKYBLUE: + case LXB_CSS_VALUE_LIGHTSLATEGRAY: + case LXB_CSS_VALUE_LIGHTSLATEGREY: + case LXB_CSS_VALUE_LIGHTSTEELBLUE: + case LXB_CSS_VALUE_LIGHTYELLOW: + case LXB_CSS_VALUE_LIME: + case LXB_CSS_VALUE_LIMEGREEN: + case LXB_CSS_VALUE_LINEN: + case LXB_CSS_VALUE_MAGENTA: + case LXB_CSS_VALUE_MAROON: + case LXB_CSS_VALUE_MEDIUMAQUAMARINE: + case LXB_CSS_VALUE_MEDIUMBLUE: + case LXB_CSS_VALUE_MEDIUMORCHID: + case LXB_CSS_VALUE_MEDIUMPURPLE: + case LXB_CSS_VALUE_MEDIUMSEAGREEN: + case LXB_CSS_VALUE_MEDIUMSLATEBLUE: + case LXB_CSS_VALUE_MEDIUMSPRINGGREEN: + case LXB_CSS_VALUE_MEDIUMTURQUOISE: + case LXB_CSS_VALUE_MEDIUMVIOLETRED: + case LXB_CSS_VALUE_MIDNIGHTBLUE: + case LXB_CSS_VALUE_MINTCREAM: + case LXB_CSS_VALUE_MISTYROSE: + case LXB_CSS_VALUE_MOCCASIN: + case LXB_CSS_VALUE_NAVAJOWHITE: + case LXB_CSS_VALUE_NAVY: + case LXB_CSS_VALUE_OLDLACE: + case LXB_CSS_VALUE_OLIVE: + case LXB_CSS_VALUE_OLIVEDRAB: + case LXB_CSS_VALUE_ORANGE: + case LXB_CSS_VALUE_ORANGERED: + case LXB_CSS_VALUE_ORCHID: + case LXB_CSS_VALUE_PALEGOLDENROD: + case LXB_CSS_VALUE_PALEGREEN: + case LXB_CSS_VALUE_PALETURQUOISE: + case LXB_CSS_VALUE_PALEVIOLETRED: + case LXB_CSS_VALUE_PAPAYAWHIP: + case LXB_CSS_VALUE_PEACHPUFF: + case LXB_CSS_VALUE_PERU: + case LXB_CSS_VALUE_PINK: + case LXB_CSS_VALUE_PLUM: + case LXB_CSS_VALUE_POWDERBLUE: + case LXB_CSS_VALUE_PURPLE: + case LXB_CSS_VALUE_REBECCAPURPLE: + case LXB_CSS_VALUE_RED: + case LXB_CSS_VALUE_ROSYBROWN: + case LXB_CSS_VALUE_ROYALBLUE: + case LXB_CSS_VALUE_SADDLEBROWN: + case LXB_CSS_VALUE_SALMON: + case LXB_CSS_VALUE_SANDYBROWN: + case LXB_CSS_VALUE_SEAGREEN: + case LXB_CSS_VALUE_SEASHELL: + case LXB_CSS_VALUE_SIENNA: + case LXB_CSS_VALUE_SILVER: + case LXB_CSS_VALUE_SKYBLUE: + case LXB_CSS_VALUE_SLATEBLUE: + case LXB_CSS_VALUE_SLATEGRAY: + case LXB_CSS_VALUE_SLATEGREY: + case LXB_CSS_VALUE_SNOW: + case LXB_CSS_VALUE_SPRINGGREEN: + case LXB_CSS_VALUE_STEELBLUE: + case LXB_CSS_VALUE_TAN: + case LXB_CSS_VALUE_TEAL: + case LXB_CSS_VALUE_THISTLE: + case LXB_CSS_VALUE_TOMATO: + case LXB_CSS_VALUE_TURQUOISE: + case LXB_CSS_VALUE_VIOLET: + case LXB_CSS_VALUE_WHEAT: + case LXB_CSS_VALUE_WHITE: + case LXB_CSS_VALUE_WHITESMOKE: + case LXB_CSS_VALUE_YELLOW: + case LXB_CSS_VALUE_YELLOWGREEN: + color->type = type; + break; + + default: + return false; + } + + break; + + default: + return false; + } + + lxb_css_syntax_parser_consume(parser); + + return true; +} + +bool +lxb_css_property_state__undef(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_failed(parser); +} + +bool +lxb_css_property_state__custom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_status_t status; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property__custom_t *custom = declar->u.custom; + + (void) lexbor_str_init(&custom->value, parser->memory->mraw, 0); + if (custom->value.data == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + status = lxb_css_syntax_token_serialize_str(token, &custom->value, + parser->memory->mraw); + if (status != LXB_STATUS_OK) { + return lxb_css_parser_memory_fail(parser); + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_display(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_property_display_t *display; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + display = declar->u.display; + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + + switch (type) { + /* */ + case LXB_CSS_DISPLAY_BLOCK: + case LXB_CSS_DISPLAY_INLINE: + case LXB_CSS_DISPLAY_RUN_IN: + display->a = type; + goto inside_listitem; + + /* */ + case LXB_CSS_DISPLAY_FLOW: + case LXB_CSS_DISPLAY_FLOW_ROOT: + display->a = type; + goto outside_listitem; + + case LXB_CSS_DISPLAY_TABLE: + case LXB_CSS_DISPLAY_FLEX: + case LXB_CSS_DISPLAY_GRID: + case LXB_CSS_DISPLAY_RUBY: + display->a = type; + goto outside; + + /* */ + case LXB_CSS_DISPLAY_LIST_ITEM: + display->a = type; + goto listitem_only; + + /* */ + case LXB_CSS_DISPLAY_TABLE_ROW_GROUP: + case LXB_CSS_DISPLAY_TABLE_HEADER_GROUP: + case LXB_CSS_DISPLAY_TABLE_FOOTER_GROUP: + case LXB_CSS_DISPLAY_TABLE_ROW: + case LXB_CSS_DISPLAY_TABLE_CELL: + case LXB_CSS_DISPLAY_TABLE_COLUMN_GROUP: + case LXB_CSS_DISPLAY_TABLE_COLUMN: + case LXB_CSS_DISPLAY_TABLE_CAPTION: + case LXB_CSS_DISPLAY_RUBY_BASE: + case LXB_CSS_DISPLAY_RUBY_TEXT: + case LXB_CSS_DISPLAY_RUBY_BASE_CONTAINER: + case LXB_CSS_DISPLAY_RUBY_TEXT_CONTAINER: + /* */ + case LXB_CSS_DISPLAY_CONTENTS: + case LXB_CSS_DISPLAY_NONE: + /* */ + case LXB_CSS_DISPLAY_INLINE_BLOCK: + case LXB_CSS_DISPLAY_INLINE_TABLE: + case LXB_CSS_DISPLAY_INLINE_FLEX: + case LXB_CSS_DISPLAY_INLINE_GRID: + display->a = type; + goto done; + + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + display->a = type; + goto done; + + default: + return lxb_css_parser_failed(parser); + } + +inside_listitem: + + lxb_css_property_state_get_type(parser, token, type); + + switch (type) { + /* */ + case LXB_CSS_DISPLAY_FLOW: + case LXB_CSS_DISPLAY_FLOW_ROOT: + display->b = type; + break; + + case LXB_CSS_DISPLAY_TABLE: + case LXB_CSS_DISPLAY_FLEX: + case LXB_CSS_DISPLAY_GRID: + case LXB_CSS_DISPLAY_RUBY: + display->b = type; + goto done; + + case LXB_CSS_DISPLAY_LIST_ITEM: + display->b = type; + goto flow_only; + + default: + return lxb_css_parser_failed(parser); + } + +listitem: + + lxb_css_property_state_get_type(parser, token, type); + + if (type == LXB_CSS_DISPLAY_LIST_ITEM) { + display->c = type; + goto done; + } + + return lxb_css_parser_failed(parser); + +outside: + + lxb_css_property_state_get_type(parser, token, type); + + switch (type) { + /* */ + case LXB_CSS_DISPLAY_BLOCK: + case LXB_CSS_DISPLAY_INLINE: + case LXB_CSS_DISPLAY_RUN_IN: + if (display->b == LXB_CSS_PROPERTY__UNDEF) { + display->b = type; + } + else { + display->c = type; + } + + goto done; + + default: + return lxb_css_parser_failed(parser); + } + +outside_listitem: + + lxb_css_property_state_get_type(parser, token, type); + + switch (type) { + /* */ + case LXB_CSS_DISPLAY_BLOCK: + case LXB_CSS_DISPLAY_INLINE: + case LXB_CSS_DISPLAY_RUN_IN: + display->b = type; + goto listitem; + + case LXB_CSS_DISPLAY_LIST_ITEM: + display->b = type; + goto outside; + + default: + return lxb_css_parser_failed(parser); + } + +listitem_only: + + lxb_css_property_state_get_type(parser, token, type); + + switch (type) { + /* */ + case LXB_CSS_DISPLAY_BLOCK: + case LXB_CSS_DISPLAY_INLINE: + case LXB_CSS_DISPLAY_RUN_IN: + display->b = type; + break; + + /* */ + case LXB_CSS_DISPLAY_FLOW: + case LXB_CSS_DISPLAY_FLOW_ROOT: + display->b = type; + goto outside; + + default: + return lxb_css_parser_failed(parser); + } + +flow_only: + + lxb_css_property_state_get_type(parser, token, type); + + switch (type) { + /* */ + case LXB_CSS_DISPLAY_FLOW: + case LXB_CSS_DISPLAY_FLOW_ROOT: + display->c = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + +done: + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_order(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + res = lxb_css_property_state_integer(parser, token, + &declar->u.order->integer); + if (res) { + declar->u.order->type = LXB_CSS_ORDER__INTEGER; + + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + declar->u.order->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_visibility(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_VISIBILITY_VISIBLE: + case LXB_CSS_VISIBILITY_HIDDEN: + case LXB_CSS_VISIBILITY_COLLAPSE: + declar->u.visibility->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_width(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + case LXB_CSS_VALUE_AUTO: + case LXB_CSS_VALUE_MIN_CONTENT: + case LXB_CSS_VALUE_MAX_CONTENT: + declar->u.width->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + } + + if (!lxb_css_property_state_length_percentage(parser, token, + declar->u.user)) + { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_width(parser, token, ctx); +} + +bool +lxb_css_property_state_box_sizing(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + case LXB_CSS_VALUE_CONTENT_BOX: + case LXB_CSS_VALUE_BORDER_BOX: + declar->u.box_sizing->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_min_width(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_width(parser, token, ctx); +} + +bool +lxb_css_property_state_min_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_width(parser, token, ctx); +} + +bool +lxb_css_property_state_max_width(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + case LXB_CSS_VALUE_NONE: + case LXB_CSS_VALUE_MIN_CONTENT: + case LXB_CSS_VALUE_MAX_CONTENT: + declar->u.width->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + } + + if (!lxb_css_property_state_length_percentage(parser, token, + declar->u.user)) + { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_max_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_max_width(parser, token, ctx); +} + +static bool +lxb_css_property_state_mp(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_rule_declaration_t *declar, bool with_auto) +{ + unsigned int state; + lxb_css_value_type_t type; + lxb_css_property_margin_top_t *top; + + state = 1; + +next: + + switch (state) { + case 1: + top = &declar->u.margin->top; + break; + + case 2: + top = &declar->u.margin->right; + break; + + case 3: + top = &declar->u.margin->bottom; + break; + + case 4: + top = &declar->u.margin->left; + break; + + default: + return lxb_css_parser_failed(parser); + } + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + top->type = type; + break; + + case LXB_CSS_VALUE_AUTO: + if (with_auto) { + top->type = type; + break; + } + + /* Fall through. */ + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + } + else if (!lxb_css_property_state_length_percentage(parser, token, + (lxb_css_value_length_percentage_t *) top)) + { + return lxb_css_parser_failed(parser); + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN__END) { + return lxb_css_parser_success(parser); + } + + state++; + + goto next; +} + +static bool +lxb_css_property_state_mp_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_rule_declaration_t *declar, bool with_auto) +{ + lxb_css_value_type_t type; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + declar->u.margin_top->type = type; + break; + + case LXB_CSS_VALUE_AUTO: + if (with_auto) { + declar->u.margin_top->type = type; + break; + } + + /* Fall through. */ + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + } + + if (!lxb_css_property_state_length_percentage(parser, token, + declar->u.user)) + { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_margin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp(parser, token, ctx, true); +} + +bool +lxb_css_property_state_margin_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, true); +} + +bool +lxb_css_property_state_margin_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, true); +} + +bool +lxb_css_property_state_margin_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, true); +} + +bool +lxb_css_property_state_margin_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, true); +} + +bool +lxb_css_property_state_padding(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp(parser, token, ctx, false); +} + +bool +lxb_css_property_state_padding_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, false); +} + +bool +lxb_css_property_state_padding_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, false); +} + +bool +lxb_css_property_state_padding_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, false); +} + +bool +lxb_css_property_state_padding_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, false); +} + +static bool +lxb_css_property_state_line_width_style_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_border_t *border) +{ + lxb_status_t status; + lxb_css_value_type_t type; + const lxb_css_data_t *unit; + lxb_css_value_length_t *length; + lxb_css_syntax_token_string_t *str; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + if (border->width.type != LXB_CSS_VALUE__UNDEF) { + return false; + } + + str = &lxb_css_syntax_token_dimension(token)->str; + + unit = lxb_css_unit_absolute_relative_by_name(str->data, + str->length); + if (unit == NULL) { + return false; + } + + length = &border->width.length; + + border->width.type = LXB_CSS_VALUE__LENGTH; + length->num = lxb_css_syntax_token_dimension(token)->num.num; + length->is_float = lxb_css_syntax_token_dimension(token)->num.is_float; + length->unit = (lxb_css_unit_t) unit->unique; + break; + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + if (border->width.type != LXB_CSS_VALUE__UNDEF) { + return false; + } + + length = &border->width.length; + + border->width.type = LXB_CSS_VALUE__NUMBER; + length->num = lxb_css_syntax_token_number(token)->num; + length->is_float = lxb_css_syntax_token_number(token)->is_float; + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_THIN: + case LXB_CSS_VALUE_MEDIUM: + case LXB_CSS_VALUE_THICK: + if (border->width.type != LXB_CSS_VALUE__UNDEF) { + return false; + } + + border->width.type = type; + break; + + case LXB_CSS_VALUE_NONE: + case LXB_CSS_VALUE_HIDDEN: + case LXB_CSS_VALUE_DOTTED: + case LXB_CSS_VALUE_DASHED: + case LXB_CSS_VALUE_SOLID: + case LXB_CSS_VALUE_DOUBLE: + case LXB_CSS_VALUE_GROOVE: + case LXB_CSS_VALUE_RIDGE: + case LXB_CSS_VALUE_INSET: + case LXB_CSS_VALUE_OUTSET: + if (border->style != LXB_CSS_VALUE__UNDEF) { + return false; + } + + border->style = type; + break; + + default: + goto color; + } + + break; + + default: + goto color; + } + + lxb_css_syntax_parser_consume(parser); + + return true; + +color: + + if (border->color.type != LXB_CSS_VALUE__UNDEF) { + return false; + } + + return lxb_css_property_state_color_handler(parser, token, &border->color, + &status); +} + +bool +lxb_css_property_state_border(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + declar->u.border->style = type; + + lxb_css_syntax_parser_consume(parser); + return lxb_css_parser_success(parser); + + default: + break; + } + } + + res = lxb_css_property_state_line_width_style_color(parser, token, + declar->u.border); + if (!res) { + return lxb_css_parser_failed(parser); + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN__END) { + return lxb_css_parser_success(parser); + } + + res = lxb_css_property_state_line_width_style_color(parser, token, + declar->u.border); + if (!res) { + return lxb_css_parser_failed(parser); + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN__END) { + return lxb_css_parser_success(parser); + } + + res = lxb_css_property_state_line_width_style_color(parser, token, + declar->u.border); + if (!res) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_border_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_border(parser, token, ctx); +} + +bool +lxb_css_property_state_border_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_border(parser, token, ctx); +} + +bool +lxb_css_property_state_border_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_border(parser, token, ctx); +} + +bool +lxb_css_property_state_border_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_border(parser, token, ctx); +} + +bool +lxb_css_property_state_border_top_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_color(parser, token, ctx); +} + +bool +lxb_css_property_state_border_right_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_color(parser, token, ctx); +} + +bool +lxb_css_property_state_border_bottom_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_color(parser, token, ctx); +} + +bool +lxb_css_property_state_border_left_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_color(parser, token, ctx); +} + +bool +lxb_css_property_state_background_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_color(parser, token, ctx); +} + +bool +lxb_css_property_state_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_status_t status; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + declar->u.color->type = type; + + lxb_css_syntax_parser_consume(parser); + return lxb_css_parser_success(parser); + + default: + break; + } + } + + res = lxb_css_property_state_color_handler(parser, token, + (lxb_css_value_color_t *) declar->u.color, + &status); + if (!res) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_opacity(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_opacity_t *opacity = declar->u.opacity; + + res = lxb_css_property_state_number_percentage(parser, token, + (lxb_css_value_number_percentage_t *) opacity); + if (res) { + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + opacity->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_position(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_POSITION_STATIC: + case LXB_CSS_POSITION_RELATIVE: + case LXB_CSS_POSITION_ABSOLUTE: + case LXB_CSS_POSITION_STICKY: + case LXB_CSS_POSITION_FIXED: + declar->u.position->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_mp_top(parser, token, ctx, true); +} + +bool +lxb_css_property_state_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_inset_block_start(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_inset_inline_start(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_inset_block_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_inset_inline_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_top(parser, token, ctx); +} + +bool +lxb_css_property_state_text_transform(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_text_transform_t *tt; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + tt = declar->u.text_transform; + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_TRANSFORM_NONE: + tt->type_case = type; + break; + + case LXB_CSS_TEXT_TRANSFORM_CAPITALIZE: + case LXB_CSS_TEXT_TRANSFORM_UPPERCASE: + case LXB_CSS_TEXT_TRANSFORM_LOWERCASE: + tt->type_case = type; + goto next; + + case LXB_CSS_TEXT_TRANSFORM_FULL_WIDTH: + tt->full_width = type; + goto next; + + case LXB_CSS_TEXT_TRANSFORM_FULL_SIZE_KANA: + tt->full_size_kana = type; + goto next; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + +next: + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_success(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + + switch (type) { + case LXB_CSS_TEXT_TRANSFORM_CAPITALIZE: + case LXB_CSS_TEXT_TRANSFORM_UPPERCASE: + case LXB_CSS_TEXT_TRANSFORM_LOWERCASE: + if (tt->type_case != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + tt->type_case = type; + goto next; + + case LXB_CSS_TEXT_TRANSFORM_FULL_WIDTH: + if (tt->full_width != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + tt->full_width = type; + goto next; + + case LXB_CSS_TEXT_TRANSFORM_FULL_SIZE_KANA: + if (tt->full_size_kana != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + tt->full_size_kana = type; + goto next; + + default: + return lxb_css_parser_failed(parser); + } +} + +bool +lxb_css_property_state_text_align(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_ALIGN_START: + case LXB_CSS_TEXT_ALIGN_END: + case LXB_CSS_TEXT_ALIGN_LEFT: + case LXB_CSS_TEXT_ALIGN_RIGHT: + case LXB_CSS_TEXT_ALIGN_CENTER: + case LXB_CSS_TEXT_ALIGN_JUSTIFY: + case LXB_CSS_TEXT_ALIGN_MATCH_PARENT: + case LXB_CSS_TEXT_ALIGN_JUSTIFY_ALL: + declar->u.text_align->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_align_all(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_ALIGN_ALL_START: + case LXB_CSS_TEXT_ALIGN_ALL_END: + case LXB_CSS_TEXT_ALIGN_ALL_LEFT: + case LXB_CSS_TEXT_ALIGN_ALL_RIGHT: + case LXB_CSS_TEXT_ALIGN_ALL_CENTER: + case LXB_CSS_TEXT_ALIGN_ALL_JUSTIFY: + case LXB_CSS_TEXT_ALIGN_ALL_MATCH_PARENT: + declar->u.text_align_all->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_align_last(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_ALIGN_LAST_AUTO: + case LXB_CSS_TEXT_ALIGN_LAST_START: + case LXB_CSS_TEXT_ALIGN_LAST_END: + case LXB_CSS_TEXT_ALIGN_LAST_LEFT: + case LXB_CSS_TEXT_ALIGN_LAST_RIGHT: + case LXB_CSS_TEXT_ALIGN_LAST_CENTER: + case LXB_CSS_TEXT_ALIGN_LAST_JUSTIFY: + case LXB_CSS_TEXT_ALIGN_LAST_MATCH_PARENT: + declar->u.text_align_last->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_justify(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_JUSTIFY_AUTO: + case LXB_CSS_TEXT_JUSTIFY_NONE: + case LXB_CSS_TEXT_JUSTIFY_INTER_WORD: + case LXB_CSS_TEXT_JUSTIFY_INTER_CHARACTER: + declar->u.text_justify->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_indent(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_text_indent_t *text_indent; + + text_indent = declar->u.text_indent; + + res = lxb_css_property_state_length_percentage(parser, token, + &text_indent->length); + if (res) { + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + text_indent->type = LXB_CSS_VALUE__LENGTH; + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + if (!res) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + if (res) { + return lxb_css_parser_failed(parser); + } + + text_indent->type = type; + break; + + /* Local. */ + case LXB_CSS_TEXT_INDENT_HANGING: + text_indent->hanging = type; + goto next; + + case LXB_CSS_TEXT_INDENT_EACH_LINE: + text_indent->each_line = type; + goto next; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + +next: + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_length_percentage(parser, token, + &text_indent->length); + if (res) { + if (text_indent->type != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + text_indent->type = LXB_CSS_VALUE__LENGTH; + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + if (text_indent->type == LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + + switch (type) { + case LXB_CSS_TEXT_INDENT_HANGING: + if (text_indent->hanging != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + text_indent->hanging = type; + goto next; + + case LXB_CSS_TEXT_INDENT_EACH_LINE: + if (text_indent->each_line != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + text_indent->each_line = type; + goto next; + + default: + return lxb_css_parser_failed(parser); + } +} + +bool +lxb_css_property_state_white_space(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_WHITE_SPACE_NORMAL: + case LXB_CSS_WHITE_SPACE_PRE: + case LXB_CSS_WHITE_SPACE_NOWRAP: + case LXB_CSS_WHITE_SPACE_PRE_WRAP: + case LXB_CSS_WHITE_SPACE_BREAK_SPACES: + case LXB_CSS_WHITE_SPACE_PRE_LINE: + declar->u.white_space->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_tab_size(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + res = lxb_css_property_state_number_length(parser, token, + (lxb_css_value_number_length_t *) declar->u.tab_size); + if (res) { + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + declar->u.tab_size->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_word_break(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_WORD_BREAK_NORMAL: + case LXB_CSS_WORD_BREAK_KEEP_ALL: + case LXB_CSS_WORD_BREAK_BREAK_ALL: + case LXB_CSS_WORD_BREAK_BREAK_WORD: + declar->u.word_break->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_line_break(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_LINE_BREAK_AUTO: + case LXB_CSS_LINE_BREAK_LOOSE: + case LXB_CSS_LINE_BREAK_NORMAL: + case LXB_CSS_LINE_BREAK_STRICT: + case LXB_CSS_LINE_BREAK_ANYWHERE: + declar->u.line_break->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_hyphens(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_HYPHENS_NONE: + case LXB_CSS_HYPHENS_MANUAL: + case LXB_CSS_HYPHENS_AUTO: + declar->u.hyphens->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_overflow_wrap(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_OVERFLOW_WRAP_NORMAL: + case LXB_CSS_OVERFLOW_WRAP_BREAK_WORD: + case LXB_CSS_OVERFLOW_WRAP_ANYWHERE: + declar->u.overflow_wrap->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_word_wrap(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_overflow_wrap(parser, token, ctx); +} + +bool +lxb_css_property_state_word_spacing(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + res = lxb_css_property_state_length(parser, token, + &declar->u.word_spacing->length); + if (res) { + declar->u.word_spacing->type = LXB_CSS_VALUE__LENGTH; + + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_WORD_SPACING_NORMAL: + declar->u.word_spacing->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_letter_spacing(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_word_spacing(parser, token, ctx); +} + +bool +lxb_css_property_state_hanging_punctuation(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_hanging_punctuation_t *hp; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + hp = declar->u.hanging_punctuation; + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_HANGING_PUNCTUATION_NONE: + hp->type_first = type; + break; + + case LXB_CSS_HANGING_PUNCTUATION_FIRST: + hp->type_first = type; + goto next; + + case LXB_CSS_HANGING_PUNCTUATION_FORCE_END: + case LXB_CSS_HANGING_PUNCTUATION_ALLOW_END: + hp->force_allow = type; + goto next; + + case LXB_CSS_HANGING_PUNCTUATION_LAST: + hp->last = type; + goto next; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + +next: + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_success(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + + switch (type) { + case LXB_CSS_HANGING_PUNCTUATION_FIRST: + if (hp->type_first != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + hp->type_first = type; + goto next; + + case LXB_CSS_HANGING_PUNCTUATION_FORCE_END: + case LXB_CSS_HANGING_PUNCTUATION_ALLOW_END: + if (hp->force_allow != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + hp->force_allow = type; + goto next; + + case LXB_CSS_HANGING_PUNCTUATION_LAST: + if (hp->last != LXB_CSS_VALUE__UNDEF) { + return lxb_css_parser_failed(parser); + } + + hp->last = type; + goto next; + + default: + return lxb_css_parser_failed(parser); + } +} + +bool +lxb_css_property_state_font_family(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + size_t length; + const lxb_char_t *data; + lexbor_str_t *str; + lexbor_mraw_t *mraw; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_font_family_t *ff; + lxb_css_property_family_name_t *name; + + mraw = parser->memory->mraw; + ff = declar->u.font_family; + + while (token != NULL) { + name = lexbor_mraw_alloc(mraw, sizeof(lxb_css_property_family_name_t)); + if (name == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + data = lxb_css_syntax_token_ident(token)->data; + length = lxb_css_syntax_token_ident(token)->length; + + type = lxb_css_value_by_name(data, length); + if (type != LXB_CSS_VALUE__UNDEF) { + name->generic = true; + name->u.type = type; + + goto next; + } + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_STRING) { + data = lxb_css_syntax_token_string(token)->data; + length = lxb_css_syntax_token_string(token)->length; + } + else { + return lxb_css_parser_failed(parser); + } + + name->generic = false; + + str = &name->u.str; + + (void) lexbor_str_init(str, mraw, length); + if (name->u.str.data == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + memcpy(str->data, data, length); + + str->data[length] = '\0'; + str->length = length; + + next: + + if (ff->first == NULL) { + ff->first = name; + } + else { + ff->last->next = name; + } + + name->next = NULL; + name->prev = ff->last; + ff->last = name; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + if (token->type == LXB_CSS_SYNTAX_TOKEN__END) { + return lxb_css_parser_success(parser); + } + + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + } + + lxb_css_property_state_check_token(parser, token); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_font_weight(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx)\ +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_font_weight_t *fw = declar->u.font_weight; + + res = lxb_css_property_state_number(parser, token, &fw->number); + + if (res) { + if (fw->number.num < 1 || fw->number.num > 1000) { + return lxb_css_parser_failed(parser); + } + + fw->type = LXB_CSS_FONT_WEIGHT__NUMBER; + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FONT_WEIGHT_NORMAL: + case LXB_CSS_FONT_WEIGHT_BOLD: + case LXB_CSS_FONT_WEIGHT_BOLDER: + case LXB_CSS_FONT_WEIGHT_LIGHTER: + fw->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_font_stretch(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_font_stretch_t *fs = declar->u.font_stretch; + + res = lxb_css_property_state_percentage(parser, token, &fs->percentage); + + if (res) { + if (fs->percentage.num < 0) { + return lxb_css_parser_failed(parser); + } + + fs->type = LXB_CSS_FONT_STRETCH__PERCENTAGE; + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FONT_STRETCH_NORMAL: + case LXB_CSS_FONT_STRETCH_ULTRA_CONDENSED: + case LXB_CSS_FONT_STRETCH_EXTRA_CONDENSED: + case LXB_CSS_FONT_STRETCH_CONDENSED: + case LXB_CSS_FONT_STRETCH_SEMI_CONDENSED: + case LXB_CSS_FONT_STRETCH_SEMI_EXPANDED: + case LXB_CSS_FONT_STRETCH_EXPANDED: + case LXB_CSS_FONT_STRETCH_EXTRA_EXPANDED: + case LXB_CSS_FONT_STRETCH_ULTRA_EXPANDED: + fs->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_font_style(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_font_style_t *fs = declar->u.font_style; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FONT_STYLE_NORMAL: + case LXB_CSS_FONT_STYLE_ITALIC: + fs->type = type; + break; + + case LXB_CSS_FONT_STYLE_OBLIQUE: + fs->type = type; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_angle(parser, token, &fs->angle); + + if (res) { + if (fs->angle.num < -90 || fs->angle.num > 90) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); + } + else { + fs->angle.unit = (lxb_css_unit_angle_t) LXB_CSS_UNIT__UNDEF; + } + + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_font_size(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_font_size_t *fs = declar->u.font_size; + + res = lxb_css_property_state_length_percentage(parser, token, &fs->length); + + if (res) { + if (fs->length.u.length.num < 0) { + return lxb_css_parser_failed(parser); + } + + fs->type = LXB_CSS_FONT_SIZE__LENGTH; + + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FONT_SIZE_XX_SMALL: + case LXB_CSS_FONT_SIZE_X_SMALL: + case LXB_CSS_FONT_SIZE_SMALL: + case LXB_CSS_FONT_SIZE_MEDIUM: + case LXB_CSS_FONT_SIZE_LARGE: + case LXB_CSS_FONT_SIZE_X_LARGE: + case LXB_CSS_FONT_SIZE_XX_LARGE: + case LXB_CSS_FONT_SIZE_XXX_LARGE: + case LXB_CSS_FONT_SIZE_MATH: + case LXB_CSS_FONT_SIZE_LARGER: + case LXB_CSS_FONT_SIZE_SMALLER: + fs->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_float_reference(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLOAT_REFERENCE_INLINE: + case LXB_CSS_FLOAT_REFERENCE_COLUMN: + case LXB_CSS_FLOAT_REFERENCE_REGION: + case LXB_CSS_FLOAT_REFERENCE_PAGE: + declar->u.float_reference->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_float(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_float_t *fp = declar->u.floatp; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + if (token->type == LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + goto snap; + } + + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLOAT_BLOCK_START: + case LXB_CSS_FLOAT_BLOCK_END: + case LXB_CSS_FLOAT_INLINE_START: + case LXB_CSS_FLOAT_INLINE_END: + case LXB_CSS_FLOAT_SNAP_BLOCK: + case LXB_CSS_FLOAT_SNAP_INLINE: + case LXB_CSS_FLOAT_LEFT: + case LXB_CSS_FLOAT_RIGHT: + case LXB_CSS_FLOAT_TOP: + case LXB_CSS_FLOAT_BOTTOM: + case LXB_CSS_FLOAT_NONE: + fp->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + +snap: + + type = lxb_css_value_by_name(lxb_css_syntax_token_function(token)->data, + lxb_css_syntax_token_function(token)->length); + + if (type != LXB_CSS_FLOAT_SNAP_BLOCK + && type != LXB_CSS_FLOAT_SNAP_INLINE) + { + return lxb_css_parser_failed(parser); + } + + fp->type = type; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_length(parser, token, &fp->length.length); + if (!res) { + return lxb_css_parser_failed(parser); + } + + fp->length.type = LXB_CSS_VALUE__LENGTH; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + fp->snap_type = LXB_CSS_VALUE__UNDEF; + + lxb_css_syntax_parser_consume(parser); + return lxb_css_parser_success(parser); + } + + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_FLOAT_START: + case LXB_CSS_FLOAT_END: + if (fp->type != LXB_CSS_FLOAT_SNAP_BLOCK) { + return lxb_css_parser_failed(parser); + } + + fp->snap_type = type; + break; + + case LXB_CSS_FLOAT_LEFT: + case LXB_CSS_FLOAT_RIGHT: + if (fp->type != LXB_CSS_FLOAT_SNAP_INLINE) { + return lxb_css_parser_failed(parser); + } + + fp->snap_type = type; + break; + + case LXB_CSS_FLOAT_NEAR: + fp->snap_type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) { + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + } + + return lxb_css_parser_failed(parser); +} + +bool +lxb_css_property_state_clear(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_CLEAR_INLINE_START: + case LXB_CSS_CLEAR_INLINE_END: + case LXB_CSS_CLEAR_BLOCK_START: + case LXB_CSS_CLEAR_BLOCK_END: + case LXB_CSS_CLEAR_LEFT: + case LXB_CSS_CLEAR_RIGHT: + case LXB_CSS_CLEAR_TOP: + case LXB_CSS_CLEAR_BOTTOM: + case LXB_CSS_CLEAR_NONE: + declar->u.clear->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_float_defer(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_float_defer_t *fd = declar->u.float_defer; + + res = lxb_css_property_state_integer(parser, token, &fd->integer); + if (res) { + fd->type = LXB_CSS_FLOAT_DEFER__INTEGER; + + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLOAT_DEFER_LAST: + case LXB_CSS_FLOAT_DEFER_NONE: + fd->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_float_offset(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_float_offset_t *fo = declar->u.float_offset; + + res = lxb_css_property_state_length_percentage(parser, token, + (lxb_css_value_length_percentage_t *) fo); + if (res) { + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + fo->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_wrap_flow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_WRAP_FLOW_AUTO: + case LXB_CSS_WRAP_FLOW_BOTH: + case LXB_CSS_WRAP_FLOW_START: + case LXB_CSS_WRAP_FLOW_END: + case LXB_CSS_WRAP_FLOW_MINIMUM: + case LXB_CSS_WRAP_FLOW_MAXIMUM: + case LXB_CSS_WRAP_FLOW_CLEAR: + declar->u.wrap_flow->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_wrap_through(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_WRAP_THROUGH_WRAP: + case LXB_CSS_WRAP_THROUGH_NONE: + declar->u.wrap_through->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_flex_direction(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLEX_DIRECTION_ROW: + case LXB_CSS_FLEX_DIRECTION_ROW_REVERSE: + case LXB_CSS_FLEX_DIRECTION_COLUMN: + case LXB_CSS_FLEX_DIRECTION_COLUMN_REVERSE: + declar->u.flex_direction->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_flex_wrap(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLEX_WRAP_NOWRAP: + case LXB_CSS_FLEX_WRAP_WRAP: + case LXB_CSS_FLEX_WRAP_WRAP_REVERSE: + declar->u.flex_wrap->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_flex_flow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_flex_flow_t *ff = declar->u.flex_flow; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLEX_DIRECTION_ROW: + case LXB_CSS_FLEX_DIRECTION_ROW_REVERSE: + case LXB_CSS_FLEX_DIRECTION_COLUMN: + case LXB_CSS_FLEX_DIRECTION_COLUMN_REVERSE: + ff->type_direction = type; + goto direction; + + case LXB_CSS_FLEX_WRAP_NOWRAP: + case LXB_CSS_FLEX_WRAP_WRAP: + case LXB_CSS_FLEX_WRAP_WRAP_REVERSE: + ff->wrap = type; + goto wrap; + + default: + return lxb_css_parser_failed(parser); + } + +direction: + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_success(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_FLEX_WRAP_NOWRAP: + case LXB_CSS_FLEX_WRAP_WRAP: + case LXB_CSS_FLEX_WRAP_WRAP_REVERSE: + ff->wrap = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + goto done; + +wrap: + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_success(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_FLEX_DIRECTION_ROW: + case LXB_CSS_FLEX_DIRECTION_ROW_REVERSE: + case LXB_CSS_FLEX_DIRECTION_COLUMN: + case LXB_CSS_FLEX_DIRECTION_COLUMN_REVERSE: + ff->type_direction = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + +done: + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +lxb_inline bool +lxb_css_property_state_flex_grow_shrink(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_flex_t *flex) +{ + bool res; + + res = lxb_css_property_state_number(parser, token, &flex->grow.number); + if (!res) { + return false; + } + + flex->grow.type = LXB_CSS_FLEX_GROW__NUMBER; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_number(parser, token, &flex->shrink.number); + if (res) { + flex->shrink.type = LXB_CSS_FLEX_SHRINK__NUMBER; + } + + return true; +} + +lxb_inline bool +lxb_css_property_state_flex_grow_basis(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_flex_t *flex) +{ + bool res; + lxb_css_value_type_t type; + + res = lxb_css_property_state_width_handler(parser, token, + (lxb_css_property_flex_basis_t *) &flex->basis); + if (res) { + return true; + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return false; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + + if (type == LXB_CSS_FLEX_BASIS_CONTENT) { + flex->basis.type = type; + + lxb_css_syntax_parser_consume(parser); + return true; + } + + return false; +} + +bool +lxb_css_property_state_flex(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_flex_t *flex = declar->u.flex; + + res = lxb_css_property_state_flex_grow_shrink(parser, token, flex); + + if (res) { + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_flex_grow_basis(parser, token, flex); + + if (!res && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + flex->basis.type = LXB_CSS_VALUE__NUMBER; + flex->basis.u.length.num = flex->grow.number.num; + flex->basis.u.length.unit = LXB_CSS_UNIT__UNDEF; + flex->basis.u.length.is_float = flex->grow.number.is_float; + + flex->grow.type = LXB_CSS_VALUE__UNDEF; + + if (flex->shrink.type != LXB_CSS_VALUE__UNDEF) { + flex->grow = flex->shrink; + flex->shrink.type = LXB_CSS_VALUE__UNDEF; + + goto try_shrink_last; + } + + res = lxb_css_property_state_flex_grow_shrink(parser, token, flex); + if (!res) { + return lxb_css_parser_failed(parser); + } + } + + return lxb_css_parser_success(parser); + } + else { + res = lxb_css_property_state_flex_grow_basis(parser, token, flex); + + if (res) { + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + (void) lxb_css_property_state_flex_grow_shrink(parser, token, flex); + + return lxb_css_parser_success(parser); + } + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_FLEX_NONE: + flex->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); + +try_shrink_last: + + res = lxb_css_property_state_number(parser, token, &flex->shrink.number); + if (res) { + flex->shrink.type = LXB_CSS_FLEX_SHRINK__NUMBER; + } + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_flex_grow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_flex_grow_t *fg = declar->u.flex_grow; + + res = lxb_css_property_state_number(parser, token, &fg->number); + if (res) { + if (fg->number.num < 0) { + return lxb_css_parser_failed(parser); + } + + fg->type = LXB_CSS_FLEX_GROW__NUMBER; + + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + fg->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_flex_shrink(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_flex_grow_t *fs = declar->u.flex_shrink; + + res = lxb_css_property_state_number(parser, token, &fs->number); + if (res) { + if (fs->number.num < 0) { + return lxb_css_parser_failed(parser); + } + + fs->type = LXB_CSS_FLEX_SHRINK__NUMBER; + + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + fs->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_flex_basis(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_flex_basis_t *fb = declar->u.flex_basis; + + res = lxb_css_property_state_width_handler(parser, token, + (lxb_css_property_width_t *) fb); + if (res) { + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + case LXB_CSS_FLEX_BASIS_CONTENT: + fb->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_justify_content(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_JUSTIFY_CONTENT_FLEX_START: + case LXB_CSS_JUSTIFY_CONTENT_FLEX_END: + case LXB_CSS_JUSTIFY_CONTENT_CENTER: + case LXB_CSS_JUSTIFY_CONTENT_SPACE_BETWEEN: + case LXB_CSS_JUSTIFY_CONTENT_SPACE_AROUND: + declar->u.justify_content->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_align_items(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_ALIGN_ITEMS_FLEX_START: + case LXB_CSS_ALIGN_ITEMS_FLEX_END: + case LXB_CSS_ALIGN_ITEMS_CENTER: + case LXB_CSS_ALIGN_ITEMS_BASELINE: + case LXB_CSS_ALIGN_ITEMS_STRETCH: + declar->u.align_items->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_align_self(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_ALIGN_SELF_AUTO: + case LXB_CSS_ALIGN_SELF_FLEX_START: + case LXB_CSS_ALIGN_SELF_FLEX_END: + case LXB_CSS_ALIGN_SELF_CENTER: + case LXB_CSS_ALIGN_SELF_BASELINE: + case LXB_CSS_ALIGN_SELF_STRETCH: + declar->u.align_self->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_align_content(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_ALIGN_CONTENT_FLEX_START: + case LXB_CSS_ALIGN_CONTENT_FLEX_END: + case LXB_CSS_ALIGN_CONTENT_CENTER: + case LXB_CSS_ALIGN_CONTENT_SPACE_BETWEEN: + case LXB_CSS_ALIGN_CONTENT_SPACE_AROUND: + case LXB_CSS_ALIGN_CONTENT_STRETCH: + declar->u.align_content->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_dominant_baseline(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_DOMINANT_BASELINE_AUTO: + case LXB_CSS_DOMINANT_BASELINE_TEXT_BOTTOM: + case LXB_CSS_DOMINANT_BASELINE_ALPHABETIC: + case LXB_CSS_DOMINANT_BASELINE_IDEOGRAPHIC: + case LXB_CSS_DOMINANT_BASELINE_MIDDLE: + case LXB_CSS_DOMINANT_BASELINE_CENTRAL: + case LXB_CSS_DOMINANT_BASELINE_MATHEMATICAL: + case LXB_CSS_DOMINANT_BASELINE_HANGING: + case LXB_CSS_DOMINANT_BASELINE_TEXT_TOP: + declar->u.dominant_baseline->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_alignment_baseline_h(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_alignment_baseline_t *ab) +{ + lxb_css_value_type_t type; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return false; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_ALIGNMENT_BASELINE_BASELINE: + case LXB_CSS_ALIGNMENT_BASELINE_TEXT_BOTTOM: + case LXB_CSS_ALIGNMENT_BASELINE_ALPHABETIC: + case LXB_CSS_ALIGNMENT_BASELINE_IDEOGRAPHIC: + case LXB_CSS_ALIGNMENT_BASELINE_MIDDLE: + case LXB_CSS_ALIGNMENT_BASELINE_CENTRAL: + case LXB_CSS_ALIGNMENT_BASELINE_MATHEMATICAL: + case LXB_CSS_ALIGNMENT_BASELINE_TEXT_TOP: + ab->type = type; + + lxb_css_syntax_parser_consume(parser); + return true; + + default: + return false; + } +} + +bool +lxb_css_property_state_baseline_shift_h(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_baseline_shift_t *bs) +{ + bool res; + lxb_css_value_type_t type; + + res = lxb_css_property_state_length_percentage(parser, token, bs); + + if (res) { + return true; + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return false; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_BASELINE_SHIFT_SUB: + case LXB_CSS_BASELINE_SHIFT_SUPER: + case LXB_CSS_BASELINE_SHIFT_TOP: + case LXB_CSS_BASELINE_SHIFT_CENTER: + case LXB_CSS_BASELINE_SHIFT_BOTTOM: + bs->type = type; + + lxb_css_syntax_parser_consume(parser); + return true; + + default: + return false; + } +} + +bool +lxb_css_property_state_vertical_align(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + uint8_t maps; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_vertical_align_t *va = declar->u.vertical_align; + + maps = 0; + +again: + + res = lxb_css_property_state_alignment_baseline_h(parser, token, + &va->alignment); + if (res) { + if (maps & 1 << 1) { + return lxb_css_parser_failed(parser); + } + + maps |= 1 << 1; + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_baseline_shift_h(parser, token, + &va->shift); + if (res) { + if (maps & 1 << 2) { + return lxb_css_parser_failed(parser); + } + + maps |= 1 << 2; + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + } + } + else { + res = lxb_css_property_state_baseline_shift_h(parser, token, + &va->shift); + if (res) { + if (maps & 1 << 2) { + return lxb_css_parser_failed(parser); + } + + maps |= 1 << 2; + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_alignment_baseline_h(parser, token, + &va->alignment); + if (res) { + if (maps & 1 << 1) { + return lxb_css_parser_failed(parser); + } + + maps |= 1 << 1; + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + } + } + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + if (maps != 0) { + return lxb_css_parser_success(parser); + } + + return lxb_css_parser_failed(parser); + } + + if (maps & 1 << 3) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_VERTICAL_ALIGN_FIRST: + case LXB_CSS_VERTICAL_ALIGN_LAST: + va->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + maps = 1 << 3; + + goto again; +} + +bool +lxb_css_property_state_baseline_source(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_BASELINE_SOURCE_AUTO: + case LXB_CSS_BASELINE_SOURCE_FIRST: + case LXB_CSS_BASELINE_SOURCE_LAST: + declar->u.baseline_source->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_alignment_baseline(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_ALIGNMENT_BASELINE_BASELINE: + case LXB_CSS_ALIGNMENT_BASELINE_TEXT_BOTTOM: + case LXB_CSS_ALIGNMENT_BASELINE_ALPHABETIC: + case LXB_CSS_ALIGNMENT_BASELINE_IDEOGRAPHIC: + case LXB_CSS_ALIGNMENT_BASELINE_MIDDLE: + case LXB_CSS_ALIGNMENT_BASELINE_CENTRAL: + case LXB_CSS_ALIGNMENT_BASELINE_MATHEMATICAL: + case LXB_CSS_ALIGNMENT_BASELINE_TEXT_TOP: + declar->u.alignment_baseline->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_baseline_shift(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + res = lxb_css_property_state_length_percentage(parser, token, + declar->u.baseline_shift); + if (res) { + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_BASELINE_SHIFT_SUB: + case LXB_CSS_BASELINE_SHIFT_SUPER: + case LXB_CSS_BASELINE_SHIFT_TOP: + case LXB_CSS_BASELINE_SHIFT_CENTER: + case LXB_CSS_BASELINE_SHIFT_BOTTOM: + declar->u.baseline_shift->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_line_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + res = lxb_css_property_state_number_length_percentage(parser, token, + declar->u.line_height); + if (res) { + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_LINE_HEIGHT_NORMAL: + declar->u.line_height->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_z_index(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + res = lxb_css_property_state_integer(parser, token, + &declar->u.z_index->integer); + if (res) { + declar->u.z_index->type = LXB_CSS_VALUE__INTEGER; + return lxb_css_parser_success(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_Z_INDEX_AUTO: + declar->u.line_height->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_direction(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_DIRECTION_LTR: + case LXB_CSS_DIRECTION_RTL: + declar->u.direction->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_unicode_bidi(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_UNICODE_BIDI_NORMAL: + case LXB_CSS_UNICODE_BIDI_EMBED: + case LXB_CSS_UNICODE_BIDI_ISOLATE: + case LXB_CSS_UNICODE_BIDI_BIDI_OVERRIDE: + case LXB_CSS_UNICODE_BIDI_ISOLATE_OVERRIDE: + case LXB_CSS_UNICODE_BIDI_PLAINTEXT: + declar->u.unicode_bidi->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_writing_mode(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_WRITING_MODE_HORIZONTAL_TB: + case LXB_CSS_WRITING_MODE_VERTICAL_RL: + case LXB_CSS_WRITING_MODE_VERTICAL_LR: + case LXB_CSS_WRITING_MODE_SIDEWAYS_RL: + case LXB_CSS_WRITING_MODE_SIDEWAYS_LR: + declar->u.writing_mode->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_orientation(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_ORIENTATION_MIXED: + case LXB_CSS_TEXT_ORIENTATION_UPRIGHT: + case LXB_CSS_TEXT_ORIENTATION_SIDEWAYS: + declar->u.text_orientation->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_combine_upright(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_text_combine_upright_t *tcu = declar->u.text_combine_upright; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_COMBINE_UPRIGHT_NONE: + case LXB_CSS_TEXT_COMBINE_UPRIGHT_ALL: + tcu->type = type; + break; + + case LXB_CSS_TEXT_COMBINE_UPRIGHT_DIGITS: + tcu->type = type; + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + res = lxb_css_property_state_integer(parser, token, + &tcu->digits); + if (res) { + if (tcu->digits.num != 2 && tcu->digits.num != 4) { + return lxb_css_parser_failed(parser); + } + } + + return lxb_css_parser_success(parser); + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_overflow_x(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_OVERFLOW_X_VISIBLE: + case LXB_CSS_OVERFLOW_X_HIDDEN: + case LXB_CSS_OVERFLOW_X_CLIP: + case LXB_CSS_OVERFLOW_X_SCROLL: + case LXB_CSS_OVERFLOW_X_AUTO: + declar->u.overflow_x->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_overflow_y(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_overflow_x(parser, token, ctx); +} + +bool +lxb_css_property_state_overflow_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_overflow_x(parser, token, ctx); +} + +bool +lxb_css_property_state_overflow_inline(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_overflow_x(parser, token, ctx); +} + +bool +lxb_css_property_state_text_overflow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_OVERFLOW_CLIP: + case LXB_CSS_TEXT_OVERFLOW_ELLIPSIS: + declar->u.text_overflow->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +lxb_status_t +lxb_css_property_state_text_decoration_line_h(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_text_decoration_line_t *tdl) +{ + lxb_css_value_type_t type; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return LXB_STATUS_NEXT; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_TEXT_DECORATION_LINE_NONE: + tdl->type = type; + + lxb_css_syntax_parser_consume(parser); + return LXB_STATUS_OK; + + default: + goto first; + } + +next: + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token_wo_ws(parser); + if (token == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return LXB_STATUS_OK; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + +first: + + switch (type) { + case LXB_CSS_TEXT_DECORATION_LINE_UNDERLINE: + if (tdl->underline != LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_STOP; + } + + tdl->underline = type; + goto next; + + case LXB_CSS_TEXT_DECORATION_LINE_OVERLINE: + if (tdl->overline != LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_STOP; + } + + tdl->overline = type; + goto next; + + case LXB_CSS_TEXT_DECORATION_LINE_LINE_THROUGH: + if (tdl->line_through != LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_STOP; + } + + tdl->line_through = type; + goto next; + + case LXB_CSS_TEXT_DECORATION_LINE_BLINK: + if (tdl->blink != LXB_CSS_VALUE__UNDEF) { + return LXB_STATUS_STOP; + } + + tdl->blink = type; + goto next; + + default: + if (tdl->underline != LXB_CSS_VALUE__UNDEF + || tdl->overline != LXB_CSS_VALUE__UNDEF + || tdl->line_through != LXB_CSS_VALUE__UNDEF + || tdl->blink != LXB_CSS_VALUE__UNDEF) + { + return LXB_STATUS_OK; + } + + return LXB_STATUS_NEXT; + } +} + +bool +lxb_css_property_state_text_decoration_line(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_status_t status; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_text_decoration_line_t *tdl = declar->u.text_decoration_line; + + status = lxb_css_property_state_text_decoration_line_h(parser, token, tdl); + + if (status == LXB_STATUS_OK) { + return lxb_css_parser_success(parser); + } + else if (status == LXB_STATUS_STOP) { + return lxb_css_parser_failed(parser); + } + else if (status != LXB_STATUS_NEXT) { + return lxb_css_parser_memory_fail(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + tdl->type = type; + + lxb_css_syntax_parser_consume(parser); + return lxb_css_parser_success(parser); + + default: + return lxb_css_parser_failed(parser); + } +} + +bool +lxb_css_property_state_text_decoration_style_h(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_property_text_decoration_style_t *tds) +{ + lxb_css_value_type_t type; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return false; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + case LXB_CSS_TEXT_DECORATION_STYLE_SOLID: + case LXB_CSS_TEXT_DECORATION_STYLE_DOUBLE: + case LXB_CSS_TEXT_DECORATION_STYLE_DOTTED: + case LXB_CSS_TEXT_DECORATION_STYLE_DASHED: + case LXB_CSS_TEXT_DECORATION_STYLE_WAVY: + tds->type = type; + + lxb_css_syntax_parser_consume(parser); + return true; + + default: + return false; + } +} + +bool +lxb_css_property_state_text_decoration_style(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return lxb_css_parser_failed(parser); + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + /* Local. */ + case LXB_CSS_TEXT_DECORATION_STYLE_SOLID: + case LXB_CSS_TEXT_DECORATION_STYLE_DOUBLE: + case LXB_CSS_TEXT_DECORATION_STYLE_DOTTED: + case LXB_CSS_TEXT_DECORATION_STYLE_DASHED: + case LXB_CSS_TEXT_DECORATION_STYLE_WAVY: + declar->u.text_decoration_style->type = type; + break; + + default: + return lxb_css_parser_failed(parser); + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_parser_success(parser); +} + +bool +lxb_css_property_state_text_decoration_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_property_state_color(parser, token, ctx); +} + +bool +lxb_css_property_state_text_decoration(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + bool res, line, style, color; + lxb_status_t status; + lxb_css_value_type_t type; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_property_text_decoration_t *td = declar->u.text_decoration; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + goto lsc; + } + + type = lxb_css_value_by_name(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length); + switch (type) { + /* Global. */ + case LXB_CSS_VALUE_INITIAL: + case LXB_CSS_VALUE_INHERIT: + case LXB_CSS_VALUE_UNSET: + case LXB_CSS_VALUE_REVERT: + td->line.type = type; + + lxb_css_syntax_parser_consume(parser); + return lxb_css_parser_success(parser); + + default: + break; + } + +lsc: + + line = false; + style = false; + color = false; + + for (size_t i = 0; i < 3; i++) { + if (!line) { + status = lxb_css_property_state_text_decoration_line_h(parser, token, + &td->line); + if (status == LXB_STATUS_OK) { + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + line = true; + } + else if (status == LXB_STATUS_STOP) { + return lxb_css_parser_failed(parser); + } + else if (status != LXB_STATUS_NEXT) { + return lxb_css_parser_memory_fail(parser); + } + } + + if (!style) { + res = lxb_css_property_state_text_decoration_style_h(parser, token, + &td->style); + if (res) { + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + style = true; + } + } + + if (!color) { + res = lxb_css_property_state_color_handler(parser, token, + (lxb_css_value_color_t *) &td->color, + &status); + if (res) { + token = lxb_css_syntax_parser_token_wo_ws(parser); + lxb_css_property_state_check_token(parser, token); + + color = true; + } + else { + if (status != LXB_STATUS_OK) { + return lxb_css_parser_failed(parser); + } + } + } + } + + if (!line && !style && !color) { + return lxb_css_parser_failed(parser); + } + + return lxb_css_parser_success(parser); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/state.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/state.h new file mode 100644 index 0000000..7d60f4f --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/state.h @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2021-2023 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_PROPERTY_STATE_H +#define LXB_CSS_PROPERTY_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" + + +LXB_API bool +lxb_css_property_state__undef(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state__custom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_display(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_order(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_visibility(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_width(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_box_sizing(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_min_width(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_min_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_max_width(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_max_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_margin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_margin_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_margin_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_margin_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_margin_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_padding(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_padding_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_padding_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_padding_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_padding_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_top_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_right_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_bottom_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_border_left_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_background_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_opacity(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_position(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_top(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_right(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_bottom(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_left(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_inset_block_start(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_inset_inline_start(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_inset_block_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_inset_inline_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_transform(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_align(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_align_all(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_align_last(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_justify(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_indent(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_white_space(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_tab_size(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_word_break(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_line_break(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_hyphens(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_overflow_wrap(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_word_wrap(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_word_spacing(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_letter_spacing(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_hanging_punctuation(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_font_family(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_font_weight(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_font_stretch(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_font_style(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_font_size(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_float_reference(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_float(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_clear(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_float_defer(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_float_offset(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_wrap_flow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_wrap_through(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex_direction(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex_wrap(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex_flow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex_grow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex_shrink(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_flex_basis(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_justify_content(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_align_items(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_align_self(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_align_content(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_z_index(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_direction(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_unicode_bidi(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_writing_mode(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_orientation(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_combine_upright(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_overflow_x(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_overflow_y(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_overflow_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_overflow_inline(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_overflow(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_decoration_line(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_decoration_style(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_decoration_color(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_text_decoration(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_dominant_baseline(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_vertical_align(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_baseline_source(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_alignment_baseline(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_baseline_shift(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +LXB_API bool +lxb_css_property_state_line_height(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_PROPERTY_STATE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/types.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/types.h new file mode 100644 index 0000000..3a23f12 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/property/types.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_PROPERTY_TYPES_H +#define LXB_CSS_PROPERTY_TYPES_H + + + + + +#endif /* LXB_CSS_PROPERTY_TYPES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/rule.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/rule.c new file mode 100644 index 0000000..5ee9387 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/rule.c @@ -0,0 +1,598 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/rule.h" +#include "lexbor/css/parser.h" +#include "lexbor/core/serialize.h" +#include "lexbor/css/stylesheet.h" +#include "lexbor/css/selectors/selectors.h" + + +void * +lxb_css_rule_destroy(lxb_css_rule_t *rule, bool self_destroy) +{ + switch (rule->type) { + case LXB_CSS_RULE_LIST: + return lxb_css_rule_list_destroy(lxb_css_rule_list(rule), + self_destroy); + case LXB_CSS_RULE_AT_RULE: + return lxb_css_rule_at_destroy(lxb_css_rule_at(rule), + self_destroy); + case LXB_CSS_RULE_STYLE: + return lxb_css_rule_style_destroy(lxb_css_rule_style(rule), + self_destroy); + case LXB_CSS_RULE_BAD_STYLE: + return lxb_css_rule_bad_style_destroy(lxb_css_rule_bad_style(rule), + self_destroy); + case LXB_CSS_RULE_DECLARATION: + return lxb_css_rule_declaration_destroy(lxb_css_rule_declaration(rule), + self_destroy); + case LXB_CSS_RULE_DECLARATION_LIST: + return lxb_css_rule_declaration_list_destroy(lxb_css_rule_declaration_list(rule), + self_destroy); + case LXB_CSS_RULE_STYLESHEET: + case LXB_CSS_RULE_UNDEF: + return NULL; + } + + return NULL; +} + +lxb_status_t +lxb_css_rule_serialize(const lxb_css_rule_t *rule, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (rule->type) { + case LXB_CSS_RULE_LIST: + return lxb_css_rule_list_serialize(lxb_css_rule_list(rule), cb, ctx); + + case LXB_CSS_RULE_AT_RULE: + return lxb_css_rule_at_serialize(lxb_css_rule_at(rule), cb, ctx); + + case LXB_CSS_RULE_STYLE: + return lxb_css_rule_style_serialize(lxb_css_rule_style(rule), + cb, ctx); + case LXB_CSS_RULE_BAD_STYLE: + return lxb_css_rule_bad_style_serialize(lxb_css_rule_bad_style(rule), + cb, ctx); + case LXB_CSS_RULE_DECLARATION: + return lxb_css_rule_declaration_serialize(lxb_css_rule_declaration(rule), + cb, ctx); + case LXB_CSS_RULE_DECLARATION_LIST: + return lxb_css_rule_declaration_list_serialize(lxb_css_rule_declaration_list(rule), + cb, ctx); + case LXB_CSS_RULE_STYLESHEET: + case LXB_CSS_RULE_UNDEF: + break; + } + + return LXB_STATUS_ERROR_WRONG_ARGS; +} + +lxb_status_t +lxb_css_rule_serialize_chain(const lxb_css_rule_t *rule, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + static const lxb_char_t ws_str[] = "\n"; + + status = lxb_css_rule_serialize(rule, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + rule = rule->next; + + while (rule != NULL) { + lexbor_serialize_write(cb, ws_str, (sizeof(ws_str) - 1), ctx, status); + + status = lxb_css_rule_serialize(rule, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + rule = rule->next; + } + + return LXB_STATUS_OK; +} + +lxb_css_rule_list_t * +lxb_css_rule_list_destroy(lxb_css_rule_list_t *list, bool self_destroy) +{ + lxb_css_rule_t *rule, *next, *parent; + lxb_css_rule_t *child_rule; + lxb_css_memory_t *memory; + lxb_css_rule_at_t *at; + lxb_css_rule_style_t *style; + lxb_css_rule_bad_style_t *bad; + lxb_css_rule_list_t *sub_list; + lxb_css_rule_declaration_list_t *declr_list; + + if (list == NULL) { + return NULL; + } + + rule = list->first; + memory = lxb_css_rule(list)->memory; + + while (rule != NULL) { + child_rule = NULL; + + switch (rule->type) { + case LXB_CSS_RULE_LIST: + sub_list = lxb_css_rule_list(rule); + + if (sub_list->first != NULL) { + child_rule = sub_list->first; + + sub_list->first = NULL; + sub_list->last = NULL; + } + break; + + case LXB_CSS_RULE_STYLE: + style = lxb_css_rule_style(rule); + + if (style->child != NULL) { + child_rule = lxb_css_rule(style->child); + style->child = NULL; + } + break; + + case LXB_CSS_RULE_BAD_STYLE: + bad = lxb_css_rule_bad_style(rule); + + if (bad->child != NULL) { + child_rule = lxb_css_rule(bad->child); + bad->child = NULL; + } + break; + + case LXB_CSS_RULE_AT_RULE: + at = lxb_css_rule_at(rule); + + if (at->type == LXB_CSS_AT_RULE_MEDIA) { + if (at->u.media != NULL && at->u.media->block != NULL) { + child_rule = lxb_css_rule(at->u.media->block); + at->u.media->block = NULL; + } + } + else if (at->type == LXB_CSS_AT_RULE__UNDEF) { + if (at->u.undef != NULL && at->u.undef->block != NULL) { + child_rule = lxb_css_rule(at->u.undef->block); + at->u.undef->block = NULL; + } + } + else if (at->type == LXB_CSS_AT_RULE__CUSTOM) { + if (at->u.custom != NULL && at->u.custom->block != NULL) { + child_rule = lxb_css_rule(at->u.custom->block); + at->u.custom->block = NULL; + } + } + else if (at->type == LXB_CSS_AT_RULE_FONT_FACE) { + if (at->u.font_face != NULL && at->u.font_face->block != NULL) { + child_rule = lxb_css_rule(at->u.font_face->block); + at->u.font_face->block = NULL; + } + } + break; + + case LXB_CSS_RULE_DECLARATION_LIST: + declr_list = lxb_css_rule_declaration_list(rule); + + if (declr_list->first != NULL) { + child_rule = declr_list->first; + + declr_list->first = NULL; + declr_list->last = NULL; + } + break; + + default: + break; + } + + if (child_rule != NULL) { + rule = child_rule; + continue; + } + + next = rule->next; + parent = rule->parent; + + (void) lxb_css_rule_destroy(rule, true); + + if (next != NULL) { + rule = next; + } + else { + if (parent == lxb_css_rule(list)) { + break; + } + + rule = parent; + } + } + + if (self_destroy) { + return lexbor_mraw_free(memory->tree, list); + } + + list->first = NULL; + list->last = NULL; + + return list; +} + +lxb_status_t +lxb_css_rule_list_serialize(const lxb_css_rule_list_t *list, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + lxb_css_rule_t *rule; + + static const lxb_char_t nl_str[] = "\n"; + + rule = list->first; + + if (rule == NULL) { + return LXB_STATUS_OK; + } + + status = lxb_css_rule_serialize(rule, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + rule = rule->next; + + while (rule != NULL) { + lexbor_serialize_write(cb, nl_str, (sizeof(nl_str) - 1), ctx, status); + + status = lxb_css_rule_serialize(rule, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + rule = rule->next; + } + + return LXB_STATUS_OK; +} + +lxb_css_rule_at_t * +lxb_css_rule_at_destroy(lxb_css_rule_at_t *at, bool self_destroy) +{ + lxb_css_memory_t *memory = lxb_css_rule(at)->memory; + + switch (at->type) { + case LXB_CSS_AT_RULE__UNDEF: + (void) lxb_css_at_rule__undef_destroy(memory, at->u.undef, true); + break; + + case LXB_CSS_AT_RULE_MEDIA: + (void) lxb_css_at_rule_media_destroy(memory, at->u.media, true); + break; + + case LXB_CSS_AT_RULE_NAMESPACE: + (void) lxb_css_at_rule_namespace_destroy(memory, at->u.ns, true); + break; + + case LXB_CSS_AT_RULE__LAST_ENTRY: + break; + } + + if (self_destroy) { + return lexbor_mraw_free(memory->tree, at); + } + + return at; +} + +lxb_status_t +lxb_css_rule_at_serialize(const lxb_css_rule_at_t *at, lexbor_serialize_cb_f cb, + void *ctx) +{ + lxb_status_t status; + const lxb_css_at_rule__undef_t *undef; + const lxb_css_at_rule__custom_t *custom; + const lxb_css_entry_at_rule_data_t *data, *undata; + + static const lxb_char_t at_str[] = "@"; + + data = lxb_css_at_rule_by_id(at->type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + lexbor_serialize_write(cb, at_str, (sizeof(at_str) - 1), ctx, status); + + if (at->type == LXB_CSS_AT_RULE__UNDEF) { + undef = at->u.undef; + + undata = lxb_css_at_rule_by_id(undef->type); + if (undata == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + lexbor_serialize_write(cb, undata->name, undata->length, ctx, status); + } + else if (at->type == LXB_CSS_AT_RULE__CUSTOM) { + custom = at->u.custom; + + lexbor_serialize_write(cb, custom->name.data, + custom->name.length, ctx, status); + } + else { + lexbor_serialize_write(cb, data->name, data->length, ctx, status); + } + + return data->serialize(at->u.user, cb, ctx); +} + +lxb_status_t +lxb_css_rule_at_serialize_name(const lxb_css_rule_at_t *at, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_at_rule_serialize_name(at->u.user, at->type, cb, ctx); +} + +lxb_css_rule_style_t * +lxb_css_rule_style_destroy(lxb_css_rule_style_t *style, bool self_destroy) +{ + lxb_css_memory_t *memory = lxb_css_rule(style)->memory; + + lxb_css_selector_list_destroy(style->selector); + (void) lxb_css_rule_declaration_list_destroy(style->declarations, true); + (void) lxb_css_rule_list_destroy(style->child, true); + + style->selector = NULL; + style->declarations = NULL; + style->child = NULL; + + if (self_destroy) { + return lexbor_mraw_free(memory->tree, style); + } + + return style; +} + +lxb_status_t +lxb_css_rule_style_serialize(const lxb_css_rule_style_t *style, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + static const lxb_char_t lc_str[] = " {"; + static const lxb_char_t rc_str[] = "}"; + static const lxb_char_t cm_str[] = "; "; + + status = lxb_css_selector_serialize_list_chain(style->selector, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (style->declarations != NULL) { + lexbor_serialize_write(cb, lc_str, (sizeof(lc_str) - 1), ctx, status); + + status = lxb_css_rule_declaration_list_serialize(style->declarations, + cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (style->child == NULL) { + lexbor_serialize_write(cb, rc_str, (sizeof(rc_str) - 1), + ctx, status); + } + } + + if (style->child != NULL && style->child->first != NULL) { + lexbor_serialize_write(cb, cm_str, (sizeof(cm_str) - 1), ctx, status); + + status = lxb_css_rule_list_serialize(style->child, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + if (style->declarations != NULL) { + lexbor_serialize_write(cb, rc_str, (sizeof(rc_str) - 1), ctx, status); + } + + return LXB_STATUS_OK; +} + +lxb_css_rule_bad_style_t * +lxb_css_rule_bad_style_destroy(lxb_css_rule_bad_style_t *bad, bool self_destroy) +{ + lxb_css_memory_t *memory = lxb_css_rule(bad)->memory; + + (void) lexbor_str_destroy(&bad->selectors, memory->mraw, false); + bad->declarations = lxb_css_rule_declaration_list_destroy(bad->declarations, + true); + bad->child = lxb_css_rule_list_destroy(bad->child, true); + + if (self_destroy) { + return lexbor_mraw_free(memory->tree, bad); + } + + return bad; +} + +lxb_status_t +lxb_css_rule_bad_style_serialize(const lxb_css_rule_bad_style_t *bad, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + static const lxb_char_t lc_str[] = "{"; + static const lxb_char_t rc_str[] = "}"; + + if (bad->selectors.data != NULL) { + lexbor_serialize_write(cb, bad->selectors.data, bad->selectors.length, + ctx, status); + } + + if (bad->declarations != NULL) { + lexbor_serialize_write(cb, lc_str, (sizeof(lc_str) - 1), ctx, status); + + status = lxb_css_rule_declaration_list_serialize(bad->declarations, + cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb(rc_str, (sizeof(rc_str) - 1), ctx); + } + + return LXB_STATUS_OK; +} + +lxb_css_rule_declaration_list_t * +lxb_css_rule_declaration_list_destroy(lxb_css_rule_declaration_list_t *list, + bool self_destroy) +{ + lxb_css_rule_t *declr, *next; + + if (list == NULL) { + return NULL; + } + + declr = list->first; + + while (declr != NULL) { + next = declr->next; + (void) lxb_css_rule_destroy(declr, true); + declr = next; + } + + if (self_destroy) { + return lexbor_mraw_free(lxb_css_rule(list)->memory->tree, list); + } + + list->first = NULL; + list->last = NULL; + + return list; +} + +lxb_status_t +lxb_css_rule_declaration_list_serialize(const lxb_css_rule_declaration_list_t *list, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_rule_t *declr; + + static const lxb_char_t sm_str[] = "; "; + + declr = list->first; + + if (declr == NULL) { + return LXB_STATUS_OK; + } + + status = lxb_css_rule_serialize(declr, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + declr = declr->next; + + while (declr != NULL) { + lexbor_serialize_write(cb, sm_str, (sizeof(sm_str) - 1), ctx, status); + + status = lxb_css_rule_serialize(declr, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + declr = declr->next; + } + + return LXB_STATUS_OK; +} + +lxb_css_rule_declaration_t * +lxb_css_rule_declaration_destroy(lxb_css_rule_declaration_t *declr, + bool self_destroy) +{ + lxb_css_memory_t *memory = lxb_css_rule(declr)->memory; + + if (declr->u.user != NULL) { + declr->u.user = lxb_css_property_destroy(memory, declr->u.user, + declr->type, true); + } + + if (self_destroy) { + return lexbor_mraw_free(memory->tree, declr); + } + + return declr; +} + +lxb_status_t +lxb_css_rule_declaration_serialize(const lxb_css_rule_declaration_t *declaration, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + const lxb_css_entry_data_t *data, *undata; + const lxb_css_property__undef_t *undef; + const lxb_css_property__custom_t *custom; + + static const lxb_char_t cl_str[] = ": "; + static const lxb_char_t imp_str[] = " !important"; + + data = lxb_css_property_by_id(declaration->type); + if (data == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + if (declaration->type == LXB_CSS_PROPERTY__UNDEF) { + undef = declaration->u.undef; + + if (undef->type > LXB_CSS_PROPERTY__CUSTOM) { + undata = lxb_css_property_by_id(undef->type); + if (undata == NULL) { + return LXB_STATUS_ERROR_NOT_EXISTS; + } + + lexbor_serialize_write(cb, undata->name, undata->length, ctx, status); + lexbor_serialize_write(cb, cl_str, (sizeof(cl_str) - 1), ctx, status); + } + } + else if (declaration->type == LXB_CSS_PROPERTY__CUSTOM) { + custom = declaration->u.custom; + + lexbor_serialize_write(cb, custom->name.data, custom->name.length, + ctx, status); + lexbor_serialize_write(cb, cl_str, (sizeof(cl_str) - 1), ctx, status); + } + else { + lexbor_serialize_write(cb, data->name, data->length, ctx, status); + lexbor_serialize_write(cb, cl_str, (sizeof(cl_str) - 1), ctx, status); + } + + status = data->serialize(declaration->u.user, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (declaration->important && declaration->type != LXB_CSS_PROPERTY__UNDEF) { + lexbor_serialize_write(cb, imp_str, (sizeof(imp_str) - 1), ctx, status); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_rule_declaration_serialize_name(const lxb_css_rule_declaration_t *declr, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_property_serialize_name(declr->u.user, declr->type, cb, ctx); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/rule.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/rule.h new file mode 100644 index 0000000..308dced --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/rule.h @@ -0,0 +1,453 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_RULE_H +#define LXB_CSS_RULE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/at_rule.h" +#include "lexbor/css/property.h" +#include "lexbor/css/selectors/selectors.h" + + +#define lxb_css_rule(rule) ((lxb_css_rule_t *) (rule)) +#define lxb_css_rule_list(rule) ((lxb_css_rule_list_t *) (rule)) +#define lxb_css_rule_at(rule) ((lxb_css_rule_at_t *) (rule)) +#define lxb_css_rule_style(rule) ((lxb_css_rule_style_t *) (rule)) +#define lxb_css_rule_bad_style(rule) ((lxb_css_rule_bad_style_t *) (rule)) +#define lxb_css_rule_declaration_list(rule) ((lxb_css_rule_declaration_list_t *) (rule)) +#define lxb_css_rule_declaration(rule) ((lxb_css_rule_declaration_t *) (rule)) + + +typedef enum { + LXB_CSS_RULE_UNDEF = 0, + LXB_CSS_RULE_STYLESHEET, + LXB_CSS_RULE_LIST, + LXB_CSS_RULE_AT_RULE, + LXB_CSS_RULE_STYLE, + LXB_CSS_RULE_BAD_STYLE, + LXB_CSS_RULE_DECLARATION_LIST, + LXB_CSS_RULE_DECLARATION +} +lxb_css_rule_type_t; + +typedef struct lxb_css_rule lxb_css_rule_t; + +struct lxb_css_rule { + lxb_css_rule_type_t type; + lxb_css_rule_t *next; + lxb_css_rule_t *prev; + lxb_css_rule_t *parent; + + lxb_css_memory_t *memory; + size_t ref_count; +}; + +struct lxb_css_rule_list { + lxb_css_rule_t rule; + + lxb_css_rule_t *first; + lxb_css_rule_t *last; +}; + +struct lxb_css_rule_at { + lxb_css_rule_t rule; + + uintptr_t type; + + union { + lxb_css_at_rule__undef_t *undef; + lxb_css_at_rule__custom_t *custom; + lxb_css_at_rule_font_face_t *font_face; + lxb_css_at_rule_media_t *media; + lxb_css_at_rule_namespace_t *ns; + void *user; + } u; + + size_t name_begin; + size_t prelude_begin; + size_t prelude_end; +}; + +struct lxb_css_rule_style { + lxb_css_rule_t rule; + + lxb_css_selector_list_t *selector; + lxb_css_rule_declaration_list_t *declarations; + lxb_css_rule_list_t *child; + + size_t prelude_begin; + size_t prelude_end; +}; + +struct lxb_css_rule_bad_style { + lxb_css_rule_t rule; + + lexbor_str_t selectors; + lxb_css_rule_declaration_list_t *declarations; + lxb_css_rule_list_t *child; + + size_t prelude_begin; + size_t prelude_end; +}; + +struct lxb_css_rule_declaration_list { + lxb_css_rule_t rule; + + lxb_css_rule_t *first; + lxb_css_rule_t *last; + + size_t count; +}; + +typedef struct { + size_t name_begin; + size_t name_end; + size_t value_begin; + size_t value_end; + size_t important_begin; + size_t important_end; +} +lxb_css_rule_declaration_offset_t; + +struct lxb_css_rule_declaration { + lxb_css_rule_t rule; + uintptr_t type; + + union { + lxb_css_property__undef_t *undef; + lxb_css_property__custom_t *custom; + lxb_css_property_display_t *display; + lxb_css_property_order_t *order; + lxb_css_property_visibility_t *visibility; + lxb_css_property_width_t *width; + lxb_css_property_height_t *height; + lxb_css_property_box_sizing_t *box_sizing; + lxb_css_property_margin_t *margin; + lxb_css_property_margin_top_t *margin_top; + lxb_css_property_margin_right_t *margin_right; + lxb_css_property_margin_bottom_t *margin_bottom; + lxb_css_property_margin_left_t *margin_left; + lxb_css_property_padding_t *padding; + lxb_css_property_padding_top_t *padding_top; + lxb_css_property_padding_right_t *padding_right; + lxb_css_property_padding_bottom_t *padding_bottom; + lxb_css_property_padding_left_t *padding_left; + lxb_css_property_border_t *border; + lxb_css_property_border_top_t *border_top; + lxb_css_property_border_right_t *border_right; + lxb_css_property_border_bottom_t *border_bottom; + lxb_css_property_border_left_t *border_left; + lxb_css_property_border_top_color_t *border_top_color; + lxb_css_property_border_right_color_t *border_right_color; + lxb_css_property_border_bottom_color_t *border_bottom_color; + lxb_css_property_border_left_color_t *border_left_color; + lxb_css_property_background_color_t *background_color; + lxb_css_property_color_t *color; + lxb_css_property_opacity_t *opacity; + lxb_css_property_position_t *position; + lxb_css_property_top_t *top; + lxb_css_property_right_t *right; + lxb_css_property_bottom_t *bottom; + lxb_css_property_left_t *left; + lxb_css_property_inset_block_start_t *inset_block_start; + lxb_css_property_inset_inline_start_t *inset_inline_start; + lxb_css_property_inset_block_end_t *inset_block_end; + lxb_css_property_inset_inline_end_t *inset_inline_end; + lxb_css_property_text_transform_t *text_transform; + lxb_css_property_text_align_t *text_align; + lxb_css_property_text_align_all_t *text_align_all; + lxb_css_property_text_align_last_t *text_align_last; + lxb_css_property_text_justify_t *text_justify; + lxb_css_property_text_indent_t *text_indent; + lxb_css_property_white_space_t *white_space; + lxb_css_property_tab_size_t *tab_size; + lxb_css_property_word_break_t *word_break; + lxb_css_property_line_break_t *line_break; + lxb_css_property_hyphens_t *hyphens; + lxb_css_property_overflow_wrap_t *overflow_wrap; + lxb_css_property_word_wrap_t *word_wrap; + lxb_css_property_word_spacing_t *word_spacing; + lxb_css_property_letter_spacing_t *letter_spacing; + lxb_css_property_hanging_punctuation_t *hanging_punctuation; + lxb_css_property_font_family_t *font_family; + lxb_css_property_font_weight_t *font_weight; + lxb_css_property_font_stretch_t *font_stretch; + lxb_css_property_font_style_t *font_style; + lxb_css_property_font_size_t *font_size; + lxb_css_property_float_reference_t *float_reference; + lxb_css_property_float_t *floatp; + lxb_css_property_clear_t *clear; + lxb_css_property_float_defer_t *float_defer; + lxb_css_property_float_offset_t *float_offset; + lxb_css_property_wrap_flow_t *wrap_flow; + lxb_css_property_wrap_through_t *wrap_through; + lxb_css_property_flex_direction_t *flex_direction; + lxb_css_property_flex_wrap_t *flex_wrap; + lxb_css_property_flex_flow_t *flex_flow; + lxb_css_property_flex_t *flex; + lxb_css_property_flex_grow_t *flex_grow; + lxb_css_property_flex_shrink_t *flex_shrink; + lxb_css_property_flex_basis_t *flex_basis; + lxb_css_property_justify_content_t *justify_content; + lxb_css_property_align_items_t *align_items; + lxb_css_property_align_self_t *align_self; + lxb_css_property_align_content_t *align_content; + lxb_css_property_dominant_baseline_t *dominant_baseline; + lxb_css_property_vertical_align_t *vertical_align; + lxb_css_property_baseline_source_t *baseline_source; + lxb_css_property_alignment_baseline_t *alignment_baseline; + lxb_css_property_baseline_shift_t *baseline_shift; + lxb_css_property_line_height_t *line_height; + lxb_css_property_z_index_t *z_index; + lxb_css_property_direction_t *direction; + lxb_css_property_unicode_bidi_t *unicode_bidi; + lxb_css_property_writing_mode_t *writing_mode; + lxb_css_property_text_orientation_t *text_orientation; + lxb_css_property_text_combine_upright_t *text_combine_upright; + lxb_css_property_overflow_x_t *overflow_x; + lxb_css_property_overflow_y_t *overflow_y; + lxb_css_property_overflow_block_t *overflow_block; + lxb_css_property_overflow_inline_t *overflow_inline; + lxb_css_property_text_overflow_t *text_overflow; + lxb_css_property_text_decoration_line_t *text_decoration_line; + lxb_css_property_text_decoration_style_t *text_decoration_style; + lxb_css_property_text_decoration_color_t *text_decoration_color; + lxb_css_property_text_decoration_t *text_decoration; + void *user; + } u; + + lxb_css_rule_declaration_offset_t offset; + + bool important; +}; + + +LXB_API void * +lxb_css_rule_destroy(lxb_css_rule_t *node, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_serialize(const lxb_css_rule_t *rule, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_rule_serialize_chain(const lxb_css_rule_t *rule, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_css_rule_list_t * +lxb_css_rule_list_destroy(lxb_css_rule_list_t *list, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_list_serialize(const lxb_css_rule_list_t *list, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_css_rule_at_t * +lxb_css_rule_at_destroy(lxb_css_rule_at_t *at, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_at_serialize(const lxb_css_rule_at_t *at, lexbor_serialize_cb_f cb, + void *ctx); + +LXB_API lxb_status_t +lxb_css_rule_at_serialize_name(const lxb_css_rule_at_t *at, lexbor_serialize_cb_f cb, + void *ctx); + +LXB_API lxb_css_rule_style_t * +lxb_css_rule_style_destroy(lxb_css_rule_style_t *style, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_style_serialize(const lxb_css_rule_style_t *style, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_css_rule_bad_style_t * +lxb_css_rule_bad_style_destroy(lxb_css_rule_bad_style_t *bad, bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_bad_style_serialize(const lxb_css_rule_bad_style_t *bad, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_css_rule_declaration_list_t * +lxb_css_rule_declaration_list_destroy(lxb_css_rule_declaration_list_t *list, + bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_declaration_list_serialize(const lxb_css_rule_declaration_list_t *list, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_css_rule_declaration_t * +lxb_css_rule_declaration_destroy(lxb_css_rule_declaration_t *declr, + bool self_destroy); + +LXB_API lxb_status_t +lxb_css_rule_declaration_serialize(const lxb_css_rule_declaration_t *declaration, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_rule_declaration_serialize_name(const lxb_css_rule_declaration_t *declr, + lexbor_serialize_cb_f cb, void *ctx); + +/* + * Inline functions + */ +lxb_inline void +lxb_css_rule_insert_next(lxb_css_rule_t *root, lxb_css_rule_t *rule) +{ + if (root->next != NULL) { + rule->next = root->next; + } + + root->next = rule; + rule->prev = root; +} + +lxb_inline lxb_css_rule_t * +lxb_css_rule_create(lxb_css_memory_t *memory, size_t size, + lxb_css_rule_type_t type) +{ + lxb_css_rule_t *rule; + + rule = (lxb_css_rule_t *) lexbor_mraw_calloc(memory->tree, size); + if (rule== NULL) { + return NULL; + } + + rule->type = type; + rule->memory = memory; + + return rule; +} + +lxb_inline lxb_css_rule_list_t * +lxb_css_rule_list_create(lxb_css_memory_t *memory) +{ + return (lxb_css_rule_list_t *) lxb_css_rule_create(memory, + sizeof(lxb_css_rule_list_t), + LXB_CSS_RULE_LIST); +} + +lxb_inline size_t +lxb_css_rule_ref_count(lxb_css_rule_t *rule) +{ + return rule->ref_count; +} + +lxb_inline lxb_status_t +lxb_css_rule_ref_inc(lxb_css_rule_t *rule) +{ + if (SIZE_MAX - rule->ref_count == 0) { + return LXB_STATUS_ERROR_OVERFLOW; + } + + rule->ref_count++; + + return LXB_STATUS_OK; +} + +lxb_inline void +lxb_css_rule_ref_dec(lxb_css_rule_t *rule) +{ + if (rule->ref_count > 0) { + rule->ref_count--; + } +} + +lxb_inline void +lxb_css_rule_ref_dec_destroy(lxb_css_rule_t *rule) +{ + if (rule->ref_count > 0) { + rule->ref_count--; + } + + if (rule->ref_count == 0) { + (void) lxb_css_rule_destroy(rule, true); + } +} + +lxb_inline void +lxb_css_rule_list_append(lxb_css_rule_list_t *list, lxb_css_rule_t *rule) +{ + if (list->first == NULL) { + list->first = rule; + } + else { + lxb_css_rule_insert_next(list->last, rule); + } + + list->last = rule; + rule->parent = lxb_css_rule(list); + + (void) lxb_css_rule_ref_inc(rule); +} + +lxb_inline lxb_css_rule_at_t * +lxb_css_rule_at_create(lxb_css_memory_t *memory) +{ + return (lxb_css_rule_at_t *) + lxb_css_rule_create(memory, sizeof(lxb_css_rule_at_t), + LXB_CSS_RULE_AT_RULE); +} + +lxb_inline lxb_css_rule_style_t * +lxb_css_rule_style_create(lxb_css_memory_t *memory) +{ + return (lxb_css_rule_style_t *) + lxb_css_rule_create(memory, sizeof(lxb_css_rule_style_t), + LXB_CSS_RULE_STYLE); +} + +lxb_inline lxb_css_rule_bad_style_t * +lxb_css_rule_bad_style_create(lxb_css_memory_t *memory) +{ + return (lxb_css_rule_bad_style_t *) + lxb_css_rule_create(memory, sizeof(lxb_css_rule_bad_style_t), + LXB_CSS_RULE_BAD_STYLE); +} + +lxb_inline lxb_css_rule_declaration_list_t * +lxb_css_rule_declaration_list_create(lxb_css_memory_t *memory) +{ + return (lxb_css_rule_declaration_list_t *) + lxb_css_rule_create(memory, sizeof(lxb_css_rule_declaration_list_t), + LXB_CSS_RULE_DECLARATION_LIST); +} + +lxb_inline void +lxb_css_rule_declaration_list_append(lxb_css_rule_declaration_list_t *list, + lxb_css_rule_t *rule) +{ + if (list->first == NULL) { + list->first = rule; + } + else { + lxb_css_rule_insert_next(list->last, rule); + } + + list->last = rule; + rule->parent = lxb_css_rule(list); + + (void) lxb_css_rule_ref_inc(rule); + + list->count++; +} + +lxb_inline lxb_css_rule_declaration_t * +lxb_css_rule_declaration_create(lxb_css_memory_t *memory) +{ + return (lxb_css_rule_declaration_t *) + lxb_css_rule_create(memory, sizeof(lxb_css_rule_declaration_t), + LXB_CSS_RULE_DECLARATION); +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_RULE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/base.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/base.h new file mode 100644 index 0000000..3151f74 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/base.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2021-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SELECTORS_BASE_H +#define LEXBOR_CSS_SELECTORS_BASE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "lexbor/core/base.h" + + +#define LXB_CSS_SELECTORS_VERSION_MAJOR 1 +#define LXB_CSS_SELECTORS_VERSION_MINOR 3 +#define LXB_CSS_SELECTORS_VERSION_PATCH 0 + +#define LXB_CSS_SELECTORS_VERSION_STRING \ + LEXBOR_STRINGIZE(LXB_CSS_SELECTORS_VERSION_MAJOR) "." \ + LEXBOR_STRINGIZE(LXB_CSS_SELECTORS_VERSION_MINOR) "." \ + LEXBOR_STRINGIZE(LXB_CSS_SELECTORS_VERSION_PATCH) + + +#define lxb_css_selector_serialize_write(data, length) \ + do { \ + (status) = cb((lxb_char_t *) (data), (length), (ctx)); \ + if ((status) != LXB_STATUS_OK) { \ + return (status); \ + } \ + } \ + while (false) + + +typedef struct lxb_css_selectors lxb_css_selectors_t; +typedef struct lxb_css_selector lxb_css_selector_t; +typedef struct lxb_css_selector_list lxb_css_selector_list_t; + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SELECTORS_BASE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo.c new file mode 100644 index 0000000..0468682 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo.c @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2020-2022 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/selectors/state.h" +#include "lexbor/css/selectors/pseudo.h" +#include "lexbor/css/selectors/pseudo_state.h" +#include "lexbor/css/selectors/pseudo_res.h" + + +const lxb_css_selectors_pseudo_data_t * +lxb_css_selector_pseudo_class_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_selectors_pseudo_class_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_class_function_by_name(const lxb_char_t *name, + size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_selectors_pseudo_class_function_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_class_function_by_id(unsigned id) +{ + return &lxb_css_selectors_pseudo_data_pseudo_class_function[id]; +} + +const lxb_css_selectors_pseudo_data_t * +lxb_css_selector_pseudo_element_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_selectors_pseudo_element_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_element_function_by_name(const lxb_char_t *name, + size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_selectors_pseudo_element_function_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_element_function_by_id(unsigned id) +{ + return &lxb_css_selectors_pseudo_data_pseudo_element_function[id]; +} + +const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_function_by_id(unsigned id, bool is_class) +{ + if (is_class) { + return &lxb_css_selectors_pseudo_data_pseudo_class_function[id]; + } + + return &lxb_css_selectors_pseudo_data_pseudo_element_function[id]; +} + +bool +lxb_css_selector_pseudo_function_can_empty(unsigned id, bool is_class) +{ + if (is_class) { + return lxb_css_selectors_pseudo_data_pseudo_class_function[id].empty; + } + + return lxb_css_selectors_pseudo_data_pseudo_element_function[id].empty; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo.h new file mode 100644 index 0000000..13eef4c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2020-2022 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SELECTORS_PSEUDO_H +#define LEXBOR_CSS_SELECTORS_PSEUDO_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/syntax/parser.h" +#include "lexbor/css/selectors/base.h" + + +typedef struct { + lxb_char_t *name; + size_t length; + unsigned id; + bool empty; + lxb_css_selector_combinator_t combinator; + const lxb_css_syntax_cb_function_t cb; + bool forgiving; + bool comma; +} +lxb_css_selectors_pseudo_data_func_t; + +typedef struct { + lxb_char_t *name; + size_t length; + unsigned id; +} +lxb_css_selectors_pseudo_data_t; + + +LXB_API const lxb_css_selectors_pseudo_data_t * +lxb_css_selector_pseudo_class_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_class_function_by_name(const lxb_char_t *name, + size_t length); + +LXB_API const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_class_function_by_id(unsigned id); + +LXB_API const lxb_css_selectors_pseudo_data_t * +lxb_css_selector_pseudo_element_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_element_function_by_name(const lxb_char_t *name, + size_t length); + +LXB_API const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_element_function_by_id(unsigned id); + +LXB_API const lxb_css_selectors_pseudo_data_func_t * +lxb_css_selector_pseudo_function_by_id(unsigned id, bool is_class); + +LXB_API bool +lxb_css_selector_pseudo_function_can_empty(unsigned id, bool is_class); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SELECTORS_PSEUDO_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_const.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_const.h new file mode 100644 index 0000000..9fa5bb2 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_const.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2020-2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/selectors/pseudo.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_SELECTOS_PSEUDO_CONST_H +#define LXB_CSS_SELECTOS_PSEUDO_CONST_H + + +typedef enum { + LXB_CSS_SELECTOR_PSEUDO_CLASS__UNDEF = 0x0000, + LXB_CSS_SELECTOR_PSEUDO_CLASS_ACTIVE = 0x0001, + LXB_CSS_SELECTOR_PSEUDO_CLASS_ANY_LINK = 0x0002, + LXB_CSS_SELECTOR_PSEUDO_CLASS_BLANK = 0x0003, + LXB_CSS_SELECTOR_PSEUDO_CLASS_CHECKED = 0x0004, + LXB_CSS_SELECTOR_PSEUDO_CLASS_CURRENT = 0x0005, + LXB_CSS_SELECTOR_PSEUDO_CLASS_DEFAULT = 0x0006, + LXB_CSS_SELECTOR_PSEUDO_CLASS_DISABLED = 0x0007, + LXB_CSS_SELECTOR_PSEUDO_CLASS_EMPTY = 0x0008, + LXB_CSS_SELECTOR_PSEUDO_CLASS_ENABLED = 0x0009, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_CHILD = 0x000a, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_OF_TYPE = 0x000b, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS = 0x000c, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_VISIBLE = 0x000d, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_WITHIN = 0x000e, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FULLSCREEN = 0x000f, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUTURE = 0x0010, + LXB_CSS_SELECTOR_PSEUDO_CLASS_HOVER = 0x0011, + LXB_CSS_SELECTOR_PSEUDO_CLASS_IN_RANGE = 0x0012, + LXB_CSS_SELECTOR_PSEUDO_CLASS_INDETERMINATE = 0x0013, + LXB_CSS_SELECTOR_PSEUDO_CLASS_INVALID = 0x0014, + LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_CHILD = 0x0015, + LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_OF_TYPE = 0x0016, + LXB_CSS_SELECTOR_PSEUDO_CLASS_LINK = 0x0017, + LXB_CSS_SELECTOR_PSEUDO_CLASS_LOCAL_LINK = 0x0018, + LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_CHILD = 0x0019, + LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_OF_TYPE = 0x001a, + LXB_CSS_SELECTOR_PSEUDO_CLASS_OPTIONAL = 0x001b, + LXB_CSS_SELECTOR_PSEUDO_CLASS_OUT_OF_RANGE = 0x001c, + LXB_CSS_SELECTOR_PSEUDO_CLASS_PAST = 0x001d, + LXB_CSS_SELECTOR_PSEUDO_CLASS_PLACEHOLDER_SHOWN = 0x001e, + LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_ONLY = 0x001f, + LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_WRITE = 0x0020, + LXB_CSS_SELECTOR_PSEUDO_CLASS_REQUIRED = 0x0021, + LXB_CSS_SELECTOR_PSEUDO_CLASS_ROOT = 0x0022, + LXB_CSS_SELECTOR_PSEUDO_CLASS_SCOPE = 0x0023, + LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET = 0x0024, + LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET_WITHIN = 0x0025, + LXB_CSS_SELECTOR_PSEUDO_CLASS_USER_INVALID = 0x0026, + LXB_CSS_SELECTOR_PSEUDO_CLASS_VALID = 0x0027, + LXB_CSS_SELECTOR_PSEUDO_CLASS_VISITED = 0x0028, + LXB_CSS_SELECTOR_PSEUDO_CLASS_WARNING = 0x0029, + LXB_CSS_SELECTOR_PSEUDO_CLASS__LAST_ENTRY = 0x002a +} +lxb_css_selector_pseudo_class_id_t; + +typedef enum { + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION__UNDEF = 0x0000, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_CURRENT = 0x0001, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR = 0x0002, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_HAS = 0x0003, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_IS = 0x0004, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG = 0x0005, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LEXBOR_CONTAINS = 0x0006, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NOT = 0x0007, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD = 0x0008, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL = 0x0009, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD = 0x000a, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL = 0x000b, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_OF_TYPE = 0x000c, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_OF_TYPE = 0x000d, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE = 0x000e, + LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION__LAST_ENTRY = 0x000f +} +lxb_css_selector_pseudo_class_function_id_t; + +typedef enum { + LXB_CSS_SELECTOR_PSEUDO_ELEMENT__UNDEF = 0x0000, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER = 0x0001, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP = 0x0002, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE = 0x0003, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER = 0x0004, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE = 0x0005, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR = 0x0006, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION = 0x0007, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER = 0x0008, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER = 0x0009, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION = 0x000a, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR = 0x000b, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT = 0x000c, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT__LAST_ENTRY = 0x000d +} +lxb_css_selector_pseudo_element_id_t; + +typedef enum { + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FUNCTION__UNDEF = 0x0000, + LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FUNCTION__LAST_ENTRY = 0x0001 +} +lxb_css_selector_pseudo_element_function_id_t; + + +#endif /* LXB_CSS_SELECTOS_PSEUDO_CONST_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_res.h new file mode 100644 index 0000000..1082574 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_res.h @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/selectors/pseudo.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_SELECTOS_PSEUDO_RES_H +#define LXB_CSS_SELECTOS_PSEUDO_RES_H + +#include "lexbor/core/shs.h" +#include "lexbor/css/selectors/pseudo_const.h" + + +static const lxb_css_selectors_pseudo_data_t lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_SELECTOR_PSEUDO_CLASS__UNDEF}, + {(lxb_char_t *) "active", 6, LXB_CSS_SELECTOR_PSEUDO_CLASS_ACTIVE}, + {(lxb_char_t *) "any-link", 8, LXB_CSS_SELECTOR_PSEUDO_CLASS_ANY_LINK}, + {(lxb_char_t *) "blank", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_BLANK}, + {(lxb_char_t *) "checked", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_CHECKED}, + {(lxb_char_t *) "current", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_CURRENT}, + {(lxb_char_t *) "default", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_DEFAULT}, + {(lxb_char_t *) "disabled", 8, LXB_CSS_SELECTOR_PSEUDO_CLASS_DISABLED}, + {(lxb_char_t *) "empty", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_EMPTY}, + {(lxb_char_t *) "enabled", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_ENABLED}, + {(lxb_char_t *) "first-child", 11, LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_CHILD}, + {(lxb_char_t *) "first-of-type", 13, LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_OF_TYPE}, + {(lxb_char_t *) "focus", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS}, + {(lxb_char_t *) "focus-visible", 13, LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_VISIBLE}, + {(lxb_char_t *) "focus-within", 12, LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_WITHIN}, + {(lxb_char_t *) "fullscreen", 10, LXB_CSS_SELECTOR_PSEUDO_CLASS_FULLSCREEN}, + {(lxb_char_t *) "future", 6, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUTURE}, + {(lxb_char_t *) "hover", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_HOVER}, + {(lxb_char_t *) "in-range", 8, LXB_CSS_SELECTOR_PSEUDO_CLASS_IN_RANGE}, + {(lxb_char_t *) "indeterminate", 13, LXB_CSS_SELECTOR_PSEUDO_CLASS_INDETERMINATE}, + {(lxb_char_t *) "invalid", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_INVALID}, + {(lxb_char_t *) "last-child", 10, LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_CHILD}, + {(lxb_char_t *) "last-of-type", 12, LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_OF_TYPE}, + {(lxb_char_t *) "link", 4, LXB_CSS_SELECTOR_PSEUDO_CLASS_LINK}, + {(lxb_char_t *) "local-link", 10, LXB_CSS_SELECTOR_PSEUDO_CLASS_LOCAL_LINK}, + {(lxb_char_t *) "only-child", 10, LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_CHILD}, + {(lxb_char_t *) "only-of-type", 12, LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_OF_TYPE}, + {(lxb_char_t *) "optional", 8, LXB_CSS_SELECTOR_PSEUDO_CLASS_OPTIONAL}, + {(lxb_char_t *) "out-of-range", 12, LXB_CSS_SELECTOR_PSEUDO_CLASS_OUT_OF_RANGE}, + {(lxb_char_t *) "past", 4, LXB_CSS_SELECTOR_PSEUDO_CLASS_PAST}, + {(lxb_char_t *) "placeholder-shown", 17, LXB_CSS_SELECTOR_PSEUDO_CLASS_PLACEHOLDER_SHOWN}, + {(lxb_char_t *) "read-only", 9, LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_ONLY}, + {(lxb_char_t *) "read-write", 10, LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_WRITE}, + {(lxb_char_t *) "required", 8, LXB_CSS_SELECTOR_PSEUDO_CLASS_REQUIRED}, + {(lxb_char_t *) "root", 4, LXB_CSS_SELECTOR_PSEUDO_CLASS_ROOT}, + {(lxb_char_t *) "scope", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_SCOPE}, + {(lxb_char_t *) "target", 6, LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET}, + {(lxb_char_t *) "target-within", 13, LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET_WITHIN}, + {(lxb_char_t *) "user-invalid", 12, LXB_CSS_SELECTOR_PSEUDO_CLASS_USER_INVALID}, + {(lxb_char_t *) "valid", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_VALID}, + {(lxb_char_t *) "visited", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_VISITED}, + {(lxb_char_t *) "warning", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_WARNING} +}; + +static const lxb_css_selectors_pseudo_data_func_t lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION__UNDEF, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function__undef, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "current", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_CURRENT, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_current, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, true}, + {(lxb_char_t *) "dir", 3, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_dir, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "has", 3, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_HAS, + false, LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT, + {.value = lxb_css_selectors_state_pseudo_class_function_has, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_forgiving_relative}, true, true}, + {(lxb_char_t *) "is", 2, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_IS, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_is, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_forgiving}, true, true}, + {(lxb_char_t *) "lang", 4, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_lang, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "lexbor-contains", 15, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LEXBOR_CONTAINS, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_lexbor_contains, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "not", 3, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NOT, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_not, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, true}, + {(lxb_char_t *) "nth-child", 9, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_nth_child, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, true}, + {(lxb_char_t *) "nth-col", 7, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_nth_col, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "nth-last-child", 14, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_nth_last_child, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, true}, + {(lxb_char_t *) "nth-last-col", 12, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_nth_last_col, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "nth-last-of-type", 16, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_OF_TYPE, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_nth_last_of_type, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "nth-of-type", 11, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_OF_TYPE, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_nth_of_type, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false}, + {(lxb_char_t *) "where", 5, LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_class_function_where, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_forgiving}, true, true} +}; + +static const lxb_css_selectors_pseudo_data_t lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_SELECTOR_PSEUDO_ELEMENT__UNDEF}, + {(lxb_char_t *) "after", 5, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER}, + {(lxb_char_t *) "backdrop", 8, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP}, + {(lxb_char_t *) "before", 6, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE}, + {(lxb_char_t *) "first-letter", 12, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER}, + {(lxb_char_t *) "first-line", 10, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE}, + {(lxb_char_t *) "grammar-error", 13, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR}, + {(lxb_char_t *) "inactive-selection", 18, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION}, + {(lxb_char_t *) "marker", 6, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER}, + {(lxb_char_t *) "placeholder", 11, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER}, + {(lxb_char_t *) "selection", 9, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION}, + {(lxb_char_t *) "spelling-error", 14, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR}, + {(lxb_char_t *) "target-text", 11, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT} +}; + +static const lxb_css_selectors_pseudo_data_func_t lxb_css_selectors_pseudo_data_pseudo_element_function[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FUNCTION__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FUNCTION__UNDEF, + false, LXB_CSS_SELECTOR_COMBINATOR_CLOSE, + {.value = lxb_css_selectors_state_pseudo_element_function__undef, + .cb.failed = lxb_css_state_failed, .cb.end = lxb_css_selectors_state_function_end}, false, false} +}; + +static const lexbor_shs_entry_t lxb_css_selectors_pseudo_class_shs[79] = +{ + {NULL, NULL, 78, 0}, + {"focus-visible", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_VISIBLE], 13, 0}, + {"first-of-type", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_OF_TYPE], 13, 1}, + {"in-range", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_IN_RANGE], 8, 0}, + {"out-of-range", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_OUT_OF_RANGE], 12, 0}, + {"read-write", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_WRITE], 10, 0}, + {"hover", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_HOVER], 5, 3}, + {"enabled", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_ENABLED], 7, 0}, + {"fullscreen", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FULLSCREEN], 10, 0}, + {"placeholder-shown", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_PLACEHOLDER_SHOWN], 17, 0}, + {"target-within", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET_WITHIN], 13, 0}, + {"indeterminate", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_INDETERMINATE], 13, 0}, + {"local-link", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_LOCAL_LINK], 10, 0}, + {"user-invalid", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_USER_INVALID], 12, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"past", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_PAST], 4, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"only-of-type", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_OF_TYPE], 12, 4}, + {"only-child", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_ONLY_CHILD], 10, 5}, + {"focus", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS], 5, 7}, + {NULL, NULL, 0, 0}, + {"any-link", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_ANY_LINK], 8, 0}, + {NULL, NULL, 0, 0}, + {"valid", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_VALID], 5, 0}, + {NULL, NULL, 0, 0}, + {"visited", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_VISITED], 7, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"root", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_ROOT], 4, 8}, + {NULL, NULL, 0, 0}, + {"focus-within", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FOCUS_WITHIN], 12, 0}, + {"checked", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_CHECKED], 7, 9}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"active", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_ACTIVE], 6, 0}, + {"last-of-type", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_OF_TYPE], 12, 0}, + {NULL, NULL, 0, 0}, + {"target", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_TARGET], 6, 0}, + {"read-only", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_READ_ONLY], 9, 10}, + {NULL, NULL, 0, 0}, + {"first-child", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FIRST_CHILD], 11, 0}, + {"disabled", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_DISABLED], 8, 0}, + {NULL, NULL, 0, 0}, + {"required", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_REQUIRED], 8, 0}, + {NULL, NULL, 0, 0}, + {"link", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_LINK], 4, 0}, + {NULL, NULL, 0, 0}, + {"empty", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_EMPTY], 5, 0}, + {"invalid", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_INVALID], 7, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"scope", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_SCOPE], 5, 12}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"blank", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_BLANK], 5, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"warning", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_WARNING], 7, 0}, + {"default", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_DEFAULT], 7, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"future", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUTURE], 6, 0}, + {"current", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_CURRENT], 7, 0}, + {"optional", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_OPTIONAL], 8, 0}, + {NULL, NULL, 0, 0}, + {"last-child", (void *) &lxb_css_selectors_pseudo_data_pseudo_class[LXB_CSS_SELECTOR_PSEUDO_CLASS_LAST_CHILD], 10, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_selectors_pseudo_class_function_shs[43] = +{ + {NULL, NULL, 42, 0}, + {"nth-last-of-type", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_OF_TYPE], 16, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"not", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NOT], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"has", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_HAS], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"nth-col", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL], 7, 0}, + {NULL, NULL, 0, 0}, + {"lexbor-contains", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LEXBOR_CONTAINS], 15, 0}, + {NULL, NULL, 0, 0}, + {"is", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_IS], 2, 0}, + {"nth-last-col", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL], 12, 0}, + {"current", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_CURRENT], 7, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"lang", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG], 4, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"nth-child", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD], 9, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"nth-last-child", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD], 14, 0}, + {"nth-of-type", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_OF_TYPE], 11, 0}, + {NULL, NULL, 0, 0}, + {"dir", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR], 3, 0}, + {"where", (void *) &lxb_css_selectors_pseudo_data_pseudo_class_function[LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE], 5, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_selectors_pseudo_element_shs[24] = +{ + {NULL, NULL, 23, 0}, + {NULL, NULL, 0, 0}, + {"inactive-selection", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION], 18, 0}, + {"placeholder", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER], 11, 0}, + {"after", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER], 5, 0}, + {"first-letter", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER], 12, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"grammar-error", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR], 13, 0}, + {"before", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE], 6, 0}, + {"selection", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION], 9, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"target-text", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT], 11, 0}, + {"first-line", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE], 10, 0}, + {"spelling-error", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR], 14, 0}, + {"backdrop", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP], 8, 0}, + {"marker", (void *) &lxb_css_selectors_pseudo_data_pseudo_element[LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER], 6, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_selectors_pseudo_element_function_shs[6] = +{ + {NULL, NULL, 5, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0} +}; + + +#endif /* LXB_CSS_SELECTOS_PSEUDO_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_state.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_state.c new file mode 100644 index 0000000..dc7dddc --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_state.c @@ -0,0 +1,429 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/selectors/pseudo_state.h" +#include "lexbor/css/selectors/selectors.h" + + +static bool +lxb_css_selectors_state_pseudo_anb(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static bool +lxb_css_selectors_state_pseudo_of_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_selectors_state_pseudo_of_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static bool +lxb_css_selectors_state_pseudo_of_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_comp = { + .prelude = lxb_css_selectors_state_complex_list, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_state_pseudo_of_end +}; + + +lxb_inline bool +lxb_css_selectors_state_pseudo_anb_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + (void) lxb_css_selectors_state_pseudo_anb(parser, token, ctx); + if (parser->status != LXB_STATUS_OK) { + parser->selectors->list = NULL; + parser->selectors->list_last = NULL; + + return lxb_css_parser_failed(parser); + } + + parser->selectors->list = NULL; + + return lxb_css_parser_success(parser); +} + + +bool +lxb_css_selectors_state_pseudo_class_function__undef(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_fail(parser, LXB_STATUS_ERROR_UNEXPECTED_DATA); +} + +bool +lxb_css_selectors_state_pseudo_class_function_current(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_set(parser, lxb_css_selectors_state_complex_list); + + parser->selectors->list = NULL; + parser->selectors->list_last = NULL; + + return true; +} + +bool +lxb_css_selectors_state_pseudo_class_function_dir(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_fail(parser, LXB_STATUS_ERROR_UNEXPECTED_DATA); +} + +bool +lxb_css_selectors_state_pseudo_class_function_has(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_set(parser, lxb_css_selectors_state_relative_list); + + parser->selectors->list = NULL; + parser->selectors->list_last = NULL; + + return true; +} + +bool +lxb_css_selectors_state_pseudo_class_function_is(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_set(parser, lxb_css_selectors_state_complex_list); + + parser->selectors->list = NULL; + parser->selectors->list_last = NULL; + + return true; +} + +bool +lxb_css_selectors_state_pseudo_class_function_lang(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_fail(parser, LXB_STATUS_ERROR_UNEXPECTED_DATA); +} + +bool +lxb_css_selectors_state_pseudo_class_function_not(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_set(parser, lxb_css_selectors_state_complex_list); + + parser->selectors->list = NULL; + parser->selectors->list_last = NULL; + + return true; +} + +bool +lxb_css_selectors_state_pseudo_class_function_nth_child(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_selectors_state_pseudo_of_begin(parser, token, ctx); +} + +bool +lxb_css_selectors_state_pseudo_class_function_nth_col(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_selectors_state_pseudo_anb_begin(parser, token, ctx); +} + +bool +lxb_css_selectors_state_pseudo_class_function_nth_last_child(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_selectors_state_pseudo_of_begin(parser, token, ctx); +} + +bool +lxb_css_selectors_state_pseudo_class_function_nth_last_col(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_selectors_state_pseudo_anb_begin(parser, token, ctx); +} + +bool +lxb_css_selectors_state_pseudo_class_function_nth_last_of_type(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_selectors_state_pseudo_anb_begin(parser, token, ctx); +} + +bool +lxb_css_selectors_state_pseudo_class_function_nth_of_type(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_selectors_state_pseudo_anb_begin(parser, token, ctx); +} + +bool +lxb_css_selectors_state_pseudo_class_function_where(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_set(parser, lxb_css_selectors_state_complex_list); + + parser->selectors->list = NULL; + parser->selectors->list_last = NULL; + + return true; +} + +bool +lxb_css_selectors_state_pseudo_element_function__undef(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return true; +} + +bool +lxb_css_selectors_state_pseudo_class_function_lexbor_contains(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_selectors_t *selectors; + lxb_css_selector_t *selector; + lxb_css_selector_contains_t *contains; + lexbor_str_t *str; + const lxb_char_t *data; + size_t length; + + selectors = parser->selectors; + selector = selectors->list_last->last; + +again: + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_STRING: + data = token->types.string.data; + length = token->types.string.length; + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + data = token->types.ident.data; + length = token->types.ident.length; + break; + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + goto again; + + default: + lxb_css_parser_unexpected_data(parser, token); + return lxb_css_parser_failed(parser); + } + + contains = lexbor_mraw_alloc(parser->memory->mraw, + sizeof(lxb_css_selector_contains_t)); + if (contains == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + contains->insensitive = false; + str = &contains->str; + + str->data = lexbor_mraw_alloc(parser->memory->mraw, length + 1); + if (str->data == NULL) { + lexbor_mraw_free(parser->memory->mraw, contains); + return lxb_css_parser_memory_fail(parser); + } + + memcpy(str->data, data, length); + + str->length = length; + str->data[length] = '\0'; + + selector->u.pseudo.data = contains; + +again_end: + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN__END: + break; + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + goto again_end; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + data = token->types.ident.data; + length = token->types.ident.length; + + if (length == 1 && (*data == 'i' || *data == 'I')) { + contains->insensitive = true; + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN__END) { + goto failed; + } + + break; + } + /* Fall through. */ + + default: + goto failed; + } + + parser->selectors->list = NULL; + + return lxb_css_parser_success(parser); + +failed: + + lexbor_mraw_free(parser->memory->mraw, contains->str.data); + lexbor_mraw_free(parser->memory->mraw, contains); + + selector->u.pseudo.data = NULL; + + lxb_css_parser_unexpected_data(parser, token); + return lxb_css_parser_failed(parser); +} + +static bool +lxb_css_selectors_state_pseudo_anb(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_selectors_t *selectors; + lxb_css_selector_list_t *list; + lxb_css_selector_anb_of_t *anbof; + + selectors = parser->selectors; + + anbof = lexbor_mraw_alloc(parser->memory->mraw, + sizeof(lxb_css_selector_anb_of_t)); + if (anbof == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + parser->status = lxb_css_syntax_anb_handler(parser, token, &anbof->anb); + if (parser->status != LXB_STATUS_OK) { + lexbor_mraw_free(parser->memory->mraw, anbof); + return true; + } + + list = selectors->list_last; + list->last->u.pseudo.data = anbof; + + anbof->of = NULL; + + return true; +} + +static bool +lxb_css_selectors_state_pseudo_of_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_syntax_rule_t *rule; + lxb_css_selectors_t *selectors; + lxb_css_selector_list_t *list; + lxb_css_syntax_token_ident_t *ident; + + static const lxb_char_t of[] = "of"; + + selectors = parser->selectors; + + (void) lxb_css_selectors_state_pseudo_anb(parser, token, ctx); + if (parser->status != LXB_STATUS_OK) { + selectors->list = NULL; + selectors->list_last = NULL; + + token = lxb_css_syntax_parser_token(parser); + if (token == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN__END) { + if (lxb_css_syntax_token_error(parser, token, "Selectors") == NULL) { + return lxb_css_parser_memory_fail(parser); + } + } + + return lxb_css_parser_failed(parser); + } + + list = selectors->list_last; + + selectors->list = NULL; + + lxb_css_parser_token_wo_ws_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + ident = lxb_css_syntax_token_ident(token); + + if (ident->length == sizeof(of) - 1 + && lexbor_str_data_ncasecmp(ident->data, of, ident->length)) + { + lxb_css_syntax_token_consume(parser->tkz); + + selectors->list = NULL; + selectors->list_last = NULL; + + token = lxb_css_syntax_parser_token(parser); + if (token == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + rule = lxb_css_syntax_parser_components_push(parser, + &lxb_css_selectors_comp, + lxb_css_selectors_state_pseudo_of_back, + list, LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); +// rule = lxb_css_syntax_parser_components_push(parser, token, +// lxb_css_selectors_state_pseudo_of_back, +// &lxb_css_selectors_comp, list, +// LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + if (rule == NULL) { + lexbor_mraw_free(parser->memory->mraw, + list->last->u.pseudo.data); + return lxb_css_parser_memory_fail(parser); + } + + lxb_css_parser_state_set(parser, + lxb_css_selectors_state_complex_list); + return true; + } + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_selectors_state_pseudo_of_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_selector_anb_of_t *anbof; + lxb_css_selector_list_t *list = ctx; + + anbof = list->last->u.pseudo.data; + anbof->of = parser->selectors->list; + + parser->selectors->list = NULL; + + return LXB_STATUS_OK; +} + +static bool +lxb_css_selectors_state_pseudo_of_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + parser->selectors->list = NULL; + + return lxb_css_parser_success(parser); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_state.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_state.h new file mode 100644 index 0000000..652e455 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/pseudo_state.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2020-2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SELECTORS_PSEUDO_STATE_H +#define LEXBOR_CSS_SELECTORS_PSEUDO_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/syntax/parser.h" +#include "lexbor/css/selectors/base.h" + + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function__undef(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_current(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_dir(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_has(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_is(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_lang(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_not(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_nth_child(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_nth_col(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_nth_last_child(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_nth_last_col(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_nth_last_of_type(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_nth_of_type(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_where(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_element_function__undef(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_pseudo_class_function_lexbor_contains(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SELECTORS_PSEUDO_STATE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selector.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selector.c new file mode 100644 index 0000000..e29d27b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selector.c @@ -0,0 +1,1002 @@ +/* + * Copyright (C) 2020 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/serialize.h" +#include "lexbor/css/css.h" +#include "lexbor/css/selectors/selectors.h" +#include "lexbor/css/selectors/selector.h" +#include "lexbor/css/selectors/pseudo.h" +#include "lexbor/css/selectors/pseudo_const.h" +#include "lexbor/css/selectors/pseudo_state.h" +#include "lexbor/css/selectors/state.h" +#include "lexbor/css/selectors/pseudo_res.h" + + +typedef void +(*lxb_css_selector_destroy_f)(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +typedef lxb_status_t +(*lxb_css_selector_serialize_f)(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); + + +static void +lxb_css_selector_destroy_undef(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +static void +lxb_css_selector_destroy_any(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +static void +lxb_css_selector_destroy_id(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +static void +lxb_css_selector_destroy_attribute(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +static void +lxb_css_selector_destroy_pseudo(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +static void +lxb_css_selector_destroy_pseudo_class_function(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); +static void +lxb_css_selector_destroy_pseudo_element_function(lxb_css_selector_t *selector, + lxb_css_memory_t *mem); + +static lxb_status_t +lxb_css_selector_serialize_undef(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_any(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_id(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_class(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_attribute(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_pseudo_class(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_pseudo_class_function(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_pseudo_element(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); +static lxb_status_t +lxb_css_selector_serialize_pseudo_element_function(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); + +static lxb_status_t +lxb_css_selector_serialize_pseudo_single(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx, + bool is_class); + + +static const lxb_css_selector_destroy_f + lxb_selector_destroy_map[LXB_CSS_SELECTOR_TYPE__LAST_ENTRY] = +{ + lxb_css_selector_destroy_undef, + lxb_css_selector_destroy_any, + lxb_css_selector_destroy_any, + lxb_css_selector_destroy_id, + lxb_css_selector_destroy_id, + lxb_css_selector_destroy_attribute, + lxb_css_selector_destroy_pseudo, + lxb_css_selector_destroy_pseudo_class_function, + lxb_css_selector_destroy_pseudo, + lxb_css_selector_destroy_pseudo_element_function +}; + +static const lxb_css_selector_serialize_f + lxb_selector_serialize_map[LXB_CSS_SELECTOR_TYPE__LAST_ENTRY] = +{ + lxb_css_selector_serialize_undef, + lxb_css_selector_serialize_any, + lxb_css_selector_serialize_any, + lxb_css_selector_serialize_id, + lxb_css_selector_serialize_class, + lxb_css_selector_serialize_attribute, + lxb_css_selector_serialize_pseudo_class, + lxb_css_selector_serialize_pseudo_class_function, + lxb_css_selector_serialize_pseudo_element, + lxb_css_selector_serialize_pseudo_element_function +}; + + +lxb_css_selector_t * +lxb_css_selector_create(lxb_css_selector_list_t *list) +{ + lxb_css_selector_t *selector = lexbor_dobject_calloc(list->memory->objs); + if (selector == NULL) { + return NULL; + } + + selector->list = list; + + return selector; +} + +void +lxb_css_selector_destroy(lxb_css_selector_t *selector) +{ + lxb_css_memory_t *memory; + + if (selector != NULL) { + memory = selector->list->memory; + + lxb_selector_destroy_map[selector->type](selector, memory); + lexbor_dobject_free(memory->objs, selector); + } +} + +void +lxb_css_selector_destroy_chain(lxb_css_selector_t *selector) +{ + lxb_css_selector_t *next; + + while (selector != NULL) { + next = selector->next; + lxb_css_selector_destroy(selector); + selector = next; + } +} + +void +lxb_css_selector_remove(lxb_css_selector_t *selector) +{ + if (selector->next != NULL) { + selector->next->prev = selector->prev; + } + + if (selector->prev != NULL) { + selector->prev->next = selector->next; + } + + if (selector->list->first == selector) { + selector->list->first = selector->next; + } + + if (selector->list->last == selector) { + selector->list->last = selector->prev; + } +} + +lxb_css_selector_list_t * +lxb_css_selector_list_create(lxb_css_memory_t *mem) +{ + lxb_css_selector_list_t *list; + + list = lexbor_dobject_calloc(mem->objs); + if (list == NULL) { + return NULL; + } + + list->memory = mem; + + return list; +} + +void +lxb_css_selector_list_remove(lxb_css_selector_list_t *list) +{ + if (list->next != NULL) { + list->next->prev = list->prev; + } + + if (list->prev != NULL) { + list->prev->next = list->next; + } +} + +void +lxb_css_selector_list_selectors_remove(lxb_css_selectors_t *selectors, + lxb_css_selector_list_t *list) +{ + lxb_css_selector_list_remove(list); + + if (selectors->list == list) { + selectors->list = list->next; + } + + if (selectors->list_last == list) { + selectors->list_last = list->prev; + } +} + +void +lxb_css_selector_list_destroy(lxb_css_selector_list_t *list) +{ + if (list != NULL) { + lxb_css_selector_destroy_chain(list->first); + lexbor_dobject_free(list->memory->objs, list); + } +} + +void +lxb_css_selector_list_destroy_chain(lxb_css_selector_list_t *list) +{ + lxb_css_selector_list_t *next; + + while (list != NULL) { + next = list->next; + lxb_css_selector_list_destroy(list); + list = next; + } +} + +void +lxb_css_selector_list_destroy_memory(lxb_css_selector_list_t *list) +{ + if (list != NULL) { + (void) lxb_css_memory_destroy(list->memory, true); + } +} + +static void +lxb_css_selector_destroy_undef(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + /* Do nothing. */ +} + +static void +lxb_css_selector_destroy_any(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + if (selector->ns.data != NULL) { + lexbor_mraw_free(mem->mraw, selector->ns.data); + } + + if (selector->name.data != NULL) { + lexbor_mraw_free(mem->mraw, selector->name.data); + } +} + +static void +lxb_css_selector_destroy_id(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + if (selector->name.data != NULL) { + (void) lexbor_mraw_free(mem->mraw, selector->name.data); + } +} + +static void +lxb_css_selector_destroy_attribute(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + if (selector->ns.data != NULL) { + lexbor_mraw_free(mem->mraw, selector->ns.data); + } + + if (selector->name.data != NULL) { + lexbor_mraw_free(mem->mraw, selector->name.data); + } + + if (selector->u.attribute.value.data != NULL) { + lexbor_mraw_free(mem->mraw, selector->u.attribute.value.data); + } +} + +static void +lxb_css_selector_destroy_pseudo(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + if (selector->name.data != NULL) { + lexbor_mraw_free(mem->mraw, selector->name.data); + } +} + +static void +lxb_css_selector_destroy_pseudo_class_function(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + lxb_css_selector_anb_of_t *anbof; + lxb_css_selector_contains_t *contains; + lxb_css_selector_pseudo_t *pseudo; + + pseudo = &selector->u.pseudo; + + switch (pseudo->type) { + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_CURRENT: + break; + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR: + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_HAS: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_IS: + lxb_css_selector_list_destroy_chain(pseudo->data); + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG: + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NOT: + lxb_css_selector_list_destroy_chain(pseudo->data); + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_OF_TYPE: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_OF_TYPE: + anbof = pseudo->data; + + if (anbof != NULL) { + lxb_css_selector_list_destroy_chain(anbof->of); + lexbor_mraw_free(mem->mraw, anbof); + } + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE: + lxb_css_selector_list_destroy_chain(pseudo->data); + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LEXBOR_CONTAINS: + contains = pseudo->data; + + if (contains != NULL) { + if (contains->str.data != NULL) { + lexbor_mraw_free(mem->mraw, contains->str.data); + } + + lexbor_mraw_free(mem->mraw, contains); + } + break; + + default: + break; + } + + lxb_css_selector_destroy_pseudo(selector, mem); +} + +static void +lxb_css_selector_destroy_pseudo_element_function(lxb_css_selector_t *selector, + lxb_css_memory_t *mem) +{ + lxb_css_selector_destroy_pseudo(selector, mem); +} + +lxb_status_t +lxb_css_selector_serialize(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_selector_serialize_map[selector->type](selector, cb, ctx); +} + +lxb_status_t +lxb_css_selector_serialize_chain(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + size_t length; + lxb_char_t *data; + lxb_status_t status; + + if (selector == NULL) { + return LXB_STATUS_OK; + } + + if (selector->combinator > LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + data = lxb_css_selector_combinator(selector, &length); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + lxb_css_selector_serialize_write(data, length); + lxb_css_selector_serialize_write(" ", 1); + } + + status = lxb_css_selector_serialize(selector, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + selector = selector->next; + + while (selector != NULL) { + data = lxb_css_selector_combinator(selector, &length); + if (data == NULL) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + if (length != 0) { + lxb_css_selector_serialize_write(" ", 1); + + if (*data != ' ') { + lxb_css_selector_serialize_write(data, length); + lxb_css_selector_serialize_write(" ", 1); + } + } + + status = lxb_css_selector_serialize(selector, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + selector = selector->next; + } + + return LXB_STATUS_OK; +} + +lxb_char_t * +lxb_css_selector_serialize_chain_char(lxb_css_selector_t *selector, + size_t *out_length) +{ + size_t length = 0; + lxb_status_t status; + lexbor_str_t str; + + status = lxb_css_selector_serialize_chain(selector, lexbor_serialize_length_cb, + &length); + if (status != LXB_STATUS_OK) { + goto failed; + } + + /* + 1 == '\0' */ + str.data = lexbor_malloc(length + 1); + if (str.data == NULL) { + goto failed; + } + + str.length = 0; + + status = lxb_css_selector_serialize_chain(selector, lexbor_serialize_copy_cb, + &str); + if (status != LXB_STATUS_OK) { + lexbor_free(str.data); + goto failed; + } + + str.data[str.length] = '\0'; + + if (out_length != NULL) { + *out_length = str.length; + } + + return str.data; + +failed: + + if (out_length != NULL) { + *out_length = 0; + } + + return NULL; +} + +lxb_status_t +lxb_css_selector_serialize_list(lxb_css_selector_list_t *list, + lexbor_serialize_cb_f cb, void *ctx) +{ + if (list != NULL) { + return lxb_css_selector_serialize_chain(list->first, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_char_t * +lxb_css_selector_serialize_list_char(lxb_css_selector_list_t *list, + size_t *out_length) +{ + size_t length = 0; + lxb_status_t status; + lexbor_str_t str; + + status = lxb_css_selector_serialize_list_chain(list, lexbor_serialize_length_cb, + &length); + if (status != LXB_STATUS_OK) { + goto failed; + } + + /* + 1 == '\0' */ + str.data = lexbor_malloc(length + 1); + if (str.data == NULL) { + goto failed; + } + + str.length = 0; + + status = lxb_css_selector_serialize_list_chain(list, lexbor_serialize_copy_cb, + &str); + if (status != LXB_STATUS_OK) { + lexbor_free(str.data); + goto failed; + } + + str.data[str.length] = '\0'; + + if (out_length != NULL) { + *out_length = str.length; + } + + return str.data; + +failed: + + if (out_length != NULL) { + *out_length = 0; + } + + return NULL; +} + +lxb_status_t +lxb_css_selector_serialize_list_chain(lxb_css_selector_list_t *list, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + if (list == NULL) { + return LXB_STATUS_OK; + } + + status = lxb_css_selector_serialize_chain(list->first, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + list = list->next; + + while (list != NULL) { + lxb_css_selector_serialize_write(", ", 2); + + status = lxb_css_selector_serialize_chain(list->first, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + list = list->next; + } + + return LXB_STATUS_OK; +} + +lxb_char_t * +lxb_css_selector_serialize_list_chain_char(lxb_css_selector_list_t *list, + size_t *out_length) +{ + size_t length = 0; + lxb_status_t status; + lexbor_str_t str; + + status = lxb_css_selector_serialize_list_chain(list, lexbor_serialize_length_cb, + &length); + if (status != LXB_STATUS_OK) { + goto failed; + } + + /* + 1 == '\0' */ + str.data = lexbor_malloc(length + 1); + if (str.data == NULL) { + goto failed; + } + + str.length = 0; + + status = lxb_css_selector_serialize_list_chain(list, lexbor_serialize_copy_cb, + &str); + if (status != LXB_STATUS_OK) { + lexbor_free(str.data); + goto failed; + } + + str.data[str.length] = '\0'; + + if (out_length != NULL) { + *out_length = str.length; + } + + return str.data; + +failed: + + if (out_length != NULL) { + *out_length = 0; + } + + return NULL; +} + + +static lxb_status_t +lxb_css_selector_serialize_undef(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + return LXB_STATUS_ERROR_UNEXPECTED_DATA; +} + +static lxb_status_t +lxb_css_selector_serialize_any(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + if (selector->ns.data != NULL) { + lxb_css_selector_serialize_write(selector->ns.data, + selector->ns.length); + lxb_css_selector_serialize_write("|", 1); + } + + if (selector->name.data != NULL) { + return cb(selector->name.data, selector->name.length, ctx); + } + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selector_serialize_id(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + lxb_css_selector_serialize_write("#", 1); + + if (selector->name.data != NULL) { + return cb(selector->name.data, selector->name.length, ctx); + } + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selector_serialize_class(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + lxb_css_selector_serialize_write(".", 1); + + if (selector->name.data != NULL) { + return cb(selector->name.data, selector->name.length, ctx); + } + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selector_serialize_escape_write(lxb_char_t *p, lxb_char_t *end, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_char_t *begin; + lxb_status_t status; + + begin = p; + + lxb_css_selector_serialize_write("\"", 1); + + while (p < end) { + if (*p == '"') { + if (begin < p) { + lxb_css_selector_serialize_write(begin, p - begin); + } + + lxb_css_selector_serialize_write("\\000022", 7); + + begin = p + 1; + } + + p++; + } + + if (begin < p) { + lxb_css_selector_serialize_write(begin, p - begin); + } + + lxb_css_selector_serialize_write("\"", 1); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selector_serialize_attribute(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_char_t *p, *end; + lxb_status_t status; + lxb_css_selector_attribute_t *attr; + + lxb_css_selector_serialize_write("[", 1); + + status = lxb_css_selector_serialize_any(selector, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + attr = &selector->u.attribute; + + if (attr->value.data == NULL) { + return cb((lxb_char_t *) "]", 1, ctx); + } + + switch (attr->match) { + case LXB_CSS_SELECTOR_MATCH_EQUAL: + lxb_css_selector_serialize_write("=", 1); + break; + case LXB_CSS_SELECTOR_MATCH_INCLUDE: + lxb_css_selector_serialize_write("~=", 2); + break; + case LXB_CSS_SELECTOR_MATCH_DASH: + lxb_css_selector_serialize_write("|=", 2); + break; + case LXB_CSS_SELECTOR_MATCH_PREFIX: + lxb_css_selector_serialize_write("^=", 2); + break; + case LXB_CSS_SELECTOR_MATCH_SUFFIX: + lxb_css_selector_serialize_write("$=", 2); + break; + case LXB_CSS_SELECTOR_MATCH_SUBSTRING: + lxb_css_selector_serialize_write("*=", 2); + break; + + default: + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + p = attr->value.data; + end = attr->value.data + attr->value.length; + + status = lxb_css_selector_serialize_escape_write(p, end, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (attr->modifier != LXB_CSS_SELECTOR_MODIFIER_UNSET) { + switch (attr->modifier) { + case LXB_CSS_SELECTOR_MODIFIER_I: + lxb_css_selector_serialize_write("i", 1); + break; + + case LXB_CSS_SELECTOR_MODIFIER_S: + lxb_css_selector_serialize_write("s", 1); + break; + + default: + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + } + + return cb((lxb_char_t *) "]", 1, ctx); +} + +static lxb_status_t +lxb_css_selector_serialize_pseudo_class(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_selector_serialize_pseudo_single(selector, cb, ctx, true); +} + +static lxb_status_t +lxb_css_selector_serialize_pseudo_class_function(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + lxb_char_t *p, *end; + lxb_css_selector_pseudo_t *pseudo; + lxb_css_selector_contains_t *contains; + const lxb_css_selectors_pseudo_data_func_t *pfunc; + + pseudo = &selector->u.pseudo; + + pfunc = &lxb_css_selectors_pseudo_data_pseudo_class_function[pseudo->type]; + + lxb_css_selector_serialize_write(":", 1); + lxb_css_selector_serialize_write(pfunc->name, pfunc->length); + lxb_css_selector_serialize_write("(", 1); + + switch (pseudo->type) { + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_CURRENT: + break; + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR: + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_HAS: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_IS: + status = lxb_css_selector_serialize_list_chain(pseudo->data, + cb, ctx); + break; + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG: + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NOT: + status = lxb_css_selector_serialize_list_chain(pseudo->data, + cb, ctx); + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_OF_TYPE: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_OF_TYPE: + status = LXB_STATUS_OK; + + if (pseudo->data != NULL) { + status = lxb_css_selector_serialize_anb_of(pseudo->data, + cb, ctx); + } + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE: + status = lxb_css_selector_serialize_list_chain(pseudo->data, + cb, ctx); + break; + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LEXBOR_CONTAINS: + contains = pseudo->data; + p = contains->str.data; + end = p + contains->str.length; + + status = lxb_css_selector_serialize_escape_write(p, end, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (contains->insensitive) { + lxb_css_selector_serialize_write(" i", 2); + } + + break; + + default: + status = LXB_STATUS_OK; + break; + } + + if (status != LXB_STATUS_OK) { + return status; + } + + lxb_css_selector_serialize_write(")", 1); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selector_serialize_pseudo_element(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + return lxb_css_selector_serialize_pseudo_single(selector, cb, ctx, false); +} + +static lxb_status_t +lxb_css_selector_serialize_pseudo_element_function(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx) +{ + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selector_serialize_pseudo_single(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx, + bool is_class) +{ + lxb_status_t status; + lxb_css_selector_pseudo_t *pseudo; + const lxb_css_selectors_pseudo_data_t *pclass; + + pseudo = &selector->u.pseudo; + + if (is_class) { + pclass = &lxb_css_selectors_pseudo_data_pseudo_class[pseudo->type]; + lxb_css_selector_serialize_write(":", 1); + } + else { + pclass = &lxb_css_selectors_pseudo_data_pseudo_element[pseudo->type]; + lxb_css_selector_serialize_write("::", 2); + } + + lxb_css_selector_serialize_write(pclass->name, pclass->length); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_selector_serialize_anb_of(lxb_css_selector_anb_of_t *anbof, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + + static const lxb_char_t of[] = " of "; + + status = lxb_css_syntax_anb_serialize(&anbof->anb, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (anbof->of != NULL) { + lxb_css_selector_serialize_write(of, sizeof(of) - 1); + + return lxb_css_selector_serialize_list_chain(anbof->of, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_char_t * +lxb_css_selector_combinator(lxb_css_selector_t *selector, size_t *out_length) +{ + switch (selector->combinator) { + case LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT: + if (out_length != NULL) {*out_length = 1;} + return (lxb_char_t *) " "; + + case LXB_CSS_SELECTOR_COMBINATOR_CLOSE: + if (out_length != NULL) {*out_length = 0;} + return (lxb_char_t *) ""; + + case LXB_CSS_SELECTOR_COMBINATOR_CHILD: + if (out_length != NULL) {*out_length = 1;} + return (lxb_char_t *) ">"; + + case LXB_CSS_SELECTOR_COMBINATOR_SIBLING: + if (out_length != NULL) {*out_length = 1;} + return (lxb_char_t *) "+"; + + case LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING: + if (out_length != NULL) {*out_length = 1;} + return (lxb_char_t *) "~"; + + case LXB_CSS_SELECTOR_COMBINATOR_CELL: + if (out_length != NULL) {*out_length = 2;} + return (lxb_char_t *) "||"; + + default: + if (out_length != NULL) {*out_length = 0;} + return NULL; + } +} + +void +lxb_css_selector_list_append(lxb_css_selector_list_t *list, + lxb_css_selector_t *selector) +{ + selector->prev = list->last; + + if (list->last != NULL) { + list->last->next = selector; + } + else { + list->first = selector; + } + + list->last = selector; +} + +void +lxb_css_selector_append_next(lxb_css_selector_t *dist, lxb_css_selector_t *src) +{ + if (dist->next != NULL) { + dist->next->prev = src; + } + + src->prev = dist; + src->next = dist->next; + + dist->next = src; +} + +void +lxb_css_selector_list_append_next(lxb_css_selector_list_t *dist, + lxb_css_selector_list_t *src) +{ + if (dist->next != NULL) { + dist->next->prev = src; + } + + src->prev = dist; + src->next = dist->next; + + dist->next = src; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selector.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selector.h new file mode 100644 index 0000000..a5d373f --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selector.h @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SELECTORS_SELECTOR_H +#define LEXBOR_CSS_SELECTORS_SELECTOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/str.h" +#include "lexbor/css/selectors/base.h" +#include "lexbor/css/syntax/anb.h" + + +typedef enum { + LXB_CSS_SELECTOR_TYPE__UNDEF = 0x00, + LXB_CSS_SELECTOR_TYPE_ANY, + LXB_CSS_SELECTOR_TYPE_ELEMENT, /* div, tag name
*/ + LXB_CSS_SELECTOR_TYPE_ID, /* #hash */ + LXB_CSS_SELECTOR_TYPE_CLASS, /* .class */ + LXB_CSS_SELECTOR_TYPE_ATTRIBUTE, /* [key=val], <... key="val"> */ + LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS, /* :pseudo */ + LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION, /* :function(...) */ + LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT, /* ::pseudo */ + LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT_FUNCTION, /* ::function(...) */ + LXB_CSS_SELECTOR_TYPE__LAST_ENTRY +} +lxb_css_selector_type_t; + +typedef enum { + LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT = 0x00, /* WHITESPACE */ + LXB_CSS_SELECTOR_COMBINATOR_CLOSE, /* two compound selectors [key=val].foo */ + LXB_CSS_SELECTOR_COMBINATOR_CHILD, /* '>' */ + LXB_CSS_SELECTOR_COMBINATOR_SIBLING, /* '+' */ + LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING, /* '~' */ + LXB_CSS_SELECTOR_COMBINATOR_CELL, /* '||' */ + LXB_CSS_SELECTOR_COMBINATOR__LAST_ENTRY +} +lxb_css_selector_combinator_t; + +typedef enum { + LXB_CSS_SELECTOR_MATCH_EQUAL = 0x00, /* = */ + LXB_CSS_SELECTOR_MATCH_INCLUDE, /* ~= */ + LXB_CSS_SELECTOR_MATCH_DASH, /* |= */ + LXB_CSS_SELECTOR_MATCH_PREFIX, /* ^= */ + LXB_CSS_SELECTOR_MATCH_SUFFIX, /* $= */ + LXB_CSS_SELECTOR_MATCH_SUBSTRING, /* *= */ + LXB_CSS_SELECTOR_MATCH__LAST_ENTRY +} +lxb_css_selector_match_t; + +typedef enum { + LXB_CSS_SELECTOR_MODIFIER_UNSET = 0x00, + LXB_CSS_SELECTOR_MODIFIER_I, + LXB_CSS_SELECTOR_MODIFIER_S, + LXB_CSS_SELECTOR_MODIFIER__LAST_ENTRY +} +lxb_css_selector_modifier_t; + +typedef struct { + lxb_css_selector_match_t match; + lxb_css_selector_modifier_t modifier; + lexbor_str_t value; +} +lxb_css_selector_attribute_t; + +typedef struct { + unsigned type; + void *data; +} +lxb_css_selector_pseudo_t; + +typedef struct { + lxb_css_syntax_anb_t anb; + lxb_css_selector_list_t *of; +} +lxb_css_selector_anb_of_t; + +typedef struct { + lexbor_str_t str; + bool insensitive; +} +lxb_css_selector_contains_t; + +struct lxb_css_selector { + lxb_css_selector_type_t type; + lxb_css_selector_combinator_t combinator; + + lexbor_str_t name; + lexbor_str_t ns; + + union lxb_css_selector_u { + lxb_css_selector_attribute_t attribute; + lxb_css_selector_pseudo_t pseudo; + } + u; + + lxb_css_selector_t *next; + lxb_css_selector_t *prev; + + lxb_css_selector_list_t *list; +}; + + +/* + * I S A B C + * 1 bit | 1 bit | 9 bit | 9 bit | 9 bit + */ +typedef uint32_t lxb_css_selector_specificity_t; + +#define LXB_CSS_SELECTOR_SPECIFICITY_MASK_N(sp, n) \ + ((sp) & ~((((uint32_t) 1 << 9) - 1) << (n))) + +#define LXB_CSS_SELECTOR_SPECIFICITY_MASK \ + ((((uint32_t) 1 << (32 - 9)) - 1) << (9)) + +/* + * CSS Selector Specificity field accessors. + * + * Specificity is packed into a single uint32_t: + * bits [31..28] — i: !important flag (1 = declaration is !important) + * bit [27] — s: style attribute flag (1 = from element's style="...") + * bits [26..18] — a: count of ID selectors + * bits [17..9] — b: count of class selectors, attribute selectors, + * and pseudo-classes + * bits [8..0] — c: count of type selectors and pseudo-elements + * + * Per CSS cascade order: !important > style attribute > (a, b, c). + */ + +/* Extract the !important flag (bits 31..28). */ +#define lxb_css_selector_sp_i(sp) ((sp) >> 28) + +/* Extract the style attribute flag (bit 27). */ +#define lxb_css_selector_sp_s(sp) \ + (((sp) >> 27) & ~((((uint32_t) 1 << 31) - 1) << (1))) + +/* Extract the ID selector count — component "a" (bits 26..18). */ +#define lxb_css_selector_sp_a(sp) \ + (((sp) >> 18) & ~LXB_CSS_SELECTOR_SPECIFICITY_MASK) + +/* Extract the class/attribute/pseudo-class count — component "b" (bits 17..9). */ +#define lxb_css_selector_sp_b(sp) \ + (((sp) >> 9) & ~LXB_CSS_SELECTOR_SPECIFICITY_MASK) + +/* Extract the type/pseudo-element count — component "c" (bits 8..0). */ +#define lxb_css_selector_sp_c(sp) \ + ((sp) & ~LXB_CSS_SELECTOR_SPECIFICITY_MASK) + +#define lxb_css_selector_sp_set_i(sp, num) \ + sp = (LXB_CSS_SELECTOR_SPECIFICITY_MASK_N((sp), 28) | ((num) << 28)) + +#define lxb_css_selector_sp_set_s(sp, num) \ + sp = (LXB_CSS_SELECTOR_SPECIFICITY_MASK_N((sp), 27) | ((num) << 27)) + +#define lxb_css_selector_sp_set_a(sp, num) \ + sp = (LXB_CSS_SELECTOR_SPECIFICITY_MASK_N((sp), 18) | ((num) << 18)) + +#define lxb_css_selector_sp_set_b(sp, num) \ + sp = (LXB_CSS_SELECTOR_SPECIFICITY_MASK_N((sp), 9) | ((num) << 9)) + +#define lxb_css_selector_sp_set_c(sp, num) \ + sp = (LXB_CSS_SELECTOR_SPECIFICITY_MASK_N((sp), 0) | (num)) + +#define lxb_css_selector_sp_add_s(sp, num) \ + (lxb_css_selector_sp_set_s((sp), lxb_css_selector_sp_s(sp) + num)) + +#define lxb_css_selector_sp_add_a(sp, num) \ + (lxb_css_selector_sp_set_a((sp), lxb_css_selector_sp_a(sp) + num)) + +#define lxb_css_selector_sp_add_b(sp, num) \ + (lxb_css_selector_sp_set_b((sp), lxb_css_selector_sp_b(sp) + num)) + +#define lxb_css_selector_sp_add_c(sp, num) \ + (lxb_css_selector_sp_set_c((sp), lxb_css_selector_sp_c(sp) + num)) + +#define lxb_css_selector_sp_up_i(num) (num | (1 << 28)) +#define lxb_css_selector_sp_up_s(num) (num | (1 << 27)) + +#define LXB_CSS_SELECTOR_SP_S_MAX ((1 << 28) - 1) +#define LXB_CSS_SELECTOR_SP_A_MAX ((1 << 27) - 1) +#define LXB_CSS_SELECTOR_SP_B_MAX ((1 << 18) - 1) +#define LXB_CSS_SELECTOR_SP_C_MAX ((1 << 9) - 1) + + +struct lxb_css_selector_list { + lxb_css_selector_t *first; + lxb_css_selector_t *last; + + lxb_css_selector_t *parent; + + lxb_css_selector_list_t *next; + lxb_css_selector_list_t *prev; + + lxb_css_memory_t *memory; + + lxb_css_selector_specificity_t specificity; +}; + + +LXB_API lxb_css_selector_t * +lxb_css_selector_create(lxb_css_selector_list_t *list); + +LXB_API void +lxb_css_selector_destroy(lxb_css_selector_t *selector); + +LXB_API void +lxb_css_selector_destroy_chain(lxb_css_selector_t *selector); + +LXB_API void +lxb_css_selector_remove(lxb_css_selector_t *selector); + +LXB_API lxb_css_selector_list_t * +lxb_css_selector_list_create(lxb_css_memory_t *mem); + +LXB_API void +lxb_css_selector_list_remove(lxb_css_selector_list_t *list); + +LXB_API void +lxb_css_selector_list_selectors_remove(lxb_css_selectors_t *selectors, + lxb_css_selector_list_t *list); + +LXB_API void +lxb_css_selector_list_destroy(lxb_css_selector_list_t *list); + +LXB_API void +lxb_css_selector_list_destroy_chain(lxb_css_selector_list_t *list); + +LXB_API void +lxb_css_selector_list_destroy_memory(lxb_css_selector_list_t *list); + +LXB_API lxb_status_t +lxb_css_selector_serialize(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_selector_serialize_chain(lxb_css_selector_t *selector, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_char_t * +lxb_css_selector_serialize_chain_char(lxb_css_selector_t *selector, + size_t *out_length); + +LXB_API lxb_status_t +lxb_css_selector_serialize_list(lxb_css_selector_list_t *list, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_selector_serialize_list_chain(lxb_css_selector_list_t *list, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_char_t * +lxb_css_selector_serialize_list_chain_char(lxb_css_selector_list_t *list, + size_t *out_length); + +LXB_API lxb_status_t +lxb_css_selector_serialize_anb_of(lxb_css_selector_anb_of_t *anbof, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_char_t * +lxb_css_selector_combinator(lxb_css_selector_t *selector, size_t *out_length); + +LXB_API void +lxb_css_selector_list_append(lxb_css_selector_list_t *list, + lxb_css_selector_t *selector); + +LXB_API void +lxb_css_selector_list_append_next(lxb_css_selector_list_t *dist, + lxb_css_selector_list_t *src); + +LXB_API void +lxb_css_selector_append_next(lxb_css_selector_t *dist, lxb_css_selector_t *src); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SELECTORS_SELECTOR_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selectors.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selectors.c new file mode 100644 index 0000000..77586f4 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selectors.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/print.h" +#include "lexbor/css/css.h" + + +static lxb_css_selector_list_t * +lxb_css_selectors_parse_list(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_components_t *components, + const lxb_char_t *data, size_t length); + +static lxb_status_t +lxb_css_selectors_components_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_complex_list_cb = { + .prelude = lxb_css_selectors_state_complex_list, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_compound_list_cb = { + .prelude = lxb_css_selectors_state_compound_list, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_simple_list_cb = { + .prelude = lxb_css_selectors_state_simple_list, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_relative_list_cb = { + .prelude = lxb_css_selectors_state_relative_list, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_complex_cb = { + .prelude = lxb_css_selectors_state_complex, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_compound_cb = { + .prelude = lxb_css_selectors_state_compound, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_simple_cb = { + .prelude = lxb_css_selectors_state_simple, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + +static const lxb_css_syntax_cb_components_t lxb_css_selectors_relative_cb = { + .prelude = lxb_css_selectors_state_relative, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_selectors_components_end +}; + + +lxb_css_selectors_t * +lxb_css_selectors_create(void) +{ + return lexbor_calloc(1, sizeof(lxb_css_selectors_t)); +} + +lxb_status_t +lxb_css_selectors_init(lxb_css_selectors_t *selectors) +{ + if (selectors == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + selectors->list = NULL; + selectors->list_last = NULL; + selectors->parent = NULL; + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + selectors->comb_default = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + selectors->error = 0; + selectors->err_in_function = false; + selectors->failed = false; + + return LXB_STATUS_OK; +} + +void +lxb_css_selectors_clean(lxb_css_selectors_t *selectors) +{ + if (selectors != NULL) { + selectors->list = NULL; + selectors->list_last = NULL; + selectors->parent = NULL; + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + selectors->comb_default = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + selectors->error = 0; + selectors->err_in_function = false; + selectors->failed = false; + } +} + +lxb_css_selectors_t * +lxb_css_selectors_destroy(lxb_css_selectors_t *selectors, bool self_destroy) +{ + if (selectors == NULL) { + return NULL; + } + + if (self_destroy) { + return lexbor_free(selectors); + } + + return selectors; +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_complex_list(parser, data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_complex_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_complex_list_cb, + data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_compound_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_compound_list_cb, + data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_simple_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_simple_list_cb, + data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_relative_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_relative_list_cb, + data, length); +} + +static lxb_status_t +lxb_css_selectors_parse_prepare(lxb_css_parser_t *parser) +{ + if (parser->stage != LXB_CSS_PARSER_CLEAN) { + if (parser->stage == LXB_CSS_PARSER_RUN) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + lxb_css_parser_clean(parser); + } + + parser->tkz->with_comment = false; + parser->stage = LXB_CSS_PARSER_RUN; + + return LXB_STATUS_OK; +} + +static lxb_css_selector_list_t * +lxb_css_selectors_parse_process(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_components_t *components, + const lxb_char_t *data, size_t length) +{ + lxb_css_syntax_rule_t *rule; + + lxb_css_parser_buffer_set(parser, data, length); + + rule = lxb_css_syntax_parser_components_push(parser, components, NULL, NULL, + LXB_CSS_SYNTAX_TOKEN_UNDEF); + if (rule == NULL) { + return NULL; + } + + parser->status = lxb_css_syntax_parser_run(parser); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + + return parser->selectors->list; +} + +static void +lxb_css_selectors_parse_finish(lxb_css_parser_t *parser) +{ + parser->stage = LXB_CSS_PARSER_END; +} + +static lxb_css_selector_list_t * +lxb_css_selectors_parse_list(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_components_t *components, + const lxb_char_t *data, size_t length) +{ + bool my_mem, my_selectors; + lxb_css_selector_list_t *list; + + my_mem = false; + my_selectors = false; + + if (parser->selectors == NULL) { + parser->selectors = lxb_css_selectors_create(); + parser->status = lxb_css_selectors_init(parser->selectors); + + if (parser->status != LXB_STATUS_OK) { + (void) lxb_css_selectors_destroy(parser->selectors, true); + return NULL; + } + + my_selectors = true; + } + else { + lxb_css_selectors_clean(parser->selectors); + } + + if (parser->memory == NULL) { + parser->memory = lxb_css_memory_create(); + parser->status = lxb_css_memory_init(parser->memory, 256); + + if (parser->status != LXB_STATUS_OK) { + if (my_selectors) { + parser->selectors = lxb_css_selectors_destroy(parser->selectors, + true); + } + + (void) lxb_css_memory_destroy(parser->memory, true); + return NULL; + } + + my_mem = true; + } + + parser->status = lxb_css_selectors_parse_prepare(parser); + if (parser->status != LXB_STATUS_OK) { + list = NULL; + goto end; + } + + list = lxb_css_selectors_parse_process(parser, components, data, length); + + lxb_css_selectors_parse_finish(parser); + +end: + + if (list == NULL && my_mem) { + parser->memory = lxb_css_memory_destroy(parser->memory, true); + } + + if (my_selectors) { + parser->selectors = lxb_css_selectors_destroy(parser->selectors, true); + } + + return list; +} + +static lxb_status_t +lxb_css_selectors_components_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_selector_list_t *list; + lxb_css_selectors_t *selectors = parser->selectors; + + if (failed) { + list = selectors->list_last; + + if (list != NULL) { + lxb_css_selector_list_selectors_remove(selectors, list); + lxb_css_selector_list_destroy(list); + } + } + + return LXB_STATUS_OK; +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_complex(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_complex_cb, + data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_compound(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_compound_cb, + data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_simple(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_simple_cb, + data, length); +} + +lxb_css_selector_list_t * +lxb_css_selectors_parse_relative(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + return lxb_css_selectors_parse_list(parser, &lxb_css_selectors_relative_cb, + data, length); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selectors.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selectors.h new file mode 100644 index 0000000..2adfecc --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/selectors.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2020-2022 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SELECTORS_H +#define LEXBOR_CSS_SELECTORS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/dobject.h" +#include "lexbor/css/base.h" +#include "lexbor/css/syntax/parser.h" +#include "lexbor/css/syntax/syntax.h" +#include "lexbor/css/selectors/base.h" +#include "lexbor/css/selectors/selector.h" +#include "lexbor/css/selectors/pseudo_const.h" + + +struct lxb_css_selectors { + lxb_css_selector_list_t *list; + lxb_css_selector_list_t *list_last; + + lxb_css_selector_t *parent; + + lxb_css_selector_combinator_t combinator; + lxb_css_selector_combinator_t comb_default; + + uintptr_t error; + bool status; + bool err_in_function; + bool failed; +}; + + +LXB_API lxb_css_selectors_t * +lxb_css_selectors_create(void); + +LXB_API lxb_status_t +lxb_css_selectors_init(lxb_css_selectors_t *selectors); + +LXB_API void +lxb_css_selectors_clean(lxb_css_selectors_t *selectors); + +LXB_API lxb_css_selectors_t * +lxb_css_selectors_destroy(lxb_css_selectors_t *selectors, bool self_destroy); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_complex_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_compound_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_simple_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_relative_list(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_complex(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_compound(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_simple(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_selector_list_t * +lxb_css_selectors_parse_relative(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +/* + * Inline functions + */ +lxb_inline void +lxb_css_selectors_append_next(lxb_css_selectors_t *selectors, + lxb_css_selector_t *selector) +{ + if (selectors->list_last->last != NULL) { + lxb_css_selector_append_next(selectors->list_last->last, selector); + } + else { + selectors->list_last->first = selector; + } + + selectors->list_last->last = selector; +} + +lxb_inline void +lxb_css_selectors_list_append_next(lxb_css_selectors_t *selectors, + lxb_css_selector_list_t *list) +{ + if (selectors->list_last != NULL) { + lxb_css_selector_list_append_next(selectors->list_last, list); + } + else { + selectors->list = list; + } + + selectors->list_last = list; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SELECTORS_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/state.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/state.c new file mode 100644 index 0000000..3ebdfbe --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/state.c @@ -0,0 +1,2060 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/parser.h" +#include "lexbor/css/css.h" +#include "lexbor/css/selectors/selectors.h" +#include "lexbor/css/selectors/pseudo.h" +#include "lexbor/css/selectors/pseudo_const.h" + + +static const char lxb_css_selectors_module_name[] = "Selectors"; + + +#define lxb_css_selectors_state_string_dup_m(selectors, name) \ + do { \ + (status) = lxb_css_syntax_token_string_dup( \ + lxb_css_syntax_token_string(token), (name), \ + (parser)->memory->mraw); \ + if ((status) != LXB_STATUS_OK) { \ + return (status); \ + } \ + } \ + while (false) + +#define lxb_css_selectors_state_append(parser, selectors, selector) \ + do { \ + (selector) = lxb_css_selector_create((selectors)->list_last); \ + if ((selector) == NULL) { \ + return lxb_css_parser_memory_fail(parser); \ + } \ + \ + lxb_css_selectors_append_next((selectors), (selector)); \ + \ + (selector)->combinator = (selectors)->combinator; \ + (selectors)->combinator = LXB_CSS_SELECTOR_COMBINATOR_CLOSE; \ + } \ + while (false) + +#define lxb_css_selectors_state_list_append(parser, selectors, list) \ + do { \ + (list) = lxb_css_selector_list_create((parser)->memory); \ + if ((list) == NULL) { \ + return lxb_css_parser_memory_fail(parser); \ + } \ + \ + lxb_css_selectors_list_append_next((selectors), (list)); \ + \ + (list)->parent = selectors->parent; \ + } \ + while (false) + + +static bool +lxb_css_selectors_state_complex_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_relative_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_relative_list_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_relative_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_relative_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool list, bool root); + +static bool +lxb_css_selectors_state_complex_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_complex_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_complex_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool root); + +static bool +lxb_css_selectors_state_compound_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_compound_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_compound_sub(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_simple_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_simple_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static bool +lxb_css_selectors_state_simple_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static lxb_status_t +lxb_css_selectors_state_hash(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_selectors_state_class(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_selectors_state_element_ns(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_selectors_state_element(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_selectors_state_attribute(lxb_css_parser_t *parser); + +static lxb_status_t +lxb_css_selectors_state_ns(lxb_css_parser_t *parser, + lxb_css_selector_t *selector); + +static lxb_status_t +lxb_css_selectors_state_ns_ident(lxb_css_parser_t *parser, + lxb_css_selector_t *selector); + +static lxb_status_t +lxb_css_selectors_state_pseudo_class(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_selectors_state_pseudo_class_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_parser_state_f success); + +static lxb_status_t +lxb_css_selectors_state_pseudo_element(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_selectors_state_pseudo_element_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_parser_state_f success); + +static lxb_status_t +lxb_css_selectors_state_forgiving_cb(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, lxb_css_parser_state_f state, + bool failed); + +static void +lxb_css_selectors_state_restore_parent(lxb_css_selectors_t *selectors, + lxb_css_selector_list_t *last); + +static bool +lxb_css_selectors_state_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_parser_state_f state); + +static bool +lxb_css_selectors_state_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static const lxb_css_syntax_token_t * +lxb_css_selectors_state_function_error(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + + +lxb_inline bool +lxb_css_selectors_done(lxb_css_parser_t *parser) +{ + lxb_css_parser_states_pop(parser); + + return lxb_css_parser_states_set_back(parser); +} + +lxb_inline void +lxb_css_selectors_state_specificity_set_b(lxb_css_selectors_t *selectors) +{ + lxb_css_selector_list_t *last = selectors->list_last; + + if (selectors->parent == NULL) { + lxb_css_selector_sp_set_b(last->specificity, + lxb_css_selector_sp_b(last->specificity) + 1); + } + else if (last->specificity > LXB_CSS_SELECTOR_SP_B_MAX) { + if (selectors->combinator == LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + lxb_css_selector_sp_set_b(last->specificity, 1); + } + } + else { + if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + last->specificity = 0; + } + + lxb_css_selector_sp_set_b(last->specificity, 1); + } +} + +lxb_inline void +lxb_css_selectors_state_specificity_set_c(lxb_css_selectors_t *selectors) +{ + lxb_css_selector_list_t *last = selectors->list_last; + + if (selectors->parent == NULL) { + lxb_css_selector_sp_set_c(last->specificity, + lxb_css_selector_sp_c(last->specificity) + 1); + } + else if (last->specificity > LXB_CSS_SELECTOR_SP_C_MAX) { + if (selectors->combinator == LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + lxb_css_selector_sp_set_c(last->specificity, 1); + } + } + else { + if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + last->specificity = 0; + } + + lxb_css_selector_sp_set_c(last->specificity, 1); + } +} + +lxb_inline void +lxb_css_selectors_state_func_specificity(lxb_css_selectors_t *selectors) +{ + lxb_css_selector_list_t *prev, *last; + + last = selectors->list_last; + prev = last->prev; + + if (prev->specificity > last->specificity) { + last->specificity = prev->specificity; + } + + prev->specificity = 0; +} + +/* + * + */ +bool +lxb_css_selectors_state_complex_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_complex_wo_root, + lxb_css_selectors_state_complex_list_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_complex_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_list_end(parser, token, + lxb_css_selectors_state_complex_wo_root); +} + +/* + * + */ +bool +lxb_css_selectors_state_relative_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_relative_list_wo_root, + lxb_css_selectors_state_relative_list_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_relative_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_list_end(parser, token, + lxb_css_selectors_state_relative_list_wo_root); +} + +/* + * + */ +bool +lxb_css_selectors_state_relative(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_relative_wo_root, + lxb_css_selectors_state_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_relative_list_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_relative_handler(parser, token, ctx, true, + false); +} + +static bool +lxb_css_selectors_state_relative_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_relative_handler(parser, token, ctx, false, + false); +} + +static bool +lxb_css_selectors_state_relative_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool list, bool root) +{ + lxb_css_parser_state_f back; + lxb_css_parser_state_t *states; + lxb_css_selectors_t *selectors = parser->selectors; + + /* */ + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + return true; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + switch (lxb_css_syntax_token_delim_char(token)) { + case '>': + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CHILD; + break; + + case '+': + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_SIBLING; + break; + + case '~': + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING; + break; + + case '|': + lxb_css_parser_token_next_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM + && lxb_css_syntax_token_delim_char(token) == '|') + { + lxb_css_syntax_parser_consume(parser); + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CELL; + break; + } + + goto done; + + default: + goto done; + } + + break; + + default: + goto done; + } + + lxb_css_syntax_parser_consume(parser); + +done: + + back = (list) ? lxb_css_selectors_state_complex_end + : lxb_css_selectors_state_end; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_compound_wo_root, + back, ctx, root); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return true; +} + +/* + * + */ +bool +lxb_css_selectors_state_complex(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_complex_wo_root, + lxb_css_selectors_state_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_complex_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_complex_handler(parser, token, ctx, false); +} + +static bool +lxb_css_selectors_state_complex_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool root) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_compound_wo_root, + lxb_css_selectors_state_complex_end, + ctx, root); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_complex_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_selectors_t *selectors = parser->selectors; + + /* */ + +again: + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + + lxb_css_parser_token_m(parser, token); + goto again; + + case LXB_CSS_SYNTAX_TOKEN__END: + return lxb_css_selectors_done(parser); + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + switch (lxb_css_syntax_token_delim_char(token)) { + case '>': + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CHILD; + break; + + case '+': + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_SIBLING; + break; + + case '~': + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_FOLLOWING; + break; + + case '|': + lxb_css_parser_token_next_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM + && lxb_css_syntax_token_delim_char(token) == '|') + { + lxb_css_syntax_parser_consume(parser); + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CELL; + break; + } + + goto done; + + default: + if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT) { + goto unexpected; + } + + goto done; + } + + break; + + case LXB_CSS_SYNTAX_TOKEN_COMMA: + return lxb_css_selectors_done(parser); + + default: + if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT) { + goto unexpected; + } + + goto done; + } + + lxb_css_syntax_parser_consume(parser); + +done: + + lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_handler); + + return true; + +unexpected: + + (void) lxb_css_selectors_done(parser); + + return lxb_css_parser_unexpected(parser); +} + +/* + * + */ +bool +lxb_css_selectors_state_compound_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_compound_wo_root, + lxb_css_selectors_state_compound_list_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_compound_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_list_end(parser, token, + lxb_css_selectors_state_compound_wo_root); +} + +/* + * + * + */ +bool +lxb_css_selectors_state_compound(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_compound_wo_root, + lxb_css_selectors_state_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_compound_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_selector_list_t *list; + + lxb_css_selectors_state_list_append(parser, parser->selectors, list); + + lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_handler); + + return false; +} + +static bool +lxb_css_selectors_state_compound_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_status_t status; + lxb_css_selectors_t *selectors; + +again: + + lxb_css_parser_state_set(parser, lxb_css_selectors_state_compound_sub); + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_HASH: + status = lxb_css_selectors_state_hash(parser, token); + break; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + switch (lxb_css_syntax_token_delim_char(token)) { + case '.': + lxb_css_syntax_parser_consume(parser); + status = lxb_css_selectors_state_class(parser, token); + break; + + case '|': + case '*': + status = lxb_css_selectors_state_element_ns(parser, token); + break; + + default: + goto unexpected; + } + + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + status = lxb_css_selectors_state_element(parser, token); + break; + + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + lxb_css_syntax_parser_consume(parser); + status = lxb_css_selectors_state_attribute(parser); + break; + + case LXB_CSS_SYNTAX_TOKEN_COLON: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + status = lxb_css_selectors_state_pseudo_class(parser, token); + break; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + lxb_css_parser_state_set(parser, + lxb_css_selectors_state_compound_pseudo); + status = lxb_css_selectors_state_pseudo_element(parser, token); + break; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + return lxb_css_parser_unexpected(parser); + } + + status = lxb_css_selectors_state_pseudo_element_function(parser, token, + lxb_css_selectors_state_compound_pseudo); + break; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + goto unexpected; + } + + status = lxb_css_selectors_state_pseudo_class_function(parser, token, + lxb_css_selectors_state_compound_sub); + break; + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + goto again; + + case LXB_CSS_SYNTAX_TOKEN__END: + selectors = parser->selectors; + + if (selectors->combinator > LXB_CSS_SELECTOR_COMBINATOR_CLOSE + || selectors->list_last->first == NULL) + { + goto unexpected; + } + + return lxb_css_selectors_done(parser); + + default: + goto unexpected; + } + + if (status == LXB_STATUS_OK) { + return true; + } + + if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) { + return lxb_css_parser_memory_fail(parser); + } + +unexpected: + + (void) lxb_css_parser_states_to_root(parser); + (void) lxb_css_parser_states_set_back(parser); + + return lxb_css_parser_unexpected(parser); +} + +static bool +lxb_css_selectors_state_compound_sub(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_status_t status; + + /* */ + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_HASH: + status = lxb_css_selectors_state_hash(parser, token); + break; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + switch (lxb_css_syntax_token_delim_char(token)) { + case '.': + lxb_css_syntax_parser_consume(parser); + status = lxb_css_selectors_state_class(parser, token); + break; + + default: + return lxb_css_parser_states_set_back(parser); + } + + break; + + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + lxb_css_syntax_parser_consume(parser); + status = lxb_css_selectors_state_attribute(parser); + break; + + case LXB_CSS_SYNTAX_TOKEN_COLON: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + status = lxb_css_selectors_state_pseudo_class(parser, token); + break; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + lxb_css_parser_state_set(parser, + lxb_css_selectors_state_compound_pseudo); + status = lxb_css_selectors_state_pseudo_element(parser, + token); + break; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + return lxb_css_parser_unexpected(parser); + } + + status = lxb_css_selectors_state_pseudo_element_function(parser, + token, lxb_css_selectors_state_compound_pseudo); + break; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + return lxb_css_parser_unexpected(parser); + } + + status = lxb_css_selectors_state_pseudo_class_function(parser, token, + lxb_css_selectors_state_compound_sub); + break; + + default: + return lxb_css_parser_states_set_back(parser); + } + + if (status == LXB_STATUS_OK) { + return true; + } + + if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) { + return lxb_css_parser_memory_fail(parser); + } + + return lxb_css_parser_unexpected(parser); +} + +static bool +lxb_css_selectors_state_compound_pseudo(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_status_t status; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COLON) { + return lxb_css_parser_states_set_back(parser); + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + status = lxb_css_selectors_state_pseudo_class(parser, token); + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + status = lxb_css_selectors_state_pseudo_element(parser, token); + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + status = lxb_css_selectors_state_pseudo_element_function(parser, token, + lxb_css_selectors_state_compound_pseudo); + } + else { + return lxb_css_parser_unexpected(parser); + } + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + return lxb_css_parser_unexpected(parser); + } + else { + status = lxb_css_selectors_state_pseudo_class_function(parser, token, + lxb_css_selectors_state_compound_pseudo); + } + + if (status == LXB_STATUS_OK) { + return true; + } + + if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) { + return lxb_css_parser_memory_fail(parser); + } + + return lxb_css_parser_unexpected(parser); +} + +/* + * + */ +bool +lxb_css_selectors_state_simple_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, lxb_css_selectors_state_simple_wo_root, + lxb_css_selectors_state_simple_list_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_simple_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_selectors_state_list_end(parser, token, + lxb_css_selectors_state_simple_wo_root); +} + +/* + * + */ +bool +lxb_css_selectors_state_simple(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_t *states; + + states = lxb_css_parser_states_next(parser, + lxb_css_selectors_state_simple_wo_root, + lxb_css_selectors_state_end, + ctx, true); + if (states == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + return false; +} + +static bool +lxb_css_selectors_state_simple_wo_root(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_selector_list_t *list; + + lxb_css_selectors_state_list_append(parser, parser->selectors, list); + + lxb_css_parser_state_set(parser, lxb_css_selectors_state_simple_handler); + + return false; +} + +static bool +lxb_css_selectors_state_simple_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_status_t status; + +again: + + lxb_css_parser_state_set(parser, lxb_css_selectors_state_simple_back); + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_HASH: + status = lxb_css_selectors_state_hash(parser, token); + break; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + switch (lxb_css_syntax_token_delim_char(token)) { + case '.': + lxb_css_syntax_parser_consume(parser); + status = lxb_css_selectors_state_class(parser, token); + break; + + case '|': + case '*': + status = lxb_css_selectors_state_element_ns(parser, token); + break; + + default: + goto unexpected; + } + + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + status = lxb_css_selectors_state_element(parser, token); + break; + + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + lxb_css_syntax_parser_consume(parser); + status = lxb_css_selectors_state_attribute(parser); + break; + + case LXB_CSS_SYNTAX_TOKEN_COLON: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + status = lxb_css_selectors_state_pseudo_class(parser, token); + break; + } + else if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + goto unexpected; + } + + status = lxb_css_selectors_state_pseudo_class_function(parser, token, + lxb_css_selectors_state_simple_back); + break; + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_m(parser, token); + goto again; + + case LXB_CSS_SYNTAX_TOKEN__END: + return lxb_css_parser_states_set_back(parser); + + default: + goto unexpected; + } + + if (status == LXB_STATUS_OK) { + return true; + } + + if (status == LXB_STATUS_ERROR_MEMORY_ALLOCATION) { + return lxb_css_parser_memory_fail(parser); + } + +unexpected: + + (void) lxb_css_parser_states_set_back(parser); + + return lxb_css_parser_unexpected(parser); +} + +static bool +lxb_css_selectors_state_simple_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + return lxb_css_parser_states_set_back(parser); +} + +static lxb_status_t +lxb_css_selectors_state_hash(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_status_t status; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + lxb_css_selector_list_t *last; + + selectors = parser->selectors; + last = selectors->list_last; + + if (selectors->parent == NULL) { + lxb_css_selector_sp_set_a(last->specificity, + lxb_css_selector_sp_a(last->specificity) + 1); + } + else if (lxb_css_selector_sp_a(last->specificity) == 0) { + if (selectors->combinator != LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + last->specificity = 0; + } + + lxb_css_selector_sp_set_a(last->specificity, 1); + } + + lxb_css_selectors_state_append(parser, selectors, selector); + + selector->type = LXB_CSS_SELECTOR_TYPE_ID; + + status = lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token), + &selector->name, parser->memory->mraw); + lxb_css_syntax_parser_consume(parser); + + return status; +} + +static lxb_status_t +lxb_css_selectors_state_class(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_status_t status; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + + lxb_css_parser_token_status_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + selectors = parser->selectors; + + lxb_css_selectors_state_specificity_set_b(selectors); + lxb_css_selectors_state_append(parser, selectors, selector); + + selector->type = LXB_CSS_SELECTOR_TYPE_CLASS; + + status = lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token), + &selector->name, parser->memory->mraw); + lxb_css_syntax_parser_consume(parser); + + return status; + } + + return lxb_css_parser_unexpected_status(parser); +} + +static lxb_status_t +lxb_css_selectors_state_element_ns(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + + selectors = parser->selectors; + + lxb_css_selectors_state_append(parser, selectors, selector); + + selector->type = LXB_CSS_SELECTOR_TYPE_ANY; + + selector->name.data = lexbor_mraw_alloc(parser->memory->mraw, 2); + if (selector->name.data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + selector->name.data[0] = '*'; + selector->name.data[1] = '\0'; + selector->name.length = 1; + + if (lxb_css_syntax_token_delim_char(token) == '*') { + lxb_css_syntax_parser_consume(parser); + return lxb_css_selectors_state_ns(parser, selector); + } + + selector->name.data[0] = '\0'; + selector->name.length = 0; + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_selectors_state_ns_ident(parser, selector); +} + +static lxb_status_t +lxb_css_selectors_state_element(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_status_t status; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + + selectors = parser->selectors; + + lxb_css_selectors_state_specificity_set_c(selectors); + + lxb_css_selectors_state_append(parser, selectors, selector); + + selector->type = LXB_CSS_SELECTOR_TYPE_ELEMENT; + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_selectors_state_ns(parser, selector); +} + + +static lxb_status_t +lxb_css_selectors_state_attribute(lxb_css_parser_t *parser) +{ + lxb_char_t modifier; + lxb_status_t status; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + const lxb_css_syntax_token_t *token; + lxb_css_selector_attribute_t *attribute; + + selectors = parser->selectors; + + lxb_css_selectors_state_append(parser, selectors, selector); + lxb_css_parser_token_status_wo_ws_m(parser, token); + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DELIM: + if (lxb_css_syntax_token_delim_char(token) != '|') { + goto failed; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + goto failed; + } + + selector->type = LXB_CSS_SELECTOR_TYPE_ATTRIBUTE; + + selector->ns.data = lexbor_mraw_alloc(parser->memory->mraw, 2); + if (selector->ns.data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + selector->ns.data[0] = '*'; + selector->ns.data[1] = '\0'; + selector->ns.length = 1; + + lxb_css_selectors_state_string_dup_m(parser->selectors, + &selector->name); + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + selector->type = LXB_CSS_SELECTOR_TYPE_ATTRIBUTE; + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_DELIM + || lxb_css_syntax_token_delim_char(token) != '|') + { + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + } + + break; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + attribute = &selector->u.attribute; + attribute->match = LXB_CSS_SELECTOR_MATCH_DASH; + + goto assignment; + } + + selector->ns = selector->name; + lexbor_str_clean_all(&selector->name); + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + break; + + default: + goto failed; + } + + attribute = &selector->u.attribute; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + goto done; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + switch (lxb_css_syntax_token_delim_char(token)) { + case '~': + attribute->match = LXB_CSS_SELECTOR_MATCH_INCLUDE; + break; + + case '|': + attribute->match = LXB_CSS_SELECTOR_MATCH_DASH; + break; + + case '^': + attribute->match = LXB_CSS_SELECTOR_MATCH_PREFIX; + break; + + case '$': + attribute->match = LXB_CSS_SELECTOR_MATCH_SUFFIX; + break; + + case '*': + attribute->match = LXB_CSS_SELECTOR_MATCH_SUBSTRING; + break; + + case '=': + attribute->match = LXB_CSS_SELECTOR_MATCH_EQUAL; + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + goto string_or_ident; + + default: + goto failed; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + break; + + case LXB_CSS_SYNTAX_TOKEN__END: + goto done_eof; + + default: + goto failed; + } + +assignment: + + if (token->type != LXB_CSS_SYNTAX_TOKEN_DELIM + || lxb_css_syntax_token_delim_char(token) != '=') + { + goto failed; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + +string_or_ident: + + if (token->type != LXB_CSS_SYNTAX_TOKEN_STRING + && token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) + { + goto failed; + } + + lxb_css_selectors_state_string_dup_m(selectors, &attribute->value); + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + goto done; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + if (lxb_css_syntax_token_string(token)->length != 1) { + goto failed; + } + + break; + + case LXB_CSS_SYNTAX_TOKEN__END: + goto done_eof; + + default: + goto failed; + } + + modifier = *lxb_css_syntax_token_string(token)->data; + + switch (modifier) { + case 'i': + case 'I': + attribute->modifier = LXB_CSS_SELECTOR_MODIFIER_I; + break; + + case 's': + case 'S': + attribute->modifier = LXB_CSS_SELECTOR_MODIFIER_S; + break; + + default: + goto failed; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_RS_BRACKET) { + if (token->type == LXB_CSS_SYNTAX_TOKEN__END) { + goto done_eof; + } + + goto failed; + } + +done: + + lxb_css_selectors_state_specificity_set_b(selectors); + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; + +done_eof: + + (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_SYNTAX_ERROR, + "%s. End Of File in attribute selector", + lxb_css_selectors_module_name); + + lxb_css_selectors_state_specificity_set_b(selectors); + + return LXB_STATUS_OK; + +failed: + + return lxb_css_parser_unexpected_status(parser); +} + +static lxb_status_t +lxb_css_selectors_state_ns(lxb_css_parser_t *parser, + lxb_css_selector_t *selector) +{ + const lxb_css_syntax_token_t *token; + + lxb_css_parser_token_status_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM + && lxb_css_syntax_token_delim_char(token) == '|') + { + lxb_css_syntax_parser_consume(parser); + return lxb_css_selectors_state_ns_ident(parser, selector); + } + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selectors_state_ns_ident(lxb_css_parser_t *parser, + lxb_css_selector_t *selector) +{ + lxb_status_t status; + const lxb_css_syntax_token_t *token; + lxb_css_selectors_t *selectors; + + lxb_css_parser_token_status_m(parser, token); + + if (token->type == LXB_CSS_SYNTAX_TOKEN_IDENT) { + selectors = parser->selectors; + + lxb_css_selectors_state_specificity_set_c(selectors); + + selector->type = LXB_CSS_SELECTOR_TYPE_ELEMENT; + + selector->ns = selector->name; + lexbor_str_clean_all(&selector->name); + + status = lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string(token), + &selector->name, parser->memory->mraw); + + lxb_css_syntax_parser_consume(parser); + + return status; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM + && lxb_css_syntax_token_delim_char(token) == '*') + { + lxb_css_syntax_parser_consume(parser); + + selector->type = LXB_CSS_SELECTOR_TYPE_ANY; + + selector->ns = selector->name; + + selector->name.data = lexbor_mraw_alloc(parser->memory->mraw, 2); + if (selector->name.data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + selector->name.data[0] = '*'; + selector->name.data[1] = '\0'; + selector->name.length = 1; + + return LXB_STATUS_OK; + } + + return lxb_css_parser_unexpected_status(parser); +} + +static lxb_status_t +lxb_css_selectors_state_pseudo_class(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_status_t status; + lxb_css_log_message_t *msg; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + const lxb_css_selectors_pseudo_data_t *pseudo; + + selectors = parser->selectors; + + lxb_css_selectors_state_append(parser, selectors, selector); + selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS; + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + pseudo = lxb_css_selector_pseudo_class_by_name(selector->name.data, + selector->name.length); + if (pseudo == NULL) { + return lxb_css_parser_unexpected_status(parser); + } + + switch (pseudo->id) { + /* Bombshell note: lexbor rejects pseudo-classes its own matcher + * does not implement. Our runtime matcher handles them, so they + * are accepted at parse time instead of rejected. */ + default: + break; + } + + selector->u.pseudo.type = pseudo->id; + selector->u.pseudo.data = NULL; + + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selectors_state_pseudo_class_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_parser_state_f success) +{ + lxb_status_t status; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + lxb_css_log_message_t *msg; + lxb_css_syntax_rule_t *rule; + const lxb_css_selectors_pseudo_data_func_t *func; + + selectors = parser->selectors; + + lxb_css_selectors_state_append(parser, selectors, selector); + selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION; + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + func = lxb_css_selector_pseudo_class_function_by_name(selector->name.data, + selector->name.length); + if (func == NULL) { + return lxb_css_parser_unexpected_status(parser); + } + + switch (func->id) { + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_DIR: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_LANG: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_COL: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_COL: + msg = lxb_css_log_not_supported(parser->log, + lxb_css_selectors_module_name, + (const char *) selector->name.data); + if (msg == NULL) { + goto failed; + } + + return lxb_css_parser_unexpected_status(parser); + + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_CHILD: + case LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_NTH_LAST_CHILD: + lxb_css_selectors_state_specificity_set_b(selectors); + break; + + default: + break; + } + + selector->u.pseudo.type = func->id; + selector->u.pseudo.data = NULL; + + selectors->combinator = func->combinator; + selectors->comb_default = func->combinator; + selectors->parent = selector; + + rule = lxb_css_syntax_consume_function(parser, token, &func->cb, + success, selectors->list_last); + if (rule == NULL) { + goto failed; + } + + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; + +failed: + + (void) lxb_css_parser_memory_fail(parser); + + return parser->status; +} + +static lxb_status_t +lxb_css_selectors_state_pseudo_element(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_status_t status; + lxb_css_log_message_t *msg; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + const lxb_css_selectors_pseudo_data_t *pseudo; + + selectors = parser->selectors; + + lxb_css_selectors_state_append(parser, selectors, selector); + selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT; + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + pseudo = lxb_css_selector_pseudo_element_by_name(selector->name.data, + selector->name.length); + if (pseudo == NULL) { + return lxb_css_parser_unexpected_status(parser); + } + + switch (pseudo->id) { + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_AFTER: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BACKDROP: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_BEFORE: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LETTER: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_FIRST_LINE: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_GRAMMAR_ERROR: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_INACTIVE_SELECTION: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_MARKER: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_PLACEHOLDER: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SELECTION: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_SPELLING_ERROR: + case LXB_CSS_SELECTOR_PSEUDO_ELEMENT_TARGET_TEXT: + msg = lxb_css_log_not_supported(parser->log, + lxb_css_selectors_module_name, + (const char *) selector->name.data); + if (msg == NULL) { + (void) lxb_css_parser_memory_fail(parser); + return parser->status; + } + + return lxb_css_parser_unexpected_status(parser); + + default: + break; + } + + selector->u.pseudo.type = pseudo->id; + selector->u.pseudo.data = NULL; + + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_selectors_state_pseudo_element_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_parser_state_f success) +{ + lxb_status_t status; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors; + lxb_css_syntax_rule_t *rule; + const lxb_css_selectors_pseudo_data_func_t *func; + + selectors = parser->selectors; + + lxb_css_selectors_state_append(parser, selectors, selector); + selector->type = LXB_CSS_SELECTOR_TYPE_PSEUDO_ELEMENT_FUNCTION; + + lxb_css_selectors_state_string_dup_m(selectors, &selector->name); + + func = lxb_css_selector_pseudo_element_function_by_name(selector->name.data, + selector->name.length); + if (func == NULL) { + return lxb_css_parser_unexpected_status(parser); + } + + selector->u.pseudo.type = func->id; + selector->u.pseudo.data = NULL; + + selectors->combinator = func->combinator; + selectors->comb_default = func->combinator; + selectors->parent = selector; + + rule = lxb_css_syntax_consume_function(parser, token, &func->cb, + success, selectors->list_last); + if (rule == NULL) { + (void) lxb_css_parser_memory_fail(parser); + return parser->status; + } + + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; +} + +lxb_inline void +lxb_css_selectors_state_restore_combinator(lxb_css_selectors_t *selectors) +{ + lxb_css_selector_t *parent; + lxb_css_selector_combinator_t comb_default; + const lxb_css_selectors_pseudo_data_func_t *data_func; + + comb_default = LXB_CSS_SELECTOR_COMBINATOR_DESCENDANT; + + if (selectors->parent != NULL) { + parent = selectors->parent; + + if (parent->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION) { + data_func = lxb_css_selector_pseudo_class_function_by_id(parent->u.pseudo.type); + } + else { + data_func = lxb_css_selector_pseudo_element_function_by_id(parent->u.pseudo.type); + } + + comb_default = data_func->combinator; + } + + selectors->combinator = LXB_CSS_SELECTOR_COMBINATOR_CLOSE; + selectors->comb_default = comb_default; +} + +lxb_status_t +lxb_css_selectors_state_function_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + bool cy; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors = parser->selectors; + + if (token->type == LXB_CSS_SYNTAX_TOKEN__EOF) { + (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_SYNTAX_ERROR, + "%s. End Of File in pseudo function", + lxb_css_selectors_module_name); + } + + if (selectors->list_last == NULL) { + lxb_css_selectors_state_restore_parent(selectors, ctx); + goto empty; + } + + lxb_css_selectors_state_restore_parent(selectors, ctx); + + return LXB_STATUS_OK; + +empty: + + selector = selectors->list_last->last; + + cy = selector->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION; + cy = lxb_css_selector_pseudo_function_can_empty(selector->u.pseudo.type, + cy); + if (cy) { + lxb_css_parser_set_ok(parser); + return LXB_STATUS_OK; + } + + (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_SYNTAX_ERROR, + "%s. Pseudo function can't be empty: %S()", + lxb_css_selectors_module_name, &selector->name); + + lxb_css_selector_remove(selector); + lxb_css_selector_destroy(selector); + + lxb_css_parser_failed_set_by_id(parser, -1, true); + selectors->err_in_function = true; + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_selectors_state_function_forgiving(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return lxb_css_selectors_state_forgiving_cb(parser, token, ctx, + lxb_css_selectors_state_complex_list, + failed); +} + +lxb_status_t +lxb_css_selectors_state_function_forgiving_relative(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return lxb_css_selectors_state_forgiving_cb(parser, token, ctx, + lxb_css_selectors_state_relative_list, + failed); +} + +static lxb_status_t +lxb_css_selectors_state_forgiving_cb(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, lxb_css_parser_state_f state, + bool failed) +{ + bool cy; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors = parser->selectors; + + lxb_css_parser_set_ok(parser); + + if (token->type == LXB_CSS_SYNTAX_TOKEN__EOF) { + (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_SYNTAX_ERROR, + "%s. End Of File in pseudo function", + lxb_css_selectors_module_name); + } + + if (selectors->list_last == NULL) { + lxb_css_selectors_state_restore_parent(selectors, ctx); + goto empty; + } + + if (selectors->parent->u.pseudo.type + == LXB_CSS_SELECTOR_PSEUDO_CLASS_FUNCTION_WHERE) + { + selectors->list_last->specificity = 0; + } + + lxb_css_selectors_state_restore_parent(selectors, ctx); + + return LXB_STATUS_OK; + +empty: + + selector = selectors->list_last->last; + + cy = selector->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION; + cy = lxb_css_selector_pseudo_function_can_empty(selector->u.pseudo.type, + cy); + if (cy) { + return LXB_STATUS_OK; + } + + (void) lxb_css_log_format(parser->log, LXB_CSS_LOG_SYNTAX_ERROR, + "%s. Pseudo function can't be empty: %S()", + lxb_css_selectors_module_name, &selector->name); + + lxb_css_selector_remove(selector); + lxb_css_selector_destroy(selector); + + lxb_css_parser_failed_set_by_id(parser, -1, true); + selectors->err_in_function = true; + + return LXB_STATUS_OK; +} + +static void +lxb_css_selectors_state_restore_parent(lxb_css_selectors_t *selectors, + lxb_css_selector_list_t *last) +{ + uint32_t src, dst; + + if (selectors->list_last != NULL && selectors->list_last != last) { + dst = last->specificity; + src = selectors->list_last->specificity; + + selectors->list_last = 0; + + if (last->parent == NULL) { + lxb_css_selector_sp_add_a(dst, lxb_css_selector_sp_a(src)); + lxb_css_selector_sp_add_b(dst, lxb_css_selector_sp_b(src)); + lxb_css_selector_sp_add_c(dst, lxb_css_selector_sp_c(src)); + } + else if (selectors->combinator == LXB_CSS_SELECTOR_COMBINATOR_CLOSE) { + dst |= src; + } + else if (src > dst) { + dst = src; + } + + last->specificity = dst; + } + + if (selectors->list != NULL) { + last->last->u.pseudo.data = selectors->list; + } + + selectors->list_last = last; + + /* Get first Selector in chain. */ + while (last->prev != NULL) { + last = last->prev; + } + + selectors->list = last; + selectors->parent = last->parent; + + lxb_css_selectors_state_restore_combinator(selectors); +} + +static bool +lxb_css_selectors_state_list_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_parser_state_f state) +{ + lxb_css_parser_state_t *states; + lxb_css_selectors_t *selectors = parser->selectors; + + if (lxb_css_parser_is_failed(parser)) { + token = lxb_css_selectors_state_function_error(parser, token); + if (token == NULL) { + return lxb_css_parser_fail(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + } + + if (selectors->parent != NULL && selectors->list_last && + selectors->list_last->prev != NULL) + { + lxb_css_selectors_state_func_specificity(selectors); + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COMMA) { + states = lxb_css_parser_states_current(parser); + + if (states->root) { + if (token->type != LXB_CSS_SYNTAX_TOKEN__END) { + token = lxb_css_selectors_state_function_error(parser, token); + if (token == NULL) { + return lxb_css_parser_fail(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + } + + (void) lxb_css_parser_states_pop(parser); + return lxb_css_parser_success(parser); + } + + return lxb_css_selectors_done(parser); + } + + selectors->combinator = selectors->comb_default; + + lxb_css_syntax_token_consume(parser->tkz); + lxb_css_parser_state_set(parser, state); + lxb_css_parser_set_ok(parser); + + return true; +} + +static bool +lxb_css_selectors_state_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_parser_state_t *states; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + } + + if (lxb_css_parser_is_failed(parser)) { + token = lxb_css_selectors_state_function_error(parser, token); + if (token == NULL) { + return lxb_css_parser_fail(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + } + + states = lxb_css_parser_states_current(parser); + + if (states->root) { + if (token->type != LXB_CSS_SYNTAX_TOKEN__END) { + token = lxb_css_selectors_state_function_error(parser, token); + if (token == NULL) { + return lxb_css_parser_fail(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + } + + (void) lxb_css_parser_states_pop(parser); + return lxb_css_parser_success(parser); + } + + return lxb_css_selectors_done(parser); +} + + +static const lxb_css_syntax_token_t * +lxb_css_selectors_state_function_error(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + bool cy, comma; + lxb_css_selector_list_t *list; + lxb_css_selector_t *selector; + lxb_css_selectors_t *selectors = parser->selectors; + const lxb_css_syntax_token_t *origin; + const lxb_css_selectors_pseudo_data_func_t *func; + + cy = false; + comma = true; + list = selectors->list_last; + selector = selectors->parent; + + if (selector != NULL) { + cy = selector->type == LXB_CSS_SELECTOR_TYPE_PSEUDO_CLASS_FUNCTION; + + func = lxb_css_selector_pseudo_function_by_id(selector->u.pseudo.type, + cy); + if (func == NULL) { + return NULL; + } + + cy = func->forgiving; + comma = func->comma; + } + + if (!selectors->err_in_function) { + origin = lxb_css_syntax_token(parser->tkz); + if (origin == NULL) { + return NULL; + } + + if (token->type != LXB_CSS_SYNTAX_TOKEN__END) { + origin = token; + } + else if (origin->type != LXB_CSS_SYNTAX_TOKEN__EOF) { + origin = NULL; + } + + if (origin != NULL) { + if (lxb_css_syntax_token_error(parser, origin, + "Selectors") == NULL) + { + return NULL; + } + } + } + + selectors->err_in_function = false; + + if (cy) { + lxb_css_selector_list_selectors_remove(selectors, list); + lxb_css_selector_list_destroy(list); + + while (token != NULL + && token->type != LXB_CSS_SYNTAX_TOKEN__END) + { + if (comma == true + && token->type == LXB_CSS_SYNTAX_TOKEN_COMMA + && lxb_css_parser_rule_deep(parser) == 0) + { + break; + } + + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return token; + } + + lxb_css_selector_list_destroy_chain(selectors->list); + + selectors->list = NULL; + selectors->list_last = NULL; + + while (token != NULL + && token->type != LXB_CSS_SYNTAX_TOKEN__END) + { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return token; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/state.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/state.h new file mode 100644 index 0000000..3f10c8f --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/selectors/state.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2020 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SELECTORS_STATE_H +#define LEXBOR_CSS_SELECTORS_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/parser.h" +#include "lexbor/css/selectors/base.h" + + +LXB_API bool +lxb_css_selectors_state_complex_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +LXB_API bool +lxb_css_selectors_state_compound_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +LXB_API bool +lxb_css_selectors_state_simple_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +LXB_API bool +lxb_css_selectors_state_relative_list(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +LXB_API bool +lxb_css_selectors_state_relative(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +LXB_API bool +lxb_css_selectors_state_complex(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_compound(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_selectors_state_simple(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + + +LXB_API lxb_status_t +lxb_css_selectors_state_function_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API lxb_status_t +lxb_css_selectors_state_function_forgiving(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +LXB_API lxb_status_t +lxb_css_selectors_state_function_forgiving_relative(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +lxb_inline bool +lxb_css_selectors_state_fail(lxb_css_parser_t *parser) +{ + parser->status = LXB_STATUS_ERROR_UNEXPECTED_DATA; + + (void) lxb_css_parser_states_pop(parser); + + return false; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SELECTORS_STATE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/state.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/state.c new file mode 100644 index 0000000..dda5310 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/state.c @@ -0,0 +1,676 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/state.h" +#include "lexbor/css/css.h" +#include "lexbor/css/at_rule/state.h" + + +static bool +lxb_css_state_list_rules_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_state_list_rules_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_at_rule_t * +lxb_css_state_at_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule); + +static bool +lxb_css_state_at_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static lxb_status_t +lxb_css_state_at_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static bool +lxb_css_state_at_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +static lxb_status_t +lxb_css_state_at_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_state_qualified_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static bool +lxb_css_state_qualified_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); + +static lxb_status_t +lxb_css_state_qualified_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_block_t * +lxb_css_state_qualified_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static bool +lxb_css_state_qualified_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx); +static lxb_status_t +lxb_css_state_qualified_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); +static bool +lxb_css_state_block_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_state_block_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static const lxb_css_syntax_cb_declarations_t * +lxb_css_state_declarations_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static lxb_css_parser_state_f +lxb_css_state_declaration_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +static lxb_status_t +lxb_css_state_declaration_end(lxb_css_parser_t *parser, + void *declarations, void *ctx, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed); + +static lxb_status_t +lxb_css_state_declarations_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static bool +lxb_css_state_declarations_bad(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + + +static const lxb_css_syntax_cb_list_rules_t lxb_css_state_list_rules = { + .at_rule = lxb_css_state_at_rule_begin, + .qualified_rule = lxb_css_state_qualified_rule_begin, + .next = lxb_css_state_list_rules_next, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_state_list_rules_end +}; + +static const lxb_css_syntax_cb_at_rule_t lxb_css_state_at_rule = { + .prelude = lxb_css_state_at_rule_prelude, + .prelude_end = lxb_css_state_at_rule_prelude_end, + .block = lxb_css_state_at_rule_block_begin, + .cb.failed = lxb_css_state_at_rule_prelude_failed, + .cb.end = lxb_css_state_at_rule_end +}; + +static const lxb_css_syntax_cb_qualified_rule_t lxb_css_state_qualified_rule = { + .prelude = lxb_css_state_qualified_rule_prelude, + .prelude_end = lxb_css_state_qualified_rule_prelude_end, + .block = lxb_css_state_qualified_rule_block_begin, + .cb.failed = lxb_css_state_qualified_rule_prelude_failed, + .cb.end = lxb_css_state_qualified_rule_end +}; + +static const lxb_css_syntax_cb_block_t lxb_css_state_block = { + .at_rule = lxb_css_state_at_rule_begin, + .declarations = lxb_css_state_declarations_begin, + .qualified_rule = lxb_css_state_qualified_rule_begin, + .next = lxb_css_state_block_next, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_state_block_end, +}; + +static const lxb_css_syntax_cb_declarations_t lxb_css_state_declaration = { + .name = lxb_css_state_declaration_name, + .end = lxb_css_state_declaration_end, + .cb.failed = lxb_css_state_declarations_bad, + .cb.end = lxb_css_state_declarations_end +}; + + +bool +lxb_css_state_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + return true; + + case LXB_CSS_SYNTAX_TOKEN__END: + return true; + + default: + break; + } + + return lxb_css_parser_failed(parser); +} + +bool +lxb_css_state_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + if (token->type == LXB_CSS_SYNTAX_TOKEN__END) { + return lxb_css_parser_success(parser); + } + + /* The lxb_css_syntax_parser_consume(...) locked in this state. */ + + lxb_css_syntax_token_consume(parser->tkz); + + return true; +} + +bool +lxb_css_state_stop(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_stop(parser); +} + +bool +lxb_css_state_blank(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + return lxb_css_parser_success(parser); +} + +const lxb_css_syntax_cb_list_rules_t * +lxb_css_state_cb_list_rules(void) +{ + return &lxb_css_state_list_rules; +} + +const lxb_css_syntax_cb_at_rule_t * +lxb_css_state_cb_at_rule(void) +{ + return &lxb_css_state_at_rule; +} + +const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_state_cb_qualified_rule(void) +{ + return &lxb_css_state_qualified_rule; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_state_cb_block(void) +{ + return &lxb_css_state_block; +} + +const lxb_css_syntax_cb_declarations_t * +lxb_css_state_cb_declarations(void) +{ + return &lxb_css_state_declaration; +} + +static bool +lxb_css_state_list_rules_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + void *returned = lxb_css_syntax_returned(parser); + lxb_css_rule_list_t *list = ctx; + + if (returned != NULL) { + lxb_css_rule_list_append(list, returned); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_state_list_rules_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_list_t *list = ctx; + + lxb_css_syntax_set_return(parser, list); + + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_at_rule_t * +lxb_css_state_at_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx, + void **out_rule) +{ + lxb_css_rule_at_t *at; + const lxb_css_entry_at_rule_data_t *entry; + + at = lxb_css_at_rule_create(parser, lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length, + &entry); + if (at == NULL) { + return lxb_css_parser_memory_fail_null(parser); + } + + *out_rule = at; + + return entry->cbs; +} + +static bool +lxb_css_state_at_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_rule_at_t *at = ctx; + + at->prelude_begin = token->offset; + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_state_at_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_status_t status; + lxb_css_rule_at_t *at = ctx; + lxb_css_at_rule__custom_t *custom; + + at->prelude_end = token->offset; + + custom = at->u.custom; + + status = lxb_css_make_data(parser, &custom->prelude, at->prelude_begin, + at->prelude_end); + if (status != LXB_STATUS_OK) { + return lxb_css_parser_memory_fail_status(parser); + } + + return LXB_STATUS_OK; +} + +const lxb_css_syntax_cb_block_t * +lxb_css_state_at_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lxb_css_rule_list_t *list; + + list = lxb_css_rule_list_create(parser->memory); + if (list == NULL) { + return lxb_css_parser_memory_fail_null(parser); + } + + *out_rule = list; + + return &lxb_css_state_block; +} + +static bool +lxb_css_state_at_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_state_at_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_at_t *at = ctx; + lxb_css_rule_list_t *block = lxb_css_syntax_returned(parser); + + at->u.custom->block = block; + + lxb_css_syntax_set_return(parser, at); + + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_state_qualified_rule_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lxb_css_rule_style_t *style; + + style = lxb_css_rule_style_create(parser->memory); + if (style == NULL) { + return lxb_css_parser_memory_fail_null(parser); + } + + *out_rule = style; + + return &lxb_css_state_qualified_rule; +} + +static bool +lxb_css_state_qualified_rule_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + lxb_css_rule_style_t *style = ctx; + + lxb_css_selectors_clean(parser->selectors); + lxb_css_parser_state_set(parser, lxb_css_selectors_state_complex_list); + + style->prelude_begin = token->offset; + + return false; +} + +static lxb_status_t +lxb_css_state_qualified_rule_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + size_t begin; + lxb_status_t status; + lxb_css_rule_style_t *style = ctx; + lxb_css_rule_bad_style_t *bad; + + if (!failed) { + style->selector = parser->selectors->list; + style->prelude_end = token->offset; + + return LXB_STATUS_OK; + } + + begin = style->prelude_begin; + + (void) lxb_css_rule_style_destroy(style, true); + + bad = lxb_css_rule_bad_style_create(parser->memory); + if (bad == NULL) { + return lxb_css_parser_memory_fail_status(parser); + } + + bad->prelude_begin = begin; + bad->prelude_end = token->offset; + + status = lxb_css_make_data(parser, &bad->selectors, bad->prelude_begin, + bad->prelude_end); + if (status != LXB_STATUS_OK) { + return lxb_css_parser_memory_fail_status(parser); + } + + lxb_css_parser_set_context(parser, bad); + + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_block_t * +lxb_css_state_qualified_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lxb_css_rule_list_t *list; + + list = lxb_css_rule_list_create(parser->memory); + if (list == NULL) { + return lxb_css_parser_memory_fail_null(parser); + } + + *out_rule = list; + + return &lxb_css_state_block; +} + +static bool +lxb_css_state_qualified_rule_prelude_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx) +{ + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_state_qualified_rule_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_t *declrs; + lxb_css_rule_list_t *list; + lxb_css_rule_style_t *style; + lxb_css_rule_bad_style_t *bad; + + list = lxb_css_syntax_returned(parser); + + if (!failed) { + style = ctx; + + if (list != NULL && list->first != NULL + && list->first->type == LXB_CSS_RULE_DECLARATION_LIST) + { + declrs = list->first; + style->declarations = lxb_css_rule_declaration_list(declrs); + + declrs->parent = lxb_css_rule(style); + + if (list->first == list->last) { + list->last = NULL; + } + + if (declrs->next != NULL) { + declrs->next->prev = NULL; + } + + list->first = declrs->next; + declrs->next = NULL; + } + + style->child = list; + + lxb_css_syntax_set_return(parser, style); + } + else { + bad = ctx; + + if (list != NULL && list->first != NULL + && list->first->type == LXB_CSS_RULE_DECLARATION_LIST) + { + declrs = list->first; + bad->declarations = lxb_css_rule_declaration_list(declrs); + + declrs->parent = lxb_css_rule(bad); + + if (list->first == list->last) { + list->last = NULL; + } + + if (declrs->next != NULL) { + declrs->next->prev = NULL; + } + + list->first = declrs->next; + declrs->next = NULL; + } + + bad->child = list; + + lxb_css_syntax_set_return(parser, bad); + } + + return LXB_STATUS_OK; +} + +static bool +lxb_css_state_block_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + /* rule can be either a declaration list or an at rule. */ + + lxb_css_rule_t *rule = lxb_css_syntax_returned(parser); + lxb_css_rule_list_t *list = ctx; + + lxb_css_rule_list_append(list, rule); + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_state_block_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_list_t *list = ctx; + + lxb_css_syntax_set_return(parser, list); + + return LXB_STATUS_OK; +} + +static const lxb_css_syntax_cb_declarations_t * +lxb_css_state_declarations_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + lxb_css_rule_declaration_list_t *list; + + list = lxb_css_rule_declaration_list_create(parser->memory); + if (list == NULL) { + return lxb_css_parser_memory_fail_null(parser); + } + + *out_rule = list; + + return &lxb_css_state_declaration; +} + +static lxb_css_parser_state_f +lxb_css_state_declaration_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule) +{ + const lxb_css_entry_data_t *entry; + lxb_css_rule_declaration_t *declar; + + declar = lxb_css_declaration_create(parser, + lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_token_ident(token)->length, + &entry); + if (declar == NULL) { + (void) lxb_css_parser_memory_fail_null(parser); + return NULL; + } + + /* We present an original position. */ + + declar->offset.name_begin = token->offset; + declar->offset.name_end = token->offset + + lxb_css_syntax_token_base(token)->length; + *out_rule = declar; + + return entry->state; +} + +static lxb_status_t +lxb_css_state_declaration_end(lxb_css_parser_t *parser, + void *declarations, void *ctx, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed) +{ + lxb_status_t status; + lxb_css_property__undef_t *undef; + lxb_css_rule_declaration_t *declar = ctx; + lxb_css_rule_declaration_list_t *list = declarations; + + declar->offset.value_begin = offset->value_begin; + declar->offset.value_end = offset->value_end; + declar->offset.important_begin = offset->important_begin; + declar->offset.important_end = offset->important_end; + declar->important = important; + + if (failed) { + lxb_css_rule_declaration_destroy(declar, false); + + undef = lxb_css_property__undef_create(parser->memory); + if (undef == NULL) { + return lxb_css_parser_memory_fail_status(parser); + } + + undef->type = declar->type; + + status = lxb_css_make_data(parser, &undef->value, + declar->offset.value_begin, + declar->offset.value_end); + if (status != LXB_STATUS_OK) { + return lxb_css_parser_memory_fail_status(parser); + } + + declar->u.undef = undef; + declar->type = LXB_CSS_PROPERTY__UNDEF; + } + + lxb_css_rule_declaration_list_append(list, lxb_css_rule(declar)); + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_state_declarations_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + lxb_css_rule_declaration_list_t *list = ctx; + + lxb_css_syntax_set_return(parser, list); + + return LXB_STATUS_OK; +} + +static bool +lxb_css_state_declarations_bad(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + lxb_css_rule_declaration_t *declar; + + if (ctx == NULL) { + declar = lxb_css_rule_declaration_create(parser->memory); + if (declar == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + lxb_css_parser_current_rule(parser)->context = declar; + declar->type = LXB_CSS_PROPERTY__UNDEF; + } + + while (token != NULL && token->type != LXB_CSS_SYNTAX_TOKEN__END) { + lxb_css_syntax_parser_consume(parser); + token = lxb_css_syntax_parser_token(parser); + } + + return lxb_css_parser_success(parser); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/state.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/state.h new file mode 100644 index 0000000..6ecd503 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/state.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_STATE_H +#define LXB_CSS_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/syntax/syntax.h" + + +LXB_API bool +lxb_css_state_success(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_state_failed(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_state_stop(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API bool +lxb_css_state_blank(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +LXB_API const lxb_css_syntax_cb_list_rules_t * +lxb_css_state_cb_list_rules(void); + +LXB_API const lxb_css_syntax_cb_at_rule_t * +lxb_css_state_cb_at_rule(void); + +LXB_API const lxb_css_syntax_cb_qualified_rule_t * +lxb_css_state_cb_qualified_rule(void); + +LXB_API const lxb_css_syntax_cb_block_t * +lxb_css_state_cb_block(void); + +LXB_API const lxb_css_syntax_cb_declarations_t * +lxb_css_state_cb_declarations(void); + +const lxb_css_syntax_cb_block_t * +lxb_css_state_at_rule_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_STATE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/stylesheet.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/stylesheet.c new file mode 100644 index 0000000..ac16f7b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/stylesheet.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/stylesheet.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/at_rule.h" +#include "lexbor/css/property.h" +#include "lexbor/css/rule.h" +#include "lexbor/css/state.h" +#include "lexbor/css/selectors/selectors.h" +#include "lexbor/css/selectors/state.h" + + +lxb_css_stylesheet_t * +lxb_css_stylesheet_create(lxb_css_memory_t *memory) +{ + lxb_status_t status; + lxb_css_stylesheet_t *stylesheet; + + if (memory == NULL) { + memory = lxb_css_memory_create(); + status = lxb_css_memory_init(memory, 1024); + + if (status != LXB_STATUS_OK) { + (void) lxb_css_memory_destroy(memory, true); + return NULL; + } + } + else { + (void) lxb_css_memory_ref_inc(memory); + } + + stylesheet = lexbor_mraw_calloc(memory->mraw, sizeof(lxb_css_stylesheet_t)); + if (stylesheet == NULL) { + return NULL; + } + + stylesheet->memory = memory; + + return stylesheet; +} + +lxb_css_stylesheet_t * +lxb_css_stylesheet_destroy(lxb_css_stylesheet_t *sst, bool destroy_memory) +{ + if (sst == NULL) { + return NULL; + } + + if (destroy_memory) { + (void) lxb_css_memory_ref_dec_destroy(sst->memory); + return NULL; + } + + if (sst->root != NULL) { + (void) lxb_css_rule_destroy(sst->root, true); + } + + (void) lexbor_mraw_free(sst->memory->mraw, sst); + + return NULL; +} + +lxb_status_t +lxb_css_stylesheet_parse(lxb_css_stylesheet_t *sst, lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + lxb_status_t status; + lxb_css_rule_list_t *list; + lxb_css_selectors_t selectors; + + if (sst == NULL || parser == NULL) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + if (parser->selectors == NULL) { + status = lxb_css_selectors_init(&selectors); + if (status != LXB_STATUS_OK) { + return status; + } + + parser->selectors = &selectors; + } + else { + lxb_css_selectors_clean(parser->selectors); + } + + parser->memory = sst->memory; + + list = lxb_css_syntax_parse_list_rules(parser, + lxb_css_state_cb_list_rules(), + data, length); + + if (parser->selectors == &selectors) { + lxb_css_selectors_destroy(&selectors, false); + parser->selectors = NULL; + } + + if (list == NULL) { + sst->root = NULL; + return parser->status; + } + + sst->root = &list->rule; + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/stylesheet.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/stylesheet.h new file mode 100644 index 0000000..9d52f98 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/stylesheet.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_STYLESHEET_H +#define LXB_CSS_STYLESHEET_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/rule.h" +#include "lexbor/core/mraw.h" +#include "lexbor/css/at_rule.h" +#include "lexbor/css/syntax/tokenizer.h" +#include "lexbor/css/selectors/base.h" + + +struct lxb_css_stylesheet { + lxb_css_rule_t *root; + lxb_css_memory_t *memory; + + void *element; /* lxb_html_style_element_t * */ +}; + +/* + * Create a new CSS stylesheet object. + * + * This function creates a stylesheet object which holds the parsed CSS rules. + * + * @param[in] memory Optional. A memory pool to use for allocations. + * If NULL, a new internal memory pool is created/managed + * by the stylesheet. + * + * @return A new lxb_css_stylesheet_t * or NULL on failure. + */ +LXB_API lxb_css_stylesheet_t * +lxb_css_stylesheet_create(lxb_css_memory_t *memory); + +/* + * Destroy a CSS stylesheet object. + * + * @param[in] sst Optional. The stylesheet object to destroy. + * If NULL, the function returns NULL. + * @param[in] destroy_memory If true, the memory pool attached to + * the stylesheet is also destroyed. + * + * @return Always NULL. + */ +LXB_API lxb_css_stylesheet_t * +lxb_css_stylesheet_destroy(lxb_css_stylesheet_t *sst, bool destroy_memory); + +/* + * Parse CSS content into the stylesheet. + * + * This function takes CSS text and builds the rule tree in the stylesheet. + * + * The function returns an error only in extremely unforeseen circumstances, + * such as the inability to allocate memory for objects. Any broken CSS will + * not cause an error. + * + * Selectors note: + * If the provided parser does not have an initialized selectors module, one + * will be created temporarily for this call. For better performance when + * parsing multiple stylesheets, initialize the selectors module in + * the parser once: + * + * lxb_css_parser_t *parser = lxb_css_parser_create(); + * lxb_css_parser_init(parser, NULL); + * lxb_css_parser_selectors_init(parser); + * + * @param[in] sst Required. The target stylesheet. + * @param[in] parser Required. An initialized CSS parser. + * @param[in] data Optional. The CSS text data. + * @param[in] length Required. Length of the data in bytes. + * + * @return LXB_STATUS_OK on success, or an error code on failure. + */ +LXB_API lxb_status_t +lxb_css_stylesheet_parse(lxb_css_stylesheet_t *sst, lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_STYLESHEET_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/anb.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/anb.c new file mode 100644 index 0000000..d3f7c7b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/anb.c @@ -0,0 +1,486 @@ +/* + * Copyright (C) 2021-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/conv.h" +#include "lexbor/core/serialize.h" +#include "lexbor/css/css.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/syntax/anb.h" + + +static bool +lxb_css_syntax_anb_state(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx); + +static lxb_status_t +lxb_css_syntax_anb_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +static lxb_css_log_message_t * +lxb_css_syntax_anb_fail(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token); + +static lxb_status_t +lxb_css_syntax_anb_state_ident(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_anb_t *anb); + +static lxb_status_t +lxb_css_syntax_anb_state_ident_data(lxb_css_parser_t *parser, + lxb_css_syntax_anb_t *anb, + const lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end); + + +static const lxb_css_syntax_cb_pipe_t lxb_css_syntax_anb_pipe = { + .prelude = lxb_css_syntax_anb_state, + .cb.failed = lxb_css_state_failed, + .cb.end = lxb_css_syntax_anb_end +}; + + +lxb_css_syntax_anb_t +lxb_css_syntax_anb_parse(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length) +{ + lxb_status_t status; + lxb_css_syntax_anb_t anb; + lxb_css_syntax_rule_t *rule; + + memset(&anb, 0, sizeof(lxb_css_syntax_anb_t)); + + if (parser->stage != LXB_CSS_PARSER_CLEAN) { + if (parser->stage == LXB_CSS_PARSER_RUN) { + parser->status = LXB_STATUS_ERROR_WRONG_ARGS; + return anb; + } + + lxb_css_parser_clean(parser); + } + + lxb_css_parser_buffer_set(parser, data, length); + + rule = lxb_css_syntax_parser_pipe_push(parser, &lxb_css_syntax_anb_pipe, + NULL, &anb, + LXB_CSS_SYNTAX_TOKEN_UNDEF); + if (rule == NULL) { + return anb; + } + + parser->tkz->with_comment = false; + parser->stage = LXB_CSS_PARSER_RUN; + + status = lxb_css_syntax_parser_run(parser); + if (status != LXB_STATUS_OK) { + /* Destroy. */ + } + + parser->stage = LXB_CSS_PARSER_END; + + return anb; +} + +static bool +lxb_css_syntax_anb_state(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, void *ctx) +{ + parser->status = lxb_css_syntax_anb_handler(parser, token, ctx); + + token = lxb_css_syntax_parser_token(parser); + if (token == NULL) { + return lxb_css_parser_memory_fail(parser); + } + + if (parser->status != LXB_STATUS_OK + || (token->type != LXB_CSS_SYNTAX_TOKEN__END)) + { + (void) lxb_css_syntax_anb_fail(parser, token); + } + + return lxb_css_parser_success(parser); +} + +static lxb_status_t +lxb_css_syntax_anb_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed) +{ + return LXB_STATUS_OK; +} + +static lxb_css_log_message_t * +lxb_css_syntax_anb_fail(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + parser->status = LXB_STATUS_ERROR_UNEXPECTED_DATA; + + static const char anb[] = "An+B"; + + return lxb_css_syntax_token_error(parser, token, anb); +} + +lxb_status_t +lxb_css_syntax_anb_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_anb_t *anb) +{ + const lxb_char_t *data, *end; + lxb_css_syntax_token_ident_t *ident; + +again: + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + if (lxb_css_syntax_token_dimension(token)->num.is_float) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + anb->a = lexbor_conv_double_to_long(lxb_css_syntax_token_dimension(token)->num.num); + + ident = lxb_css_syntax_token_dimension_string(token); + + goto ident; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + return lxb_css_syntax_anb_state_ident(parser, token, anb); + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + if (lxb_css_syntax_token_number(token)->is_float) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + anb->a = 0; + anb->b = lexbor_conv_double_to_long(lxb_css_syntax_token_number(token)->num); + break; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + if (lxb_css_syntax_token_delim(token)->character != '+') { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + anb->a = 1; + + ident = lxb_css_syntax_token_ident(token); + + goto ident; + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_m(parser, token); + goto again; + + default: + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; + +ident: + + data = ident->data; + end = ident->data + ident->length; + + if (*data != 'n' && *data != 'N') { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + data++; + + return lxb_css_syntax_anb_state_ident_data(parser, anb, token, data, end); +} + +static lxb_status_t +lxb_css_syntax_anb_state_ident(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_anb_t *anb) +{ + size_t length; + lxb_char_t c; + const lxb_char_t *data, *end; + lxb_css_syntax_token_ident_t *ident; + + static const lxb_char_t odd[] = "odd"; + static const lxb_char_t even[] = "even"; + + ident = lxb_css_syntax_token_ident(token); + + length = ident->length; + data = ident->data; + end = data + length; + + c = *data++; + + /* 'n' or '-n' */ + + if (c == 'n' || c == 'N') { + anb->a = 1; + } + else if (c == '-') { + if (data >= end) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + c = *data++; + + if (c != 'n' && c != 'N') { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + anb->a = -1; + } + else if (length == sizeof(odd) - 1 + && lexbor_str_data_ncasecmp(ident->data, odd, sizeof(odd) - 1)) + { + anb->a = 2; + anb->b = 1; + + lxb_css_syntax_parser_consume(parser); + return LXB_STATUS_OK; + } + else if (length == sizeof(even) - 1 + && lexbor_str_data_ncasecmp(ident->data, even, sizeof(even) - 1)) + { + anb->a = 2; + anb->b = 0; + + lxb_css_syntax_parser_consume(parser); + return LXB_STATUS_OK; + } + else { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + return lxb_css_syntax_anb_state_ident_data(parser, anb, token, data, end); +} + +static lxb_status_t +lxb_css_syntax_anb_state_ident_data(lxb_css_parser_t *parser, + lxb_css_syntax_anb_t *anb, + const lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end) +{ + unsigned sign; + lxb_char_t c; + const lxb_char_t *p; + + sign = 0; + + if (data >= end) { + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + if (!lxb_css_syntax_token_number(token)->have_sign) { + anb->b = 0; + return LXB_STATUS_OK; + } + + break; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + c = lxb_css_syntax_token_delim(token)->character; + + switch (c) { + case '-': + sign = 1; + break; + + case '+': + sign = 2; + break; + + default: + anb->b = 0; + return LXB_STATUS_OK; + } + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + + break; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + anb->b = 0; + return LXB_STATUS_OK; + + default: + anb->b = 0; + return LXB_STATUS_OK; + } + + goto number; + } + + c = *data++; + + if (c != '-') { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + if (data < end) { + p = data; + anb->b = -lexbor_conv_data_to_long(&data, end - data); + + if (anb->b > 0 || data == p || data < end) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + goto done; + } + + sign = 1; + + lxb_css_syntax_parser_consume(parser); + lxb_css_parser_token_status_wo_ws_m(parser, token); + +number: + + if (token->type != LXB_CSS_SYNTAX_TOKEN_NUMBER) { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + if (lxb_css_syntax_token_number(token)->is_float + || (sign > 0 && lxb_css_syntax_token_number(token)->have_sign)) + { + return LXB_STATUS_ERROR_UNEXPECTED_DATA; + } + + anb->b = lexbor_conv_double_to_long(lxb_css_syntax_token_number(token)->num); + + if (sign == 1) { + anb->b = -anb->b; + } + +done: + + lxb_css_syntax_parser_consume(parser); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_syntax_anb_serialize(lxb_css_syntax_anb_t *anb, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_char_t buf[128]; + lxb_char_t *p, *end; + + if (anb == NULL) { + return LXB_STATUS_OK; + } + + static const lxb_char_t odd[] = "odd"; + static const lxb_char_t even[] = "even"; + + if (anb->a == 2) { + if (anb->b == 1) { + return cb(odd, sizeof(odd) - 1, ctx); + } + + if (anb->b == 0) { + return cb(even, sizeof(even) - 1, ctx); + } + } + + p = buf; + end = p + sizeof(buf); + + if (anb->a == 1) { + *p = '+'; + p++; + } + else if (anb->a == -1) { + *p = '-'; + p++; + } + else { + p += lexbor_conv_float_to_data((double) anb->a, p, end - p); + if (p >= end) { + return LXB_STATUS_ERROR_SMALL_BUFFER; + } + } + + *p = 'n'; + p++; + + if (p >= end) { + return cb(buf, p - buf, ctx); + } + + if (anb->b == 0) { + return cb(buf, p - buf, ctx); + } + + if (anb->b > 0) { + *p = '+'; + p++; + + if (p >= end) { + return LXB_STATUS_ERROR_SMALL_BUFFER; + } + } + + p += lexbor_conv_float_to_data((double) anb->b, p, end - p); + + return cb(buf, p - buf, ctx); +} + +lxb_char_t * +lxb_css_syntax_anb_serialize_char(lxb_css_syntax_anb_t *anb, size_t *out_length) +{ + size_t length = 0; + lxb_status_t status; + lexbor_str_t str; + + status = lxb_css_syntax_anb_serialize(anb, lexbor_serialize_length_cb, + &length); + if (status != LXB_STATUS_OK) { + goto failed; + } + + /* + 1 == '\0' */ + str.data = lexbor_malloc(length + 1); + if (str.data == NULL) { + goto failed; + } + + str.length = 0; + + status = lxb_css_syntax_anb_serialize(anb, lexbor_serialize_copy_cb, &str); + if (status != LXB_STATUS_OK) { + lexbor_free(str.data); + goto failed; + } + + str.data[str.length] = '\0'; + + if (out_length != NULL) { + *out_length = str.length; + } + + return str.data; + +failed: + + if (out_length != NULL) { + *out_length = 0; + } + + return NULL; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/anb.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/anb.h new file mode 100644 index 0000000..ed6838e --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/anb.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_ANB_H +#define LEXBOR_CSS_SYNTAX_ANB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/syntax/token.h" + + +typedef struct { + long a; + long b; +} +lxb_css_syntax_anb_t; + + +LXB_API lxb_css_syntax_anb_t +lxb_css_syntax_anb_parse(lxb_css_parser_t *parser, + const lxb_char_t *data, size_t length); + +LXB_API lxb_status_t +lxb_css_syntax_anb_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_anb_t *anb); + +LXB_API lxb_status_t +lxb_css_syntax_anb_serialize(lxb_css_syntax_anb_t *anb, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_char_t * +lxb_css_syntax_anb_serialize_char(lxb_css_syntax_anb_t *anb, + size_t *out_length); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_ANB_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/base.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/base.h new file mode 100644 index 0000000..627fce4 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/base.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_BASE_H +#define LEXBOR_CSS_SYNTAX_BASE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "lexbor/core/base.h" +#include "lexbor/css/base.h" + + +#define LXB_CSS_SYNTAX_VERSION_MAJOR 1 +#define LXB_CSS_SYNTAX_VERSION_MINOR 4 +#define LXB_CSS_SYNTAX_VERSION_PATCH 0 + +#define LXB_CSS_SYNTAX_VERSION_STRING \ + LEXBOR_STRINGIZE(LXB_CSS_SYNTAX_VERSION_MAJOR) "." \ + LEXBOR_STRINGIZE(LXB_CSS_SYNTAX_VERSION_MINOR) "." \ + LEXBOR_STRINGIZE(LXB_CSS_SYNTAX_VERSION_PATCH) + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_BASE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/parser.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/parser.c new file mode 100644 index 0000000..7de012a --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/parser.c @@ -0,0 +1,2251 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/state.h" +#include "lexbor/css/syntax/parser.h" +#include "lexbor/css/syntax/syntax.h" +#include "lexbor/css/at_rule/state.h" + + +static const lexbor_str_t lxb_css_err_rc = lexbor_str("Unexpected token in " + "qualified rule: RC_BRACKET"); + +static lxb_css_syntax_rule_t * +lxb_css_syntax_parser_stack_pop(lxb_css_parser_t *parser); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules_at(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules_qualified(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + lxb_css_parser_state_f back_state, + lxb_css_syntax_begin_at_rule_f cb, + bool nested); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_prelude_end_consule_token(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_back_to_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_rule_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_back_to_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + lxb_css_parser_state_f back_state, + lxb_css_syntax_begin_block_f cb); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_at(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_qualified(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_validate(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_drop(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declaration_back_to_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declaration_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declaration_end_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + bool skip_token); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_end_h(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + bool skip_token); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_components(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_components_back_to_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_function_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_pipe(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_pipe_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_end_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + + +lxb_inline const lxb_css_syntax_token_t * +lxb_css_syntax_parser_failed(lxb_css_parser_t *parser, lxb_status_t status) +{ + parser->status = status; + return NULL; +} + +lxb_inline const lxb_css_syntax_token_t * +lxb_css_syntax_token_parser_do_phase_again(lxb_css_parser_t *parser) +{ + parser->fake_null = true; + return NULL; +} + +lxb_inline const lxb_css_syntax_token_t * +lxb_css_syntax_parser_call_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token) +{ + lxb_css_syntax_rule_t *rules; + + (void) lxb_css_syntax_parser_stack_pop(parser); + + rules = parser->rules; + + if (parser->rules <= parser->rules_begin) { + rules->state = lxb_css_state_stop; + return token; + } + + return rules->back(parser, token, rules); +} + + +lxb_status_t +lxb_css_syntax_parser_run(lxb_css_parser_t *parser) +{ + const lxb_css_syntax_token_t *token; + + parser->loop = true; + + do { + token = lxb_css_syntax_parser_token(parser); + if (token == NULL) { + if (parser->fake_null) { + parser->fake_null = false; + continue; + } + + return parser->status; + } + + while (parser->rules->state(parser, token, + parser->rules->context) == false) {}; + } + while (parser->loop); + + return parser->status; +} + +const lxb_css_syntax_token_t * +lxb_css_syntax_parser_token(lxb_css_parser_t *parser) +{ + lxb_css_syntax_token_t *token; + lxb_css_syntax_rule_t *rule = parser->rules; + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + return rule->phase(parser, token, rule); +} + +const lxb_css_syntax_token_t * +lxb_css_syntax_parser_token_wo_ws(lxb_css_parser_t *parser) +{ + const lxb_css_syntax_token_t *token; + + token = lxb_css_syntax_parser_token(parser); + + if (token != NULL && token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_parser_consume(parser); + return lxb_css_syntax_parser_token(parser); + } + + return token; +} + +void +lxb_css_syntax_parser_consume(lxb_css_parser_t *parser) +{ + if (!parser->rules->skip_consume) { + lxb_css_syntax_token_consume(parser->tkz); + } +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_list_rules_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_list_rules_t *cb_rules, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_list_rules, + .state = lxb_css_state_blank, + .back = lxb_css_syntax_parser_list_rules_back, + .cbx.list_rules = cb_rules, + .context = ctx, + .block_end = stop + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_at_rule_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_at_rule_t *at_rule, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop, + bool nested) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_at_rule, + .state = at_rule->prelude, + .back = lxb_css_syntax_parser_at_back_to_prelude, + .cbx.at_rule = at_rule, + .context = ctx, + .block_end = stop, + .nested = nested + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_qualified_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_qualified_rule_t *qualified, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop, + bool nested) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_qualified_rule, + .state = qualified->prelude, + .back = lxb_css_syntax_parser_qualified_back_to_prelude, + .cbx.qualified_rule = qualified, + .context = ctx, + .block_end = stop, + .nested = nested + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_block_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_block_t *block, + lxb_css_parser_state_f back, void *ctx) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_block, + .state = lxb_css_state_blank, + .back = lxb_css_syntax_parser_block_back, + .cbx.block = block, + .context = ctx + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_declarations_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_declarations_t *declr, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop, + bool name_validate, bool nested) +{ + lxb_css_syntax_rule_t *rule; + lxb_css_syntax_state_f phase; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + phase = (!name_validate) ? lxb_css_syntax_parser_declarations_begin + : lxb_css_syntax_parser_declarations_validate; + + *rule = (lxb_css_syntax_rule_t) { + .phase = phase, + .state = lxb_css_state_blank, + .back = lxb_css_syntax_parser_declaration_back_to_value, + .cbx.declarations = declr, + .context = ctx, + .block_end = stop, + .nested = nested + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_components_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_components_t *comp, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_components, + .state = comp->prelude, + .back = lxb_css_syntax_parser_components_back_to_value, + .cbx.components = comp, + .context = ctx, + .block_end = stop + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_function_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_function_t *func, + lxb_css_parser_state_f back, void *ctx) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_function, + .state = func->value, + .back = lxb_css_syntax_parser_function_back, + .cbx.func = func, + .context = ctx + }; + + return rule; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_parser_pipe_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_pipe_t *pipe, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop) +{ + lxb_css_syntax_rule_t *rule; + + if ((parser->rules + 1) >= parser->rules_end) { + parser->status = lxb_css_syntax_stack_expand(parser, 1); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + } + + parser->rules->back_state = back; + + rule = ++parser->rules; + + *rule = (lxb_css_syntax_rule_t) { + .phase = lxb_css_syntax_parser_pipe, + .state = pipe->prelude, + .back = lxb_css_syntax_parser_pipe_back, + .cbx.pipe = pipe, + .context = ctx, + .block_end = stop + }; + + return rule; +} + +static lxb_css_syntax_rule_t * +lxb_css_syntax_parser_stack_pop(lxb_css_parser_t *parser) +{ + return parser->rules--; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + if (rule->offset > token->offset) { + return token; + } + + rule->skip_consume = true; + +begin: + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + case LXB_CSS_SYNTAX_TOKEN_CDC: + case LXB_CSS_SYNTAX_TOKEN_CDO: + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + + goto begin; + + case LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD: + rule->phase = lxb_css_syntax_parser_list_rules_at; + break; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + goto done; + + default: + if (rule->block_end == token->type && rule->deep == 0) { + goto done; + } + + rule->phase = lxb_css_syntax_parser_list_rules_qualified; + break; + } + + return token; + +done: + + rule->phase = lxb_css_syntax_parser_end; + + return lxb_css_parser_token_end(parser, 0); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules_at(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + const lxb_css_syntax_cb_list_rules_t *list_rules = rule->cbx.list_rules; + + return lxb_css_syntax_parser_at_begin(parser, token, rule, list_rules->next, + list_rules->at_rule, false); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules_qualified(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + void *qualified_ctx; + lxb_css_syntax_rule_t *qualified; + lxb_css_syntax_begin_qualified_rule_f cb; + const lxb_css_syntax_cb_list_rules_t *list_rules; + const lxb_css_syntax_cb_qualified_rule_t *cb_qualified; + + qualified_ctx = NULL; + list_rules = rule->cbx.list_rules; + cb = list_rules->qualified_rule; + + rule->skip_consume = false; + + cb_qualified = cb(parser, token, rule->context, &qualified_ctx); + if (cb_qualified == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + qualified = lxb_css_syntax_parser_qualified_push(parser, cb_qualified, + list_rules->next, + qualified_ctx, + rule->block_end, + false); + if (qualified == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_list_rules_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_list_rules; + rule->state = rule->back_state; + rule->skip_consume = true; + + return token; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + lxb_css_parser_state_f back_state, + lxb_css_syntax_begin_at_rule_f cb, + bool nested) +{ + void *at_rule_ctx; + lxb_css_syntax_rule_t *at_rule; + const lxb_css_syntax_cb_at_rule_t *cb_at_rule; + + at_rule_ctx = NULL; + rule->skip_consume = false; + + cb_at_rule = cb(parser, token, rule->context, &at_rule_ctx); + if (cb_at_rule == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + at_rule = lxb_css_syntax_parser_at_rule_push(parser, cb_at_rule, + back_state, at_rule_ctx, + rule->block_end, nested); + if (at_rule == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_token_consume(parser->tkz); + } + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * First call for this code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + * Rule -- lxb_css_syntax_rule_t with at_rule callbacks. + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + const lxb_css_log_message_t *msg; + + if (rule->offset > token->offset) { + return token; + } + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + if (rule->block_end == token->type && rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_at_prelude_end; + goto done; + } + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_at_block; + rule->back = lxb_css_syntax_parser_end_back; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); + } + + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + if (rule->deep != 0) { + if (parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + } + else { + msg = lxb_css_log_format(parser->log, + LXB_CSS_LOG_SYNTAX_ERROR, + "%S", &lxb_css_err_rc); + if (msg == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + if (rule->nested) { + rule->phase = lxb_css_syntax_parser_at_prelude_end; + goto done; + } + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + if (rule->deep != 0 && parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_at_prelude_end_consule_token; + goto done; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + rule->phase = lxb_css_syntax_parser_at_prelude_end; + goto done; + + default: + return token; + } + + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->deep++; + + return token; + +done: + + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + const lxb_css_syntax_cb_at_rule_t *at_rule = rule->cbx.at_rule; + + status = at_rule->prelude_end(parser, token, rule->context, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + return lxb_css_syntax_parser_block_begin(parser, token, rule, + at_rule->prelude, at_rule->block); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + const lxb_css_syntax_cb_at_rule_t *at_rule = rule->cbx.at_rule; + + rule->phase = lxb_css_syntax_parser_end; + rule->state = lxb_css_state_success; + + status = at_rule->prelude_end(parser, token, rule->context, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_prelude_end_consule_token(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + const lxb_css_syntax_cb_at_rule_t *at_rule = rule->cbx.at_rule; + + rule->phase = lxb_css_syntax_parser_end_consume_token; + + status = at_rule->prelude_end(parser, token, rule->context, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_at_back_to_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_at_rule; + rule->state = rule->back_state; + rule->skip_consume = false; + + return token; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + const lxb_css_log_message_t *msg; + + if (rule->offset > token->offset) { + return token; + } + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + if (rule->block_end == token->type && rule->deep == 0) { + goto done; + } + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_qualified_rule_block; + rule->back = lxb_css_syntax_parser_end_back; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); + } + + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + if (rule->deep != 0) { + if (parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + } + else { + msg = lxb_css_log_format(parser->log, + LXB_CSS_LOG_SYNTAX_ERROR, + "%S", &lxb_css_err_rc); + if (msg == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + if (rule->nested) { + goto done; + } + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + if (rule->deep != 0 && parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + goto done; + + default: + return token; + } + + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->deep++; + + return token; + +done: + + rule->phase = lxb_css_syntax_parser_qualified_prelude_end; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_rule_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + const lxb_css_syntax_cb_qualified_rule_t *qualified_rule; + + qualified_rule = rule->cbx.qualified_rule; + + parser->status = qualified_rule->prelude_end(parser, token, + rule->context, rule->failed); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + + return lxb_css_syntax_parser_block_begin(parser, token, rule, + qualified_rule->prelude, + qualified_rule->block); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_prelude_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + const lxb_css_syntax_cb_qualified_rule_t *qualified_rule; + + qualified_rule = rule->cbx.qualified_rule; + + parser->status = qualified_rule->prelude_end(parser, token, + rule->context, rule->failed); + if (parser->status != LXB_STATUS_OK) { + return NULL; + } + + rule->phase = lxb_css_syntax_parser_end; + rule->state = lxb_css_state_success; + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_qualified_back_to_prelude(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_qualified_rule; + rule->state = rule->back_state; + rule->skip_consume = false; + + return token; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + lxb_css_parser_state_f back_state, + lxb_css_syntax_begin_block_f cb) +{ + void *block_ctx; + lxb_css_syntax_rule_t *block; + const lxb_css_syntax_cb_block_t *cb_block; + + block_ctx = NULL; + rule->skip_consume = false; + + cb_block = cb(parser, token, rule->context, &block_ctx); + if (cb_block == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + block = lxb_css_syntax_parser_block_push(parser, cb_block, back_state, + block_ctx); + if (block == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + lxb_css_syntax_token_consume(parser->tkz); + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + if (rule->offset > token->offset) { + return token; + } + +begin: + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + + goto begin; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_end_consume_token; + break; + } + + if (parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + rule->phase = lxb_css_syntax_parser_end; + break; + + case LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD: + rule->phase = lxb_css_syntax_parser_block_at; + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + if (lxb_css_syntax_tokenizer_lookup_colon(parser->tkz)) { + rule->phase = lxb_css_syntax_parser_block_declarations; + break; + } + + /* Fall Through. */ + + default: + rule->phase = lxb_css_syntax_parser_block_qualified; + break; + } + + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, 0); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_at(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + const lxb_css_syntax_cb_block_t *block = rule->cbx.block; + + return lxb_css_syntax_parser_at_begin(parser, token, rule, + block->next, block->at_rule, true); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + void *declr_ctx; + lxb_css_syntax_rule_t *declr_rule; + lxb_css_syntax_begin_declarations_f cb; + const lxb_css_syntax_cb_block_t *block; + const lxb_css_syntax_cb_declarations_t *cb_declr; + + declr_ctx = NULL; + block = rule->cbx.block; + cb = block->declarations; + + rule->skip_consume = false; + + cb_declr = cb(parser, token, rule->context, &declr_ctx); + if (cb_declr == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + declr_rule = lxb_css_syntax_parser_declarations_push(parser, cb_declr, + block->next, declr_ctx, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET, + false, true); + if (declr_rule == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_qualified(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + void *qualified_ctx; + lxb_css_syntax_rule_t *qualified; + const lxb_css_syntax_cb_block_t *block; + lxb_css_syntax_begin_qualified_rule_f cb; + const lxb_css_syntax_cb_qualified_rule_t *cb_qualified; + + qualified_ctx = NULL; + block = rule->cbx.block; + cb = block->qualified_rule; + + rule->skip_consume = false; + + cb_qualified = cb(parser, token, rule->context, &qualified_ctx); + if (cb_qualified == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + qualified = lxb_css_syntax_parser_qualified_push(parser, cb_qualified, + block->next, qualified_ctx, + LXB_CSS_SYNTAX_TOKEN_SEMICOLON, + true); + if (qualified == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_MEMORY_ALLOCATION); + } + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_block_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_block; + rule->state = rule->back_state; + rule->skip_consume = true; + + return token; +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_validate(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ +begin: + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_IDENT: + if (lxb_css_syntax_tokenizer_lookup_colon(parser->tkz)) { + return lxb_css_syntax_parser_declarations_begin(parser, token, rule); + } + + break; + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + + goto begin; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + rule->phase = lxb_css_syntax_parser_declarations_end; + rule->context_old = rule->context; + + return lxb_css_syntax_token_parser_do_phase_again(parser); + + default: + break; + } + + rule->phase = lxb_css_syntax_parser_declarations_drop; + rule->state = rule->cbx.cb->failed; + rule->begin = token->offset; + rule->context_old = rule->context; + rule->context = NULL; + rule->failed = true; + + parser->offset.value_end = 0; + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_begin(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + void *declr_ctx; + lxb_css_syntax_declaration_name_f cb; + + declr_ctx = NULL; + cb = rule->cbx.declarations->name; + + rule->state = cb(parser, token, rule->context, &declr_ctx); + if (rule->state == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + rule->phase = lxb_css_syntax_parser_declarations_name; + rule->context_old = rule->context; + rule->context = declr_ctx; + rule->skip_consume = false; + + lxb_css_syntax_token_consume(parser->tkz); + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_name(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + /* 1. */ + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + } + + /* 2. */ + + if (token->type != LXB_CSS_SYNTAX_TOKEN_COLON) { + /* Parse error. */ + + /* + * It can't be. + * + * Before entering the lxb_css_syntax_parser_declarations_name() + * function, data validation takes place. In fact, these checks are not + * needed here. + */ + + /* + * But it's good for validation, if we come here it means we're + * doing badly. + */ + + return NULL; + } + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + /* 3. */ + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + } + + rule->begin = token->offset; + parser->offset.value_end = 0; + + /* 4. */ + + rule->phase = lxb_css_syntax_parser_declarations_value; + + return lxb_css_syntax_parser_declarations_value(parser, token, rule); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + bool imp; + size_t offset; + lxb_status_t status; + + if (rule->offset > token->offset) { + return token; + } + +again: + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + if (rule->block_end == token->type && rule->deep == 0) { + goto done; + } + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + if (rule->deep != 0) { + return token; + } + + imp = lxb_css_syntax_tokenizer_lookup_declaration_ws_end(parser->tkz, + rule->block_end, + (rule->block_end == LXB_CSS_SYNTAX_TOKEN_RC_BRACKET) ? 0x7D : 0x00); + + if (!imp) { + return token; + } + + parser->offset.value_end = token->offset; + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + /* Have !important? */ + + if (token->type == LXB_CSS_SYNTAX_TOKEN_DELIM) { + rule->important = true; + parser->offset.important_begin = token->offset; + + lxb_css_syntax_token_consume(parser->tkz); + + /* Skip important */ + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + parser->offset.important_end = token->offset + + lxb_css_syntax_token_base(token)->length; + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + } + } + else { + parser->offset.important_begin = 0; + parser->offset.important_end = 0; + } + + goto again; + + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_declarations_next; + + offset = token->offset; + + parser->offset.value_begin = rule->begin; + parser->offset.end = offset; + + if (parser->offset.value_end == 0) { + parser->offset.value_end = offset; + parser->offset.important_begin = 0; + parser->offset.important_end = 0; + } + + lxb_css_syntax_token_consume(parser->tkz); + + return lxb_css_parser_token_end(parser, offset); + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_DELIM: + if (lxb_css_syntax_token_delim(token)->character != '!') { + return token; + } + + imp = lxb_css_syntax_tokenizer_lookup_important(parser->tkz, + rule->block_end, + (rule->block_end == LXB_CSS_SYNTAX_TOKEN_RC_BRACKET) ? 0x7D : 0x00); + + if (!imp) { + return token; + } + + rule->important = true; + + parser->offset.value_end = token->offset; + parser->offset.important_begin = token->offset; + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + parser->offset.important_end = token->offset + + lxb_css_syntax_token_base(token)->length; + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, parser->tkz->status); + } + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + } + + goto again; + + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + if (rule->deep != 0 && parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + goto done; + + default: + return token; + } + + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->deep++; + + return token; + +done: + + parser->offset.value_begin = rule->begin; + parser->offset.end = token->offset; + + if (parser->offset.value_end == 0) { + parser->offset.value_end = token->offset; + parser->offset.important_begin = 0; + parser->offset.important_end = 0; + } + + rule->phase = lxb_css_syntax_parser_declaration_end; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_drop(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + size_t offset; + lxb_status_t status; + + if (rule->offset > token->offset) { + return token; + } + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + if (rule->block_end == token->type && rule->deep == 0) { + goto done; + } + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_declarations_next; + + offset = token->offset; + + parser->offset.value_begin = rule->begin; + parser->offset.end = offset; + + if (parser->offset.value_end == 0) { + parser->offset.value_end = offset; + parser->offset.important_begin = 0; + parser->offset.important_end = 0; + } + + lxb_css_syntax_token_consume(parser->tkz); + + return lxb_css_parser_token_end(parser, offset); + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + if (rule->deep == 0) { + if (rule->nested) { + goto done; + } + } + else if (parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + if (rule->deep != 0 && parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + goto done; + + default: + return token; + } + + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->deep++; + + return token; + +done: + + parser->offset.value_begin = rule->begin; + parser->offset.end = token->offset; + + if (parser->offset.value_end == 0) { + parser->offset.value_end = token->offset; + parser->offset.important_begin = 0; + parser->offset.important_end = 0; + } + + rule->phase = lxb_css_syntax_parser_declaration_end; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_next(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + void *out_rule; + lxb_status_t status; + lxb_css_syntax_declaration_name_f name; + + if (rule->state != lxb_css_state_success) { + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); + } + + status = rule->cbx.declarations->end(parser, rule->context_old, + rule->context, token, &parser->offset, + rule->important, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + +begin: + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + + goto begin; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + rule->phase = lxb_css_syntax_parser_declarations_end; + break; + + case LXB_CSS_SYNTAX_TOKEN_IDENT: + if (lxb_css_syntax_tokenizer_lookup_colon(parser->tkz)) { + out_rule = NULL; + name = rule->cbx.declarations->name; + rule->skip_consume = true; + + rule->state = name(parser, token, rule->context, &out_rule); + if (rule->state == NULL) { + return lxb_css_syntax_parser_failed(parser, + LXB_STATUS_ERROR_UNEXPECTED_DATA); + } + + rule->context = out_rule; + + lxb_css_syntax_token_consume(parser->tkz); + + rule->phase = lxb_css_syntax_parser_declarations_name; + rule->context = out_rule; + + break; + } + + /* Fall through. */ + + default: + if (rule->nested) { + rule->phase = lxb_css_syntax_parser_declarations_end; + } + else { + rule->phase = lxb_css_syntax_parser_declarations_drop; + rule->state = rule->cbx.cb->failed; + rule->begin = token->offset; + rule->context = NULL; + rule->failed = true; + + parser->offset.value_end = 0; + + return lxb_css_syntax_token_parser_do_phase_again(parser); + } + + break; + } + + rule->skip_consume = false; + rule->important = false; + rule->failed = false; + + return lxb_css_syntax_token_parser_do_phase_again(parser); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declaration_back_to_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_declarations_value; + rule->state = rule->back_state; + rule->skip_consume = false; + + return token; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declaration_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + return lxb_css_syntax_parser_declaration_end_handler(parser, token, + rule, false); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declaration_end_handler(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + bool skip_token) +{ + lxb_status_t status; + + if (rule->state != lxb_css_state_success) { + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); + } + + status = rule->cbx.declarations->end(parser, rule->context_old, + rule->context, token, &parser->offset, + rule->important, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + return lxb_css_syntax_parser_declarations_end_h(parser, token, + rule, skip_token); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + return lxb_css_syntax_parser_declarations_end_h(parser, token, + rule, false); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_declarations_end_h(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule, + bool skip_token) +{ + lxb_status_t status; + + /* This code will be called exclusively from the lxb_css_parser_run(...). */ + + rule->context = rule->context_old; + + status = rule->cbx.cb->end(parser, token, rule->context, false); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + if (skip_token) { + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + } + + return lxb_css_syntax_parser_call_back(parser, token); +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_components(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + + if (rule->offset > token->offset) { + return token; + } + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + if (rule->block_end == token->type && rule->deep == 0) { + goto done; + } + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + if (rule->deep != 0 && parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + goto done; + + default: + return token; + } + + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->deep++; + + return token; + +done: + + rule->phase = lxb_css_syntax_parser_end; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_components_back_to_value(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_components; + rule->state = rule->back_state; + rule->skip_consume = false; + + return token; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + + if (rule->offset > token->offset) { + return token; + } + + rule->offset = token->offset + lxb_css_syntax_token_base(token)->length; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS); + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + status = lxb_css_parser_types_push(parser, + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET); + break; + + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + if (rule->deep == 0) { + rule->phase = lxb_css_syntax_parser_end_consume_token; + goto done; + } + + if (parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + if (rule->deep != 0 && parser->types_pos[-1] == token->type) { + parser->types_pos--; + rule->deep--; + } + + return token; + + case LXB_CSS_SYNTAX_TOKEN__EOF: + rule->phase = lxb_css_syntax_parser_end; + goto done; + + default: + return token; + } + + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->deep++; + + return token; + +done: + + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_function_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_function; + rule->state = rule->back_state; + rule->skip_consume = false; + + return token; +} + +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_pipe(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + if ((rule->block_end == token->type && rule->deep == 0) + || token->type == LXB_CSS_SYNTAX_TOKEN__EOF) + { + rule->phase = lxb_css_syntax_parser_end; + rule->skip_consume = true; + + return lxb_css_parser_token_end(parser, token->offset); + } + + return token; +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_pipe_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_pipe; + rule->state = rule->back_state; + rule->skip_consume = false; + + return token; +} + +/* + * This code will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ +static const lxb_css_syntax_token_t * +lxb_css_syntax_parser_end_back(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + rule->phase = lxb_css_syntax_parser_end; + rule->state = lxb_css_state_blank; + + return token; +} + +const lxb_css_syntax_token_t * +lxb_css_syntax_parser_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + lxb_css_syntax_cb_base_t *base; + + rule->skip_consume = true; + + if (rule->state != lxb_css_state_success) { + return lxb_css_parser_token_end(parser, token->offset); + } + + /* This code will be called exclusively from the lxb_css_parser_run(...). */ + + base = rule->cbx.user; + + status = base->end(parser, token, rule->context, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->skip_consume = false; + + return lxb_css_syntax_parser_call_back(parser, token); +} + +const lxb_css_syntax_token_t * +lxb_css_syntax_parser_end_consume_token(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule) +{ + lxb_status_t status; + lxb_css_syntax_cb_base_t *base; + + rule->skip_consume = true; + + if (rule->state != lxb_css_state_success) { + return lxb_css_parser_token_end(parser, token->offset); + } + + /* This code will be called exclusively from the lxb_css_parser_run(...). */ + + base = rule->cbx.user; + + status = base->end(parser, token, rule->context, rule->failed); + if (status != LXB_STATUS_OK) { + return lxb_css_syntax_parser_failed(parser, status); + } + + rule->skip_consume = false; + + lxb_css_syntax_token_consume(parser->tkz); + + token = lxb_css_syntax_token(parser->tkz); + if (token == NULL) { + return lxb_css_syntax_parser_failed(parser, + parser->tkz->status); + } + + return lxb_css_syntax_parser_call_back(parser, token); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/parser.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/parser.h new file mode 100644 index 0000000..524da6b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/parser.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2020-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_PARSER_H +#define LEXBOR_CSS_SYNTAX_PARSER_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "lexbor/css/base.h" + + +LXB_API lxb_status_t +lxb_css_syntax_parser_run(lxb_css_parser_t *parser); + +LXB_API const lxb_css_syntax_token_t * +lxb_css_syntax_parser_token(lxb_css_parser_t *parser); + +LXB_API const lxb_css_syntax_token_t * +lxb_css_syntax_parser_token_wo_ws(lxb_css_parser_t *parser); + +LXB_API void +lxb_css_syntax_parser_consume(lxb_css_parser_t *parser); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_list_rules_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_list_rules_t *list_rules, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_at_rule_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_at_rule_t *at_rule, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop, + bool nested); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_qualified_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_qualified_rule_t *qualified, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop, + bool nested); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_block_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_block_t *block, + lxb_css_parser_state_f back, void *ctx); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_declarations_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_declarations_t *declr, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop, + bool name_validate, bool nested); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_components_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_components_t *comp, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_function_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_function_t *func, + lxb_css_parser_state_f back, void *ctx); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_parser_pipe_push(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_pipe_t *pipe, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop); + +LXB_API const lxb_css_syntax_token_t * +lxb_css_syntax_parser_end(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + +LXB_API const lxb_css_syntax_token_t * +lxb_css_syntax_parser_end_consume_token(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_PARSER_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/res.h new file mode 100644 index 0000000..7fa2f8b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/res.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_RES_H +#define LEXBOR_CSS_SYNTAX_RES_H + +#define LXB_CSS_SYNTAX_RES_NAME_START 0x01 + +LXB_API const lxb_char_t lxb_css_syntax_res_name_map[256] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01 +}; + +#endif /* LEXBOR_CSS_SYNTAX_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state.c new file mode 100644 index 0000000..5b694e9 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state.c @@ -0,0 +1,1852 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include +#include + +#include "lexbor/core/utils.h" +#include "lexbor/core/strtod.h" + +#include "lexbor/css/syntax/state.h" +#include "lexbor/css/syntax/syntax.h" +#include "lexbor/css/syntax/tokenizer/error.h" + +#include "lexbor/css/syntax/res.h" + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_map_hex[256]; +#endif + +#define LXB_CSS_SYNTAX_ERROR_CODEPOINT 0x1FFFFF + +#define lxb_css_syntax_buffer_append_m(_tkz, _begin, _length) \ + do { \ + if ((_length) > 0) { \ + lxb_status_t status = lxb_css_syntax_string_append(_tkz, \ + (const lxb_char_t *) (_begin), \ + _length); \ + if (status != LXB_STATUS_OK) { \ + return NULL; \ + } \ + } \ + } \ + while (0) + +#define LXB_CSS_SYNTAX_CARRIAGE_RETURN_BLOCK(tkz, begin, data, end) \ + { \ + lxb_css_syntax_buffer_append_m(tkz, begin, ((data) - (begin)) + 1); \ + (tkz)->pos[-1] = 0x0A; \ + \ + /* U+000A LINE FEED (LF) */ \ + if ((data) + 1 < (end) && (data)[1] == 0x0A) { \ + (data) += 1; \ + } \ + \ + (begin) = (data) + 1; \ + } + +#define LXB_CSS_SYNTAX_FORM_FEED_BLOCK(tkz, begin, data, end) \ + { \ + lxb_css_syntax_buffer_append_m(tkz, begin, ((data) - (begin)) + 1); \ + (tkz)->pos[-1] = 0x0A; \ + \ + (begin) = (data) + 1; \ + } + +#define LXB_CSS_SYNTAX_NULL_BLOCK(tkz, begin, data, end) \ + { \ + lxb_css_syntax_buffer_append_m(tkz, begin, ((data) - (begin))); \ + \ + /* U+FFFD REPLACEMENT CHARACTER */ \ + lxb_css_syntax_buffer_append_m(tkz, "\uFFFD", \ + lxb_css_syntax_replacement_length); \ + (begin) = (data) + 1; \ + } + +#define LXB_CSS_SYNTAX_UTF_8_UP_80_BLOCK(tkz, begin, data, end) \ + const lxb_char_t *_bad = data; \ + lxb_codepoint_t cp = lxb_css_syntax_state_decode_utf_8_up_80(&data, \ + end); \ + \ + if (cp == LXB_CSS_SYNTAX_ERROR_CODEPOINT) { \ + /* Flush the run before the ill-formed sequence, then U+FFFD. */ \ + lxb_css_syntax_buffer_append_m(tkz, begin, _bad - begin); \ + /* U+FFFD REPLACEMENT CHARACTER */ \ + lxb_css_syntax_buffer_append_m(tkz, "\uFFFD", \ + lxb_css_syntax_replacement_length);\ + begin = data; \ + } + + +static const size_t lxb_css_syntax_replacement_length = 3; /* sizeof("\uFFFD") - 1 */ + + +static const lxb_char_t * +lxb_css_syntax_state_consume_numeric(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end); + +static const lxb_char_t * +lxb_css_syntax_state_consume_numeric_name_start(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end); + +static const lxb_char_t * +lxb_css_syntax_state_consume_ident(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +static const lxb_char_t * +lxb_css_syntax_state_consume_unicode_range(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end); + +static const lxb_char_t * +lxb_css_syntax_state_url(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +static const lxb_char_t * +lxb_css_syntax_state_bad_url(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +static const lxb_char_t * +lxb_css_syntax_state_escaped(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *data, const lxb_char_t *end); + +static bool +lxb_css_syntax_state_start_number(const lxb_char_t *data, const lxb_char_t *end); + +static bool +lxb_css_syntax_state_start_ident_sequence(const lxb_char_t *data, + const lxb_char_t *end); + +static lxb_codepoint_t +lxb_css_syntax_state_decode_utf_8_up_80(const lxb_char_t **data, + const lxb_char_t *end); + + +lxb_inline bool +lxb_css_syntax_state_valid_escape(const lxb_char_t *data, + const lxb_char_t *end) +{ + /* U+005C REVERSE SOLIDUS (\) */ + if (*data == 0x5C) { + data += 1; + if (data >= end || (*data != 0x0A && *data != 0x0C && *data != 0x0D)) { + return true; + } + } + + return false; +} + +lxb_inline bool +lxb_css_syntax_state_non_ascii(lxb_codepoint_t cp) +{ + /* This code is generated by the file utils/lexbor/css/syntax/non_ascii.pl */ + + /* Begin */ + if (cp <= 0x2040) { + if (cp <= 0x00F6) { + if (cp >= 0x00B7 && cp <= 0x00B7) { + return true; + } + else if (cp >= 0x00C0) { + if (cp <= 0x00D6) { + return true; + } + else if (cp >= 0x00D8) { + return true; + } + } + } + else if (cp >= 0x00F8) { + if (cp <= 0x1FFF) { + if (cp <= 0x037D) { + return true; + } + else if (cp >= 0x037F) { + return true; + } + } + else if (cp >= 0x200C) { + if (cp <= 0x200D) { + return true; + } + else if (cp >= 0x203F) { + return true; + } + } + } + } + else if (cp >= 0x2070) { + if (cp <= 0xD7FF) { + if (cp <= 0x218F) { + return true; + } + else if (cp >= 0x2C00) { + if (cp <= 0x2FEF) { + return true; + } + else if (cp >= 0x3001) { + return true; + } + } + } + else if (cp >= 0xF900) { + if (cp <= 0xFFFD) { + if (cp <= 0xFDCF) { + return true; + } + else if (cp >= 0xFDF0) { + return true; + } + } + else if (cp >= 0x10000) { + if (cp <= 0x10FFFF) { + return true; + } + } + } + } + /* End */ + + return false; +} + +lxb_inline bool +lxb_css_syntax_state_start_ident_utf_8_80(const lxb_char_t **data, + const lxb_char_t *end) +{ + lxb_codepoint_t cp; + + cp = lxb_css_syntax_state_decode_utf_8_up_80(data, end); + if (cp == LXB_CSS_SYNTAX_ERROR_CODEPOINT) { + return true; /* To be replaced by \uFFFD. */ + } + + return lxb_css_syntax_state_non_ascii(cp); +} + +lxb_inline lxb_status_t +lxb_css_syntax_string_realloc(lxb_css_syntax_tokenizer_t *tkz, size_t upto) +{ + size_t len = tkz->pos - tkz->start; + size_t size = (tkz->end - tkz->start) + upto; + + lxb_char_t *tmp = lexbor_realloc(tkz->start, size); + if (tmp == NULL) { + tkz->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + return tkz->status; + } + + tkz->start = tmp; + tkz->pos = tmp + len; + tkz->end = tmp + size; + + return LXB_STATUS_OK; +} + +lxb_inline lxb_status_t +lxb_css_syntax_string_append(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *data, size_t length) +{ + if ((size_t) (tkz->end - tkz->pos) <= length) { + if (lxb_css_syntax_string_realloc(tkz, length + 1024) != LXB_STATUS_OK) { + return tkz->status; + } + } + + memcpy(tkz->pos, data, length); + + tkz->pos += length; + + return LXB_STATUS_OK; +} + +lxb_inline lxb_status_t +lxb_css_syntax_state_string_term(lxb_css_syntax_tokenizer_t *tkz) +{ + if (tkz->pos >= tkz->end) { + if (lxb_css_syntax_string_realloc(tkz, 1024) != LXB_STATUS_OK) { + return tkz->status; + } + } + + *tkz->pos = 0x00; + + return LXB_STATUS_OK; +} + +lxb_inline const lxb_char_t * +lxb_css_syntax_state_string_set(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data) +{ + if(lxb_css_syntax_state_string_term(tkz) != LXB_STATUS_OK) { + return NULL; + } + + lxb_css_syntax_token_string(token)->data = tkz->start; + lxb_css_syntax_token_string(token)->length = tkz->pos - tkz->start; + + tkz->pos = tkz->start; + + return data; +} + +lxb_inline const lxb_char_t * +lxb_css_syntax_state_dimension_set(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data) +{ + if(lxb_css_syntax_state_string_term(tkz) != LXB_STATUS_OK) { + return NULL; + } + + lxb_css_syntax_token_dimension_string(token)->data = tkz->start; + lxb_css_syntax_token_dimension_string(token)->length = tkz->pos - tkz->start; + + tkz->pos = tkz->start; + + return data; +} + +/* + * Delim + */ +lxb_inline const lxb_char_t * +lxb_css_syntax_state_delim_set(lxb_css_syntax_token_t *token, + const lxb_char_t *data, lxb_char_t ch) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_DELIM; + + lxb_css_syntax_token_delim(token)->character = (lxb_codepoint_t) ch; + lxb_css_syntax_token_base(token)->length = 1; + + return data + 1; +} + +lxb_inline const lxb_char_t * +lxb_css_syntax_state_delim_set_cp(lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + lxb_codepoint_t cp; + + if (*data < 0x80) { + cp = *data++; + } + else { + cp = lxb_css_syntax_state_decode_utf_8_up_80(&data, end); + } + + token->type = LXB_CSS_SYNTAX_TOKEN_DELIM; + + lxb_css_syntax_token_delim(token)->character = cp; + + return data; +} + +const lxb_char_t * +lxb_css_syntax_state_delim(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + lxb_css_syntax_state_delim_set(token, data, *data); + + return data + 1; +} + +/* + * Comment + */ +const lxb_char_t * +lxb_css_syntax_state_comment(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + bool failed; + const lxb_char_t *begin; + + /* Skip forward slash (/) */ + data += 1; + + /* U+002A ASTERISK (*) */ + if (data >= end || *data != 0x2A) { + return lxb_css_syntax_state_delim_set(token, data - 1, '/'); + } + + /* Skip U+002A ASTERISK (*) */ + begin = ++data; + failed = true; + + while (data < end) { + switch (*data) { + /* U+002A ASTERISK (*) */ + case 0x2A: + data += 1; + + if (data >= end) { + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + goto done; + } + + /* U+002F Forward slash (/) */ + if (*data == 0x2F) { + lxb_css_syntax_buffer_append_m(tkz, begin, + (data - begin) - 1); + data += 1; + failed = false; + goto done; + } + + continue; + + /* U+000D CARRIAGE RETURN (CR) */ + case 0x0D: + LXB_CSS_SYNTAX_CARRIAGE_RETURN_BLOCK(tkz, begin, data, end) + break; + + /* U+000C FORM FEED (FF) */ + case 0x0C: + LXB_CSS_SYNTAX_FORM_FEED_BLOCK(tkz, begin, data, end) + break; + + /* U+0000 NULL */ + case 0x00: + LXB_CSS_SYNTAX_NULL_BLOCK(tkz, begin, data, end) + break; + + default: + if (*data >= 0x80) { + LXB_CSS_SYNTAX_UTF_8_UP_80_BLOCK(tkz, begin, data, end) + continue; + } + + break; + } + + data += 1; + } + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + +done: + + if (failed) { + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINCO); + } + + token->type = LXB_CSS_SYNTAX_TOKEN_COMMENT; + + return lxb_css_syntax_state_string_set(tkz, token, data); +} + +/* + * Whitespace + */ +const lxb_char_t * +lxb_css_syntax_state_whitespace(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + const lxb_char_t *begin; + + begin = data; + + do { + switch (*data) { + /* U+000D CARRIAGE RETURN (CR) */ + case 0x0D: + LXB_CSS_SYNTAX_CARRIAGE_RETURN_BLOCK(tkz, begin, data, end) + break; + + /* U+000C FORM FEED (FF) */ + case 0x0C: + LXB_CSS_SYNTAX_FORM_FEED_BLOCK(tkz, begin, data, end) + break; + + case 0x09: + case 0x20: + case 0x0A: + break; + + default: + goto done; + } + + data += 1; + } + while (data < end); + +done: + + token->type = LXB_CSS_SYNTAX_TOKEN_WHITESPACE; + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + return lxb_css_syntax_state_string_set(tkz, token, data); +} + +/* + * String token for U+0022 Quotation Mark (") and U+0027 Apostrophe (') + */ +const lxb_char_t * +lxb_css_syntax_state_string(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + lxb_char_t mark; + const lxb_char_t *begin; + lxb_codepoint_t cp; + + mark = *data++; + begin = data; + + token->type = LXB_CSS_SYNTAX_TOKEN_STRING; + + while (data < end) { + switch (*data) { + /* U+0000 NULL */ + case 0x00: + LXB_CSS_SYNTAX_NULL_BLOCK(tkz, begin, data, end) + break; + + /* + * U+000A LINE FEED + * U+000D CARRIAGE RETURN + * U+000C FORM FEED + */ + case 0x0A: + case 0x0D: + case 0x0C: + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_NEINST); + + token->type = LXB_CSS_SYNTAX_TOKEN_BAD_STRING; + + goto done; + + /* U+005C REVERSE SOLIDUS (\) */ + case 0x5C: + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + data += 1; + begin = data; + + if (data >= end) { + data = lxb_css_syntax_state_escaped(tkz, data, end); + begin = data; + continue; + } + + switch (*data) { + /* U+000D CARRIAGE RETURN (CR) */ + case 0x0D: + /* U+000A LINE FEED (LF) */ + if (data + 1 < end && data[1] == 0x0A) { + data += 1; + } + + begin = data + 1; + break; + + /* U+000C FORM FEED (FF) */ + case 0x0A: + case 0x0C: + begin = data + 1; + break; + + /* U+0000 NULL */ + case 0x00: + LXB_CSS_SYNTAX_NULL_BLOCK(tkz, begin, data, end) + break; + + default: + if (*data < 0x80) { + data = lxb_css_syntax_state_escaped(tkz, data, end); + begin = data; + } + else { + cp = lxb_css_syntax_state_decode_utf_8_up_80(&data, end); + + if (cp == LXB_CSS_SYNTAX_ERROR_CODEPOINT) { + /* U+FFFD REPLACEMENT CHARACTER */ + lxb_css_syntax_buffer_append_m(tkz, "\uFFFD", + lxb_css_syntax_replacement_length); + begin = data; + } + } + + continue; + } + + break; + + default: + /* '"' or '\'' */ + if (*data == mark) { + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + return lxb_css_syntax_state_string_set(tkz, token, data + 1); + } + + if (*data >= 0x80) { + LXB_CSS_SYNTAX_UTF_8_UP_80_BLOCK(tkz, begin, data, end) + continue; + } + + break; + } + + data += 1; + } + + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINST); +done: + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + return lxb_css_syntax_state_string_set(tkz, token, data); +} + +/* + * U+0023 NUMBER SIGN (#) + */ +const lxb_char_t * +lxb_css_syntax_state_hash(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, const lxb_char_t *data, + const lxb_char_t *end) +{ + lxb_char_t ch; + const lxb_char_t *begin; + + data += 1; + if (data >= end) { + return lxb_css_syntax_state_delim_set(token, data - 1, '#'); + } + + if (*data >= 0x80) { + begin = data; + + if (lxb_css_syntax_state_start_ident_utf_8_80(&data, end)) { + data = begin; + goto hash; + } + + return lxb_css_syntax_state_delim_set(token, begin - 1, '#'); + } + + if (lxb_css_syntax_res_name_map[*data] == 0x00) { + if (*data == 0x00) { + goto hash; + } + + /* U+005C REVERSE SOLIDUS (\) */ + if (*data != 0x5C) { + if (*data >= 0x80) { + begin = data; + + if (lxb_css_syntax_state_start_ident_utf_8_80(&data, end)) { + data = begin; + goto hash; + } + } + + return lxb_css_syntax_state_delim_set(token, data - 1, '#'); + } + + data += 1; + + if (data < end) { + ch = *data; + + if (ch == 0x0A || ch == 0x0C || ch == 0x0D) { + return lxb_css_syntax_state_delim_set(token, data - 2, '#'); + } + } + + data -= 1; + } + +hash: + + token->type = LXB_CSS_SYNTAX_TOKEN_HASH; + + return lxb_css_syntax_state_consume_ident(tkz, token, data, end); +} + +/* + * U+0028 LEFT PARENTHESIS (() + */ +const lxb_char_t * +lxb_css_syntax_state_lparenthesis(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS; + return data + 1; +} + +/* + * U+0029 RIGHT PARENTHESIS ()) + */ +const lxb_char_t * +lxb_css_syntax_state_rparenthesis(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS; + return data + 1; +} + +/* + * U+002B PLUS SIGN (+) + */ +const lxb_char_t * +lxb_css_syntax_state_plus(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + /* Skip U+002B PLUS SIGN (+). */ + data += 1; + + if (data >= end) { + return lxb_css_syntax_state_delim_set(token, data - 1, '+'); + } + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (*data >= 0x30 && *data <= 0x39) { + lxb_css_syntax_token_number(token)->have_sign = true; + return lxb_css_syntax_state_consume_numeric(tkz, token, data, end); + } + + /* U+002E FULL STOP (.) */ + if (*data == 0x2E) { + data += 1; + + if (data >= end) { + return lxb_css_syntax_state_delim_set(token, data - 2, '+'); + } + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (*data >= 0x30 && *data <= 0x39) { + lxb_css_syntax_token_number(token)->have_sign = true; + return lxb_css_syntax_state_consume_numeric(tkz, token, + data - 1, end); + } + + data -= 1; + } + + return lxb_css_syntax_state_delim_set(token, data - 1, '+'); +} + +/* + * U+002C COMMA (,) + */ +const lxb_char_t * +lxb_css_syntax_state_comma(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_COMMA; + return data + 1; +} + +/* + * U+002D HYPHEN-MINUS (-) + */ +const lxb_char_t * +lxb_css_syntax_state_minus(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + lxb_css_syntax_token_number_t *number; + + /* Check for */ + + if (lxb_css_syntax_state_start_number(data, end)) { + data = lxb_css_syntax_state_consume_numeric(tkz, token, data + 1, end); + + number = lxb_css_syntax_token_number(token); + number->num = -number->num; + + lxb_css_syntax_token_number(token)->have_sign = true; + + return data; + } + + /* Check for */ + + if (data + 3 <= end) { + /* U+002D HYPHEN-MINUS U+003E GREATER-THAN SIGN (->) */ + if (data[1] == 0x2D && data[2] == 0x3E) { + token->type = LXB_CSS_SYNTAX_TOKEN_CDC; + return data + 3; + } + } + + if (lxb_css_syntax_state_start_ident_sequence(data, end)) { + return lxb_css_syntax_state_ident_like_not_url(tkz, token, + data, end); + } + + return lxb_css_syntax_state_delim_set(token, data, '-'); +} + +/* + * U+002E FULL STOP (.) + */ +const lxb_char_t * +lxb_css_syntax_state_full_stop(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + if (lxb_css_syntax_state_start_number(data, end)) { + lxb_css_syntax_token_number(token)->have_sign = false; + return lxb_css_syntax_state_consume_numeric(tkz, token, data, end); + } + + return lxb_css_syntax_state_delim_set(token, data, '.'); +} + +/* + * U+003A COLON (:) + */ +const lxb_char_t * +lxb_css_syntax_state_colon(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_COLON; + return data + 1; +} + +/* + * U+003B SEMICOLON (;) + */ +const lxb_char_t * +lxb_css_syntax_state_semicolon(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_SEMICOLON; + return data + 1; +} + +/* + * U+003C LESS-THAN SIGN (<) + */ +const lxb_char_t * +lxb_css_syntax_state_less_sign(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + if (data + 4 <= end) { + /* U+0021 EXCLAMATION MARK + * U+002D HYPHEN-MINUS + * U+002D HYPHEN-MINUS + * (!--) + */ + if (data[1] == 0x21 && data[2] == 0x2D && data[3] == 0x2D) { + token->type = LXB_CSS_SYNTAX_TOKEN_CDO; + return data + 4; + } + } + + return lxb_css_syntax_state_delim_set(token, data, '<'); +} + +/* + * U+0040 COMMERCIAL AT (@) + */ +const lxb_char_t * +lxb_css_syntax_state_at(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + /* Skip U+0040 COMMERCIAL AT (@) */ + data += 1; + + if (lxb_css_syntax_state_start_ident_sequence(data, end)) { + token->type = LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD; + + return lxb_css_syntax_state_consume_ident(tkz, token, data, end); + } + + return lxb_css_syntax_state_delim_set(token, data - 1, '@'); +} + +/* + * U+005B LEFT SQUARE BRACKET ([) + */ +const lxb_char_t * +lxb_css_syntax_state_ls_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_LS_BRACKET; + return data + 1; +} + +/* + * U+005C REVERSE SOLIDUS (\) + */ +const lxb_char_t * +lxb_css_syntax_state_rsolidus(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + if (lxb_css_syntax_state_valid_escape(data, end)) { + return lxb_css_syntax_state_ident_like(tkz, token, data, end); + } + + return lxb_css_syntax_state_delim_set(token, data, '\\'); +} + +/* + * U+005D RIGHT SQUARE BRACKET (]) + */ +const lxb_char_t * +lxb_css_syntax_state_rs_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_RS_BRACKET; + return data + 1; +} + +/* + * U+007B LEFT CURLY BRACKET ({) + */ +const lxb_char_t * +lxb_css_syntax_state_lc_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_LC_BRACKET; + return data + 1; +} + +/* + * U+007D RIGHT CURLY BRACKET (}) + */ +const lxb_char_t * +lxb_css_syntax_state_rc_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + token->type = LXB_CSS_SYNTAX_TOKEN_RC_BRACKET; + return data + 1; +} + +/* + * Numeric + */ +lxb_inline void +lxb_css_syntax_consume_numeric_set(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *start, const lxb_char_t *end, + bool is_float, bool e_is_negative, + int exponent, int e_digit) +{ + if (e_is_negative) { + exponent = e_digit - exponent; + exponent = -exponent; + } + else { + exponent = e_digit + exponent; + } + + double num = lexbor_strtod_internal(start, (end - start), exponent); + + token->type = LXB_CSS_SYNTAX_TOKEN_NUMBER; + + lxb_css_syntax_token_number(token)->is_float = is_float; + lxb_css_syntax_token_number(token)->num = num; +} + +const lxb_char_t * +lxb_css_syntax_state_consume_before_numeric(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end) +{ + lxb_css_syntax_token_number(token)->have_sign = false; + + return lxb_css_syntax_state_consume_numeric(tkz, token, data, end); +} + +static const lxb_char_t * +lxb_css_syntax_state_consume_numeric(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end) +{ + bool e_is_negative, is_float; + int exponent, e_digit; + lxb_char_t ch, *buf_p; + const lxb_char_t *begin, *buf_end; + lxb_css_syntax_token_t *t_str; + lxb_css_syntax_token_string_t *str; + lxb_char_t buf[128]; + + buf_p = buf; + buf_end = buf + sizeof(buf); + + str = lxb_css_syntax_token_dimension_string(token); + t_str = (lxb_css_syntax_token_t *) (void *) str; + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + while (*data >= 0x30 && *data <= 0x39) { + if (buf_p != buf_end) { + *buf_p++ = *data; + } + + data += 1; + + if (data >= end) { + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + false, false, 0, 0); + return data; + } + } + + exponent = 0; + is_float = false; + + /* U+002E FULL STOP (.) */ + if (*data == 0x2E) { + data += 1; + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (data >= end || *data < 0x30 || *data > 0x39) { + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + false, false, 0, 0); + return data - 1; + } + + begin = buf_p; + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + do { + if (buf_p != buf_end) { + *buf_p++ = *data; + } + + data += 1; + } + while (data < end && *data >= 0x30 && *data <= 0x39); + + exponent = -(int) (buf_p - begin); + is_float = true; + + if (data >= end) { + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + true, false, exponent, 0); + return data; + } + } + + ch = *data; + + /* U+0045 Latin Capital Letter (E) or U+0065 Latin Small Letter (e) */ + if (ch != 0x45 && ch != 0x65) { + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + is_float, false, exponent, 0); + + return lxb_css_syntax_state_consume_numeric_name_start(tkz, token, + data, end); + } + + lxb_css_syntax_token_base(t_str)->begin = data; + + data += 1; + + if (data >= end) { + data -= 1; + + lxb_css_syntax_token_base(t_str)->length = 1; + lxb_css_syntax_buffer_append_m(tkz, data, 1); + + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + is_float, false, exponent, 0); + + token->type = LXB_CSS_SYNTAX_TOKEN_DIMENSION; + + return lxb_css_syntax_state_dimension_set(tkz, token, data + 1); + } + + e_is_negative = false; + + switch (*data) { + /* U+002D HYPHEN-MINUS (-) */ + case 0x2D: + e_is_negative = true; + /* fall through */ + + /* U+002B PLUS SIGN (+) */ + case 0x2B: + data += 1; + break; + + default: + break; + } + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (data >= end || *data < 0x30 || *data > 0x39) { + data -= 1; + if (*data != ch) { + data -= 1; + } + + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + is_float, false, exponent, 0); + + token->type = LXB_CSS_SYNTAX_TOKEN_DIMENSION; + + begin = lxb_css_syntax_state_consume_ident(tkz, t_str, data, end); + + lxb_css_syntax_token_base(t_str)->begin = data; + lxb_css_syntax_token_base(t_str)->length = begin - data; + + return begin; + } + + e_digit = 0; + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + do { + if (e_digit < INT_MAX / 10) { + e_digit = (*data - 0x30) + e_digit * 0x0A; + } + + data += 1; + + if (data >= end) { + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + true, e_is_negative, + exponent, e_digit); + return data; + } + } + while(*data >= 0x30 && *data <= 0x39); + + lxb_css_syntax_consume_numeric_set(tkz, token, buf, buf_p, + true, e_is_negative, + exponent, e_digit); + + return lxb_css_syntax_state_consume_numeric_name_start(tkz, token, + data, end); +} + +static const lxb_char_t * +lxb_css_syntax_state_consume_numeric_name_start(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end) +{ + const lxb_char_t *p; + lxb_css_syntax_token_t *t_str; + lxb_css_syntax_token_string_t *str; + + if (lxb_css_syntax_state_start_ident_sequence(data, end)) { + str = lxb_css_syntax_token_dimension_string(token); + t_str = (lxb_css_syntax_token_t *) (void *) str; + + token->type = LXB_CSS_SYNTAX_TOKEN_DIMENSION; + + p = lxb_css_syntax_state_consume_ident(tkz, t_str, data, end); + + lxb_css_syntax_token_base(t_str)->begin = data; + lxb_css_syntax_token_base(t_str)->length = p - data; + + return p; + } + + /* U+0025 PERCENTAGE SIGN (%) */ + if (*data == 0x25) { + token->type = LXB_CSS_SYNTAX_TOKEN_PERCENTAGE; + return data + 1; + } + + return data; +} + +static const lxb_char_t * +lxb_css_syntax_state_consume_ident(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + const lxb_char_t *begin; + + begin = data; + + while (data < end) { + if (*data < 0x80) { + if (lxb_css_syntax_res_name_map[*data] == 0x00) { + /* U+005C REVERSE SOLIDUS (\) */ + if (*data == 0x5C) { + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + data += 1; + + if (data < end) { + if (*data == 0x0A || *data == 0x0C || *data == 0x0D) { + data -= 1; + begin = data; + break; + } + } + + data = lxb_css_syntax_state_escaped(tkz, data, end); + if (data == NULL) { + return NULL; + } + + begin = data; + continue; + } + else if (*data == 0x00) + LXB_CSS_SYNTAX_NULL_BLOCK(tkz, begin, data, end) + else { + break; + } + } + + data += 1; + } + else { + LXB_CSS_SYNTAX_UTF_8_UP_80_BLOCK(tkz, begin, data, end) + else if (!lxb_css_syntax_state_non_ascii(cp)) { + data = _bad; + break; + } + } + } + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + return lxb_css_syntax_state_string_set(tkz, token, data); +} + +static const lxb_char_t * +lxb_css_syntax_state_consume_unicode_range(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, + const lxb_char_t *end) +{ + bool mq; + unsigned count, question; + lxb_codepoint_t cp, range_start, range_end; + + token->type = LXB_CSS_SYNTAX_TOKEN_UNICODE_RANGE; + + /* Skip [Uu]\+ */ + data += 2; + mq = true; + +again: + + cp = 0x0000; + count = 6; + + while (data < end && count > 0) { + if (lexbor_str_res_map_hex[*data] == LEXBOR_STR_RES_SLIP) { + /* U+003F QUESTION MARK (?) */ + if (*data == 0x3F && mq) { + question = 0; + + do { + question += 1; + count -= 1; + data += 1; + } + while (data < end && *data == 0x3F && count > 0); + + range_start = cp << (4 * question); + range_end = range_start | ((1 << (4 * question)) - 1); + + lxb_css_syntax_token_unicode_range(token)->start = range_start; + lxb_css_syntax_token_unicode_range(token)->end = range_end; + + return data; + } + + break; + } + + cp <<= 4; + cp |= lexbor_str_res_map_hex[ *data ]; + + count -= 1; + data += 1; + } + + if (mq) { + mq = false; + + lxb_css_syntax_token_unicode_range(token)->start = cp; + + /* U+002D HYPHEN-MINUS (-) */ + if (data + 2 > end || data[0] != 0x2D + || lexbor_str_res_map_hex[data[1]] == LEXBOR_STR_RES_SLIP) + { + lxb_css_syntax_token_unicode_range(token)->end = cp; + return data; + } + + /* Skip U+002D HYPHEN-MINUS (-) */ + data += 1; + + goto again; + } + + lxb_css_syntax_token_unicode_range(token)->end = cp; + + return data; +} + + +const lxb_char_t * +lxb_css_syntax_state_ident_like(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + lxb_char_t ch; + const lxb_char_t *begin; + lxb_css_syntax_token_string_t *str; + static const lxb_char_t url[] = "url"; + + /* Would start a unicode-range. */ + /* + * U+002B PLUS SIGN (+) + * U+003F QUESTION MARK (?) + */ + if (tkz->with_unicode_range && data + 3 <= end && data[1] == 0x2B + && (lexbor_str_res_map_hex[ data[2] ] != 0xFF || data[2] == 0x3F)) + { + return lxb_css_syntax_state_consume_unicode_range(tkz, token, + data, end); + } + + data = lxb_css_syntax_state_consume_ident(tkz, token, data, end); + if (data == NULL) { + goto done; + } + + if (data < end && *data == '(') { + data += 1; + str = lxb_css_syntax_token_string(token); + + if (str->length != 3 || !lexbor_str_data_casecmp(str->data, url)) { + token->type = LXB_CSS_SYNTAX_TOKEN_FUNCTION; + + return data; + } + + begin = data; + + while (data < end) { + ch = *data; + + if (lexbor_utils_whitespace(ch, !=, &&)) { + /* U+0022 QUOTATION MARK (") or U+0027 APOSTROPHE (') */ + if (ch == 0x22 || ch == 0x27) { + break; + } + + tkz->pos = tkz->start; + + return lxb_css_syntax_state_url(tkz, token, data, end); + } + + data++; + } + + token->type = LXB_CSS_SYNTAX_TOKEN_FUNCTION; + + return begin; + } + +done: + + token->type = LXB_CSS_SYNTAX_TOKEN_IDENT; + + return data; +} + +const lxb_char_t * +lxb_css_syntax_state_ident_like_not_url_start(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + const lxb_char_t *begin = data; + + if (lxb_css_syntax_state_start_ident_utf_8_80(&data, end)) { + return lxb_css_syntax_state_ident_like_not_url(tkz, token, begin, end); + } + + return lxb_css_syntax_state_delim_set_cp(token, begin, end); +} + +const lxb_char_t * +lxb_css_syntax_state_ident_like_not_url(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + data = lxb_css_syntax_state_consume_ident(tkz, token, data, end); + if (data == NULL) { + return NULL; + } + + if (data < end && *data == '(') { + token->type = LXB_CSS_SYNTAX_TOKEN_FUNCTION; + + return data + 1; + } + + token->type = LXB_CSS_SYNTAX_TOKEN_IDENT; + + return data; +} + +const lxb_char_t * +lxb_css_syntax_state_ident_like_not_url_surrogate(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + const lxb_char_t *begin = data; + + if (data + 3 <= end) { + lxb_codepoint_t srp = data[1] << 8 | data[2]; + + /* Leading surrogate U+D800 to U+DFFF. */ + if (srp >= (0xA0 << 8 | 0x80) && srp <= (0xBF << 8 | 0xBF)) { + return lxb_css_syntax_state_ident_like_not_url(tkz, token, + data, end); + } + } + + if (lxb_css_syntax_state_start_ident_utf_8_80(&data, end)) { + return lxb_css_syntax_state_ident_like_not_url(tkz, token, begin, end); + } + + return lxb_css_syntax_state_delim_set_cp(token, begin, end); +} + +/* + * URL + */ +static const lxb_char_t * +lxb_css_syntax_state_url(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + lxb_char_t ch; + const lxb_char_t *begin; + + *tkz->pos = 0x00; + + begin = data; + + while (data < end) { + switch (*data) { + /* U+0000 NULL */ + case 0x00: + LXB_CSS_SYNTAX_NULL_BLOCK(tkz, begin, data, end) + break; + + /* U+0029 RIGHT PARENTHESIS ()) */ + case 0x29: + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + data += 1; + goto done; + + /* + * U+0022 QUOTATION MARK (") + * U+0027 APOSTROPHE (') + * U+0028 LEFT PARENTHESIS (() + * U+000B LINE TABULATION + * U+007F DELETE + */ + case 0x22: + case 0x27: + case 0x28: + case 0x0B: + case 0x7F: + goto bad; + + /* U+005C REVERSE SOLIDUS (\) */ + case 0x5C: + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + data += 1; + + if (data >= end) { + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_WRESINUR); + } + else { + ch = *data; + + if (ch == 0x0A || ch == 0x0C || ch == 0x0D) { + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_WRESINUR); + + return lxb_css_syntax_state_bad_url(tkz, token, data, end); + } + } + + data = lxb_css_syntax_state_escaped(tkz, data, end); + if (data == NULL) { + return NULL; + } + + begin = data; + continue; + + /* + * U+0009 CHARACTER TABULATION (tab) + * U+000A LINE FEED (LF) + * U+000C FORM FEED (FF) + * U+000D CARRIAGE RETURN (CR) + * U+0020 SPACE + */ + case 0x09: + case 0x0A: + case 0x0C: + case 0x0D: + case 0x20: + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + data += 1; + + while (data < end) { + ch = *data; + + if (lexbor_utils_whitespace(ch, !=, &&)) { + /* U+0029 RIGHT PARENTHESIS ()) */ + if (*data == 0x29) { + data += 1; + goto done; + } + + return lxb_css_syntax_state_bad_url(tkz, token, + data, end); + } + + data += 1; + } + + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINUR); + + goto done; + + default: + if (*data >= 0x80) { + LXB_CSS_SYNTAX_UTF_8_UP_80_BLOCK(tkz, begin, data, end) + continue; + } + + /* + * Inclusive: + * U+0000 NULL and U+0008 BACKSPACE or + * U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE + */ + if ((*data <= 0x08) || (*data >= 0x0E && *data <= 0x1F)) { + goto bad; + } + + break; + } + + data += 1; + } + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINUR); + +done: + + token->type = LXB_CSS_SYNTAX_TOKEN_URL; + + return lxb_css_syntax_state_string_set(tkz, token, data); + +bad: + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_QOINUR); + + return lxb_css_syntax_state_bad_url(tkz, token, data, end); +} + +/* + * Bad URL + */ +static const lxb_char_t * +lxb_css_syntax_state_bad_url(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end) +{ + const lxb_char_t *begin; + + token->type = LXB_CSS_SYNTAX_TOKEN_BAD_URL; + + begin = data; + + while (data < end) { + /* U+0029 RIGHT PARENTHESIS ()) */ + if (*data == 0x29) { + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + return lxb_css_syntax_state_string_set(tkz, token, data + 1); + } + /* U+005C REVERSE SOLIDUS (\) */ + else if (*data == 0x5C) { + data += 1; + if (data >= end) { + break; + } + } + + if (*data >= 0x80) { + LXB_CSS_SYNTAX_UTF_8_UP_80_BLOCK(tkz, begin, data, end) + continue; + } + + data += 1; + } + + lxb_css_syntax_buffer_append_m(tkz, begin, data - begin); + + return lxb_css_syntax_state_string_set(tkz, token, data); +} + +static const lxb_char_t * +lxb_css_syntax_state_escaped(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *data, const lxb_char_t *end) +{ + unsigned count; + lxb_codepoint_t cp; + + cp = 0; + + for (count = 0; count < 6; count++, data++) { + if (data >= end) { + if (count == 0) { + lxb_css_syntax_tokenizer_error_add(tkz->parse_errors, data, + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINES); + } + + goto done; + } + + if (lexbor_str_res_map_hex[*data] == 0xFF) { + if (count == 0) { + if (*data < 0x80) { + cp = (lxb_codepoint_t) *data++; + } + else { + cp = lxb_css_syntax_state_decode_utf_8_up_80(&data, end); + } + + goto done; + } + + break; + } + + cp <<= 4; + cp |= lexbor_str_res_map_hex[*data]; + } + + if (data < end) { + switch (*data) { + case 0x0D: + data += 1; + + if (data >= end) { + break; + } + + if (*data == 0x0A) { + data += 1; + } + + break; + + case 0x09: + case 0x20: + case 0x0A: + case 0x0C: + data += 1; + break; + + default: + break; + } + } + +done: + + if ((tkz->end - tkz->pos) < 6) { + if (lxb_css_syntax_string_realloc(tkz, 1024) != LXB_STATUS_OK) { + return NULL; + } + } + + lxb_css_syntax_codepoint_to_ascii(tkz, cp); + + return data; +} + +static bool +lxb_css_syntax_state_start_number(const lxb_char_t *data, const lxb_char_t *end) +{ + switch (*data) { + /* + * U+002B PLUS SIGN (+) + * U+002D HYPHEN-MINUS (-) + */ + case 0x2B: + case 0x2D: + data += 1; + if (data >= end) { + return false; + } + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (*data >= 0x30 && *data <= 0x39) { + return true; + } + + break; + + default: + break; + } + + /* U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9) */ + if (*data >= 0x30 && *data <= 0x39) { + return true; + } + + /* U+002E FULL STOP (.) */ + if (*data == 0x2E) { + data += 1; + + if (data >= end || *data < 0x30 || *data > 0x39) { + return false; + } + + return true; + } + + return false; +} + +static bool +lxb_css_syntax_state_start_ident_sequence(const lxb_char_t *data, + const lxb_char_t *end) +{ + if (data >= end) { + return false; + } + + if (*data < 0x80) { + /* U+002D HYPHEN-MINUS */ + if (*data == 0x2D) { + data += 1; + + if (data >= end) { + return false; + } + + if (*data < 0x80) { + /* U+002D HYPHEN-MINUS */ + if (*data == 0x2D + || lxb_css_syntax_res_name_map[*data] == LXB_CSS_SYNTAX_RES_NAME_START + || lxb_css_syntax_state_valid_escape(data, end) + || *data == 0x00) + { + return true; + } + } + } + /* U+005C REVERSE SOLIDUS (\) */ + else if (*data == 0x5C) { + return lxb_css_syntax_state_valid_escape(data, end); + } + + return lxb_css_syntax_res_name_map[*data] == LXB_CSS_SYNTAX_RES_NAME_START + || *data == 0x00; + } + + return lxb_css_syntax_state_start_ident_utf_8_80(&data, end); +} + +static lxb_codepoint_t +lxb_css_syntax_state_decode_utf_8_up_80(const lxb_char_t **data, + const lxb_char_t *end) +{ + lxb_char_t ch, lower, upper; + unsigned needed; + const lxb_char_t *p; + lxb_codepoint_t cp; + + /* + * WHATWG UTF-8 decoder: https://encoding.spec.whatwg.org/#utf-8-decoder + */ + + p = *data; + ch = *p++; + + if (ch <= 0xDF) { + if (ch < 0xC2) { + *data = p; + return LXB_CSS_SYNTAX_ERROR_CODEPOINT; + } + + needed = 1; + lower = 0x80; + upper = 0xBF; + cp = ch & 0x1F; + } + else if (ch <= 0xEF) { + needed = 2; + lower = (ch == 0xE0) ? 0xA0 : 0x80; + upper = (ch == 0xED) ? 0x9F : 0xBF; + cp = ch & 0x0F; + } + else if (ch <= 0xF4) { + needed = 3; + lower = (ch == 0xF0) ? 0x90 : 0x80; + upper = (ch == 0xF4) ? 0x8F : 0xBF; + cp = ch & 0x07; + } + else { + /* 0xF5..0xFF: an invalid lead byte. */ + *data = p; + return LXB_CSS_SYNTAX_ERROR_CODEPOINT; + } + + do { + if (p >= end || *p < lower || *p > upper) { + *data = p; + return LXB_CSS_SYNTAX_ERROR_CODEPOINT; + } + + cp = (cp << 6) | (*p++ & 0x3F); + + lower = 0x80; + upper = 0xBF; + } + while (--needed != 0); + + *data = p; + + return cp; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state.h new file mode 100644 index 0000000..59b5a87 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_STATE_H +#define LEXBOR_CSS_SYNTAX_STATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/syntax/base.h" +#include "lexbor/css/syntax/tokenizer.h" + + +const lxb_char_t * +lxb_css_syntax_state_delim(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_comment(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_whitespace(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_string(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_hash(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_lparenthesis(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_rparenthesis(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_plus(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_comma(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_minus(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_full_stop(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_colon(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_semicolon(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_less_sign(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_at(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_ls_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_rsolidus(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_rs_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_lc_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_rc_bracket(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_consume_before_numeric(lxb_css_syntax_tokenizer_t *tkz, lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_ident_like(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_ident_like_not_url_start(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_ident_like_not_url(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +const lxb_char_t * +lxb_css_syntax_state_ident_like_not_url_surrogate(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_STATE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state_res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state_res.h new file mode 100644 index 0000000..e98909a --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/state_res.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_STATE_RES_H +#define LEXBOR_CSS_SYNTAX_STATE_RES_H + + +static const lxb_css_syntax_tokenizer_state_f +lxb_css_syntax_state_res_map[256] = +{ + lxb_css_syntax_state_ident_like_not_url, /* 0x00; 'NUL'; NULL */ + lxb_css_syntax_state_delim, /* 0x01; 'SOH'; Start of Heading */ + lxb_css_syntax_state_delim, /* 0x02; 'STX'; Start of text */ + lxb_css_syntax_state_delim, /* 0x03; 'ETX'; End of text */ + lxb_css_syntax_state_delim, /* 0x04; 'EOT'; End of Transmission */ + lxb_css_syntax_state_delim, /* 0x05; 'ENQ'; Enquiry */ + lxb_css_syntax_state_delim, /* 0x06; 'ACK'; Acknowledge */ + lxb_css_syntax_state_delim, /* 0x07; 'BEL'; Bell */ + lxb_css_syntax_state_delim, /* 0x08; 'BS'; Backspace */ + lxb_css_syntax_state_whitespace, /* 0x09; 'TAB'; Horizontal Tab */ + lxb_css_syntax_state_whitespace, /* 0x0A; 'LF'; Line Feed ('\n') */ + lxb_css_syntax_state_delim, /* 0x0B; 'VT'; Vertical Tab */ + lxb_css_syntax_state_whitespace, /* 0x0C; 'FF'; Form Feed */ + lxb_css_syntax_state_whitespace, /* 0x0D; 'CR'; Carriage Return ('\r') */ + lxb_css_syntax_state_delim, /* 0x0E; 'SO'; Shift Out */ + lxb_css_syntax_state_delim, /* 0x0F; 'SI'; Shift In */ + lxb_css_syntax_state_delim, /* 0x10; 'DLE'; Data Link Escape */ + lxb_css_syntax_state_delim, /* 0x11; 'DC1'; Device Control #1 */ + lxb_css_syntax_state_delim, /* 0x12; 'DC2'; Device Control #2 */ + lxb_css_syntax_state_delim, /* 0x13; 'DC3'; Device Control #3 */ + lxb_css_syntax_state_delim, /* 0x14; 'DC4'; Device Control #4 */ + lxb_css_syntax_state_delim, /* 0x15; 'NAK'; Negative Acknowledge */ + lxb_css_syntax_state_delim, /* 0x16; 'SYN'; Synchronous Idle */ + lxb_css_syntax_state_delim, /* 0x17; 'ETB'; End of Transmission Block */ + lxb_css_syntax_state_delim, /* 0x18; 'CAN'; Cancel */ + lxb_css_syntax_state_delim, /* 0x19; 'EM'; End of Medium */ + lxb_css_syntax_state_delim, /* 0x1A; 'SUB'; Substitute */ + lxb_css_syntax_state_delim, /* 0x1B; 'ESC'; Escape */ + lxb_css_syntax_state_delim, /* 0x1C; 'FS'; File Separator */ + lxb_css_syntax_state_delim, /* 0x1D; 'GS'; Group Separator */ + lxb_css_syntax_state_delim, /* 0x1E; 'RS'; Record Separator */ + lxb_css_syntax_state_delim, /* 0x1F; 'US'; Unit Separator */ + lxb_css_syntax_state_whitespace, /* 0x20; 'SP'; Space */ + lxb_css_syntax_state_delim, /* 0x21; '!'; Exclamation mark */ + lxb_css_syntax_state_string, /* 0x22; '"'; Only quotes above */ + lxb_css_syntax_state_hash, /* 0x23; '#'; Pound sign */ + lxb_css_syntax_state_delim, /* 0x24; '$'; Dollar sign */ + lxb_css_syntax_state_delim, /* 0x25; '%'; Percentage sign */ + lxb_css_syntax_state_delim, /* 0x26; '&'; Ampersand */ + lxb_css_syntax_state_string, /* 0x27; '''; Apostrophe */ + lxb_css_syntax_state_lparenthesis, /* 0x28; '('; Left bracket */ + lxb_css_syntax_state_rparenthesis, /* 0x29; ')'; Right bracket */ + lxb_css_syntax_state_delim, /* 0x2A; '*'; Asterisk */ + lxb_css_syntax_state_plus, /* 0x2B; '+'; Plus symbol */ + lxb_css_syntax_state_comma, /* 0x2C; ','; Comma */ + lxb_css_syntax_state_minus, /* 0x2D; '-'; Dash */ + lxb_css_syntax_state_full_stop, /* 0x2E; '.'; Full stop */ + lxb_css_syntax_state_comment, /* 0x2F; '/'; Forward slash */ + lxb_css_syntax_state_consume_before_numeric, /* 0x30; '0' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x31; '1' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x32; '2' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x33; '3' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x34; '4' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x35; '5' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x36; '6' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x37; '7' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x38; '8' */ + lxb_css_syntax_state_consume_before_numeric, /* 0x39; '9' */ + lxb_css_syntax_state_colon, /* 0x3A; ':'; Colon */ + lxb_css_syntax_state_semicolon, /* 0x3B; ';'; Semicolon */ + lxb_css_syntax_state_less_sign, /* 0x3C; '<'; Small than bracket */ + lxb_css_syntax_state_delim, /* 0x3D; '='; Equals sign */ + lxb_css_syntax_state_delim, /* 0x3E; '>'; Bigger than symbol */ + lxb_css_syntax_state_delim, /* 0x3F; '?'; Question mark */ + lxb_css_syntax_state_at, /* 0x40; '@'; At symbol */ + lxb_css_syntax_state_ident_like_not_url, /* 0x41; 'A' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x42; 'B' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x43; 'C' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x44; 'D' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x45; 'E' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x46; 'F' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x47; 'G' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x48; 'H' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x49; 'I' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x4A; 'J' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x4B; 'K' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x4C; 'L' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x4D; 'M' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x4E; 'N' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x4F; 'O' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x50; 'P' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x51; 'Q' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x52; 'R' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x53; 'S' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x54; 'T' */ + lxb_css_syntax_state_ident_like, /* 0x55; 'U' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x56; 'V' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x57; 'W' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x58; 'X' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x59; 'Y' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x5A; 'Z' */ + lxb_css_syntax_state_ls_bracket, /* 0x5B; '['; Left square bracket */ + lxb_css_syntax_state_rsolidus, /* 0x5C; '\'; Inverse/backward slash */ + lxb_css_syntax_state_rs_bracket, /* 0x5D; ']'; Right square bracket */ + lxb_css_syntax_state_delim, /* 0x5E; '^'; Circumflex */ + lxb_css_syntax_state_ident_like_not_url, /* 0x5F; '_'; Underscore */ + lxb_css_syntax_state_delim, /* 0x60; '`'; Gravis (backtick) */ + lxb_css_syntax_state_ident_like_not_url, /* 0x61; 'a' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x62; 'b' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x63; 'c' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x64; 'd' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x65; 'e' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x66; 'f' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x67; 'g' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x68; 'h' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x69; 'i' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x6A; 'j' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x6B; 'k' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x6C; 'l' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x6D; 'm' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x6E; 'n' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x6F; 'o' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x70; 'p' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x71; 'q' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x72; 'r' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x73; 's' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x74; 't' */ + lxb_css_syntax_state_ident_like, /* 0x75; 'u' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x76; 'v' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x77; 'w' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x78; 'x' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x79; 'y' */ + lxb_css_syntax_state_ident_like_not_url, /* 0x7A; 'z' */ + lxb_css_syntax_state_lc_bracket, /* 0x7B; '{'; Left curly bracket */ + lxb_css_syntax_state_delim, /* 0x7C; '|'; Vertical line */ + lxb_css_syntax_state_rc_bracket, /* 0x7D; '}'; Right curly brackets */ + lxb_css_syntax_state_delim, /* 0x7E; '~'; Tilde */ + lxb_css_syntax_state_delim, /* 0x7F; 'DEL'; Delete */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x80 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x81 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x82 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x83 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x84 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x85 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x86 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x87 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x88 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x89 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x8A */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x8B */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x8C */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x8D */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x8E */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x8F */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x90 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x91 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x92 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x93 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x94 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x95 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x96 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x97 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x98 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x99 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x9A */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x9B */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x9C */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x9D */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x9E */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0x9F */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA0 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA1 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA2 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA3 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA4 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA5 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA6 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA7 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA8 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xA9 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xAA */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xAB */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xAC */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xAD */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xAE */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xAF */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB0 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB1 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB2 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB3 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB4 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB5 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB6 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB7 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB8 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xB9 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xBA */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xBB */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xBC */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xBD */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xBE */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xBF */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC0 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC1 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC2 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC3 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC4 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC5 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC6 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC7 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC8 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xC9 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xCA */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xCB */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xCC */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xCD */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xCE */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xCF */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD0 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD1 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD2 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD3 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD4 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD5 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD6 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD7 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD8 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xD9 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xDA */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xDB */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xDC */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xDD */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xDE */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xDF */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE0 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE1 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE2 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE3 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE4 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE5 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE6 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE7 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE8 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xE9 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xEA */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xEB */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xEC */ + lxb_css_syntax_state_ident_like_not_url_surrogate, /* 0xED */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xEE */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xEF */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF0 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF1 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF2 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF3 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF4 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF5 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF6 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF7 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF8 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xF9 */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xFA */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xFB */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xFC */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xFD */ + lxb_css_syntax_state_ident_like_not_url_start, /* 0xFE */ + lxb_css_syntax_state_ident_like_not_url_start /* 0xFF */ +}; + + +#endif /* LEXBOR_CSS_SYNTAX_STATE_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/syntax.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/syntax.c new file mode 100644 index 0000000..fd03fe0 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/syntax.c @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/syntax/syntax.h" +#include "lexbor/css/parser.h" +#include "lexbor/css/rule.h" + +#include "lexbor/core/serialize.h" +#include "lexbor/core/str.h" + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_ansi_replacement_character[4]; + LXB_EXTERN const lxb_char_t lexbor_str_res_map_hex[256]; + LXB_EXTERN const lxb_char_t lexbor_str_res_map_hex_to_char_lowercase[17]; + LXB_EXTERN const char *lexbor_str_res_char_to_two_hex_value_lowercase[257]; + LXB_EXTERN const lxb_char_t lxb_css_syntax_res_name_map[256]; +#endif + +static const lexbor_str_t lxb_css_syntax_str_ws = lexbor_str(" "); + + +lxb_css_rule_list_t * +lxb_css_syntax_parse_list_rules(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_list_rules_t *cb, + const lxb_char_t *data, size_t length) +{ + lxb_css_rule_list_t *list; + lxb_css_syntax_rule_t *rule; + + if (lxb_css_parser_is_running(parser)) { + parser->status = LXB_STATUS_ERROR_WRONG_STAGE; + return NULL; + } + + lxb_css_parser_clean(parser); + lxb_css_parser_buffer_set(parser, data, length); + + list = lxb_css_rule_list_create(parser->memory); + if (list == NULL) { + parser->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + goto failed; + } + + rule = lxb_css_syntax_parser_list_rules_push(parser, cb, NULL, list, + LXB_CSS_SYNTAX_TOKEN_UNDEF); + if (rule == NULL) { + goto failed; + } + + parser->tkz->with_comment = false; + parser->stage = LXB_CSS_PARSER_RUN; + + parser->status = lxb_css_syntax_parser_run(parser); + if (parser->status != LXB_STATUS_OK) { + goto failed; + } + + parser->stage = LXB_CSS_PARSER_END; + + return list; + +failed: + + if (list != NULL) { + lxb_css_rule_list_destroy(list, true); + } + + parser->stage = LXB_CSS_PARSER_END; + + return NULL; +} + +lxb_css_rule_declaration_list_t * +lxb_css_syntax_parse_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_declarations_t *cb, + const lxb_char_t *data, size_t length) +{ + lxb_css_rule_declaration_list_t *list; + lxb_css_syntax_rule_t *rule; + + if (lxb_css_parser_is_running(parser)) { + parser->status = LXB_STATUS_ERROR_WRONG_STAGE; + return NULL; + } + + lxb_css_parser_clean(parser); + lxb_css_parser_buffer_set(parser, data, length); + + list = lxb_css_rule_declaration_list_create(parser->memory); + if (list == NULL) { + parser->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + goto failed; + } + + rule = lxb_css_syntax_parser_declarations_push(parser, cb, NULL, list, + LXB_CSS_SYNTAX_TOKEN_UNDEF, + true, false); + if (rule == NULL) { + goto failed; + } + + parser->tkz->with_comment = false; + parser->stage = LXB_CSS_PARSER_RUN; + + parser->status = lxb_css_syntax_parser_run(parser); + if (parser->status != LXB_STATUS_OK) { + goto failed; + } + + parser->stage = LXB_CSS_PARSER_END; + + return list; + +failed: + + if (list != NULL) { + lxb_css_rule_declaration_list_destroy(list, true); + } + + parser->stage = LXB_CSS_PARSER_END; + + return NULL; +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_list_rules(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_list_rules_t *list_rules, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop) +{ + return lxb_css_syntax_parser_list_rules_push(parser, list_rules, back, + ctx, stop); +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_at_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_at_rule_t *at_rule, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop) +{ + if (token->type != LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD) { + return NULL; + } + + if (parser->rules > parser->rules_begin && parser->rules->deep != 0 + && parser->types_pos[-1] == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) + { + parser->types_pos -= 1; + parser->rules->deep -= 1; + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_syntax_parser_at_rule_push(parser, at_rule, back, ctx, + stop, false); +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_qualified_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_qualified_rule_t *qualified, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop) +{ + lxb_css_syntax_token_type_t type; + + if (parser->rules > parser->rules_begin && parser->rules->deep != 0) { + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + type = LXB_CSS_SYNTAX_TOKEN_RS_BRACKET; + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + type = LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS; + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + type = LXB_CSS_SYNTAX_TOKEN_RC_BRACKET; + break; + + default: + type = LXB_CSS_SYNTAX_TOKEN_UNDEF; + break; + } + + + if (parser->types_pos[-1] == type) { + parser->types_pos -= 1; + parser->rules->deep -= 1; + } + } + + return lxb_css_syntax_parser_qualified_push(parser, qualified, back, + ctx, stop, false); +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_block_t *block, + lxb_css_parser_state_f back, void *ctx) +{ + if (token->type != LXB_CSS_SYNTAX_TOKEN_LC_BRACKET) { + return NULL; + } + + if (parser->rules > parser->rules_begin && parser->rules->deep != 0 + && parser->types_pos[-1] == LXB_CSS_SYNTAX_TOKEN_RC_BRACKET) + { + parser->types_pos -= 1; + parser->rules->deep -= 1; + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_syntax_parser_block_push(parser, block, back, ctx); +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_declarations_t *declr, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop) +{ + lxb_css_syntax_token_type_t type; + + if (parser->rules > parser->rules_begin && parser->rules->deep != 0) { + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + type = LXB_CSS_SYNTAX_TOKEN_RS_BRACKET; + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + type = LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS; + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + type = LXB_CSS_SYNTAX_TOKEN_RC_BRACKET; + break; + + default: + type = LXB_CSS_SYNTAX_TOKEN_UNDEF; + break; + } + + + if (parser->types_pos[-1] == type) { + parser->types_pos -= 1; + parser->rules->deep -= 1; + } + } + + return lxb_css_syntax_parser_declarations_push(parser, declr, back, + ctx, stop, true, false); +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_components(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_components_t *comp, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop) +{ + lxb_css_syntax_token_type_t type; + + if (parser->rules > parser->rules_begin && parser->rules->deep != 0) { + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + type = LXB_CSS_SYNTAX_TOKEN_RS_BRACKET; + break; + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + type = LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS; + break; + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + type = LXB_CSS_SYNTAX_TOKEN_RC_BRACKET; + break; + + default: + type = LXB_CSS_SYNTAX_TOKEN_UNDEF; + break; + } + + + if (parser->types_pos[-1] == type) { + parser->types_pos -= 1; + parser->rules->deep -= 1; + } + } + + return lxb_css_syntax_parser_components_push(parser, comp, back, ctx, stop); +} + +lxb_css_syntax_rule_t * +lxb_css_syntax_consume_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_function_t *func, + lxb_css_parser_state_f back, void *ctx) +{ + if (token->type != LXB_CSS_SYNTAX_TOKEN_FUNCTION) { + return NULL; + } + + if (parser->rules > parser->rules_begin && parser->rules->deep != 0 + && parser->types_pos[-1] == LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS) + { + parser->types_pos -= 1; + parser->rules->deep -= 1; + } + + lxb_css_syntax_parser_consume(parser); + + return lxb_css_syntax_parser_function_push(parser, func, back, ctx); +} + +lxb_status_t +lxb_css_syntax_stack_expand(lxb_css_parser_t *parser, size_t count) +{ + size_t length, cur_len, size; + lxb_css_syntax_rule_t *p; + + cur_len = parser->rules - parser->rules_begin; + + length = cur_len + count + 1024; + size = length * sizeof(lxb_css_syntax_rule_t); + + p = lexbor_realloc(parser->rules_begin, size); + if (p == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + parser->rules_begin = p; + parser->rules_end = p + length; + parser->rules = p + cur_len; + + return LXB_STATUS_OK; +} + +void +lxb_css_syntax_codepoint_to_ascii(lxb_css_syntax_tokenizer_t *tkz, + lxb_codepoint_t cp) +{ + /* + * Zero, or is for a surrogate, or is greater than + * the maximum allowed code point (tkz->num > 0x10FFFF). + */ + if (cp == 0 || cp > 0x10FFFF || (cp >= 0xD800 && cp <= 0xDFFF)) { + memcpy(tkz->pos, lexbor_str_res_ansi_replacement_character, 3); + + tkz->pos += 3; + *tkz->pos = '\0'; + + return; + } + + lxb_char_t *data = tkz->pos; + + if (cp <= 0x0000007F) { + /* 0xxxxxxx */ + data[0] = (lxb_char_t) cp; + + tkz->pos += 1; + } + else if (cp <= 0x000007FF) { + /* 110xxxxx 10xxxxxx */ + data[0] = (char)(0xC0 | (cp >> 6 )); + data[1] = (char)(0x80 | (cp & 0x3F)); + + tkz->pos += 2; + } + else if (cp <= 0x0000FFFF) { + /* 1110xxxx 10xxxxxx 10xxxxxx */ + data[0] = (char)(0xE0 | ((cp >> 12))); + data[1] = (char)(0x80 | ((cp >> 6 ) & 0x3F)); + data[2] = (char)(0x80 | ( cp & 0x3F)); + + tkz->pos += 3; + } + else if (cp <= 0x001FFFFF) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + data[0] = (char)(0xF0 | ( cp >> 18)); + data[1] = (char)(0x80 | ((cp >> 12) & 0x3F)); + data[2] = (char)(0x80 | ((cp >> 6 ) & 0x3F)); + data[3] = (char)(0x80 | ( cp & 0x3F)); + + tkz->pos += 4; + } + + *tkz->pos = '\0'; +} + +lxb_status_t +lxb_css_syntax_ident_serialize(const lxb_char_t *data, size_t length, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_char_t ch; + lxb_status_t status; + const char **hex_map; + const lxb_char_t *p = data, *end; + + static const lexbor_str_t str_s = lexbor_str("\\"); + + end = data + length; + hex_map = lexbor_str_res_char_to_two_hex_value_lowercase; + + while (p < end) { + ch = *p; + + if (lxb_css_syntax_res_name_map[ch] == 0x00) { + lexbor_serialize_write(cb, data, p - data, ctx, status); + lexbor_serialize_write(cb, str_s.data, str_s.length, ctx, status); + lexbor_serialize_write(cb, hex_map[ch], 2, ctx, status); + + data = ++p; + + if (p < end && lexbor_str_res_map_hex[*p] != 0xff) { + lexbor_serialize_write(cb, lxb_css_syntax_str_ws.data, + lxb_css_syntax_str_ws.length, + ctx, status); + } + + continue; + } + + p++; + } + + if (data < p) { + lexbor_serialize_write(cb, data, p - data, ctx, status); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_syntax_string_serialize(const lxb_char_t *data, size_t length, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_char_t ch; + lxb_status_t status; + const char **hex_map; + const lxb_char_t *p, *end; + + static const lexbor_str_t str_s = lexbor_str("\\"); + static const lexbor_str_t str_dk = lexbor_str("\""); + static const lexbor_str_t str_ds = lexbor_str("\\\\"); + static const lexbor_str_t str_dks = lexbor_str("\\\""); + + p = data; + end = data + length; + hex_map = lexbor_str_res_char_to_two_hex_value_lowercase; + + lexbor_serialize_write(cb, str_dk.data, str_dk.length, ctx, status); + + while (p < end) { + ch = *p; + + if (lxb_css_syntax_res_name_map[ch] == 0x00) { + switch (ch) { + case '\\': + lexbor_serialize_write(cb, data, p - data, ctx, status); + lexbor_serialize_write(cb, str_ds.data, str_ds.length, + ctx, status); + break; + + case '"': + lexbor_serialize_write(cb, data, p - data, ctx, status); + lexbor_serialize_write(cb, str_dks.data, str_dks.length, + ctx, status); + break; + + case '\n': + case '\t': + case '\r': + lexbor_serialize_write(cb, data, p - data, ctx, status); + lexbor_serialize_write(cb, str_s.data, str_s.length, + ctx, status); + lexbor_serialize_write(cb, hex_map[ch], 2, ctx, status); + + p++; + + if (p < end && lexbor_str_res_map_hex[*p] != 0xff) { + lexbor_serialize_write(cb, lxb_css_syntax_str_ws.data, + lxb_css_syntax_str_ws.length, + ctx, status); + } + + data = p; + continue; + + default: + p++; + continue; + } + + data = ++p; + continue; + } + + p++; + } + + if (data < p) { + lexbor_serialize_write(cb, data, p - data, ctx, status); + } + + lexbor_serialize_write(cb, str_dk.data, str_dk.length, ctx, status); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_syntax_ident_or_string_serialize(const lxb_char_t *data, size_t length, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_char_t *p, *end; + + p = data; + end = data + length; + + while (p < end) { + if (lxb_css_syntax_res_name_map[*p++] == 0x00) { + return lxb_css_syntax_string_serialize(data, length, cb, ctx); + } + } + + return cb(data, length, ctx); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/syntax.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/syntax.h new file mode 100644 index 0000000..08e9c5c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/syntax.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2022-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_H +#define LEXBOR_CSS_SYNTAX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/syntax/tokenizer.h" +#include "lexbor/css/syntax/tokenizer.h" + + +typedef struct lxb_css_syntax_rule lxb_css_syntax_rule_t; + +typedef const lxb_css_syntax_token_t * +(*lxb_css_syntax_state_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_rule_t *rule); + + +typedef struct lxb_css_syntax_cb_base lxb_css_syntax_cb_base_t; +typedef struct lxb_css_syntax_cb_list_rules lxb_css_syntax_cb_list_rules_t; +typedef struct lxb_css_syntax_cb_at_rule lxb_css_syntax_cb_at_rule_t; +typedef struct lxb_css_syntax_cb_qualified_rule lxb_css_syntax_cb_qualified_rule_t; +typedef struct lxb_css_syntax_cb_block lxb_css_syntax_cb_block_t; +typedef struct lxb_css_syntax_cb_declarations lxb_css_syntax_cb_declarations_t; +typedef struct lxb_css_syntax_cb_function lxb_css_syntax_cb_function_t; +typedef struct lxb_css_syntax_cb_components lxb_css_syntax_cb_components_t; +typedef struct lxb_css_syntax_cb_pipe lxb_css_syntax_cb_pipe_t; + +typedef struct lxb_css_syntax_declaration_offset lxb_css_syntax_declaration_offset_t; + +typedef lxb_status_t +(*lxb_css_syntax_cb_done_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, bool failed); + +typedef const lxb_css_syntax_cb_at_rule_t * +(*lxb_css_syntax_begin_at_rule_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +typedef const lxb_css_syntax_cb_qualified_rule_t * +(*lxb_css_syntax_begin_qualified_rule_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +typedef const lxb_css_syntax_cb_block_t * +(*lxb_css_syntax_begin_block_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); + +typedef const lxb_css_syntax_cb_declarations_t * +(*lxb_css_syntax_begin_declarations_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +typedef lxb_css_parser_state_f +(*lxb_css_syntax_declaration_name_f)(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + void *ctx, void **out_rule); +typedef lxb_status_t +(*lxb_css_syntax_declaration_end_f)(lxb_css_parser_t *parser, + void *declaration, void *ctx, + const lxb_css_syntax_token_t *token, + lxb_css_syntax_declaration_offset_t *offset, + bool important, bool failed); + +struct lxb_css_syntax_cb_base { + lxb_css_parser_state_f failed; + lxb_css_syntax_cb_done_f end; +}; + +struct lxb_css_syntax_cb_list_rules { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f next; + lxb_css_syntax_begin_at_rule_f at_rule; + lxb_css_syntax_begin_qualified_rule_f qualified_rule; +}; + +struct lxb_css_syntax_cb_at_rule { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f prelude; + lxb_css_syntax_cb_done_f prelude_end; + lxb_css_syntax_begin_block_f block; +}; + +struct lxb_css_syntax_cb_qualified_rule { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f prelude; + lxb_css_syntax_cb_done_f prelude_end; + lxb_css_syntax_begin_block_f block; +}; + +struct lxb_css_syntax_cb_block { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f next; + lxb_css_syntax_begin_at_rule_f at_rule; + lxb_css_syntax_begin_declarations_f declarations; + lxb_css_syntax_begin_qualified_rule_f qualified_rule; +}; + +struct lxb_css_syntax_cb_declarations { + lxb_css_syntax_cb_base_t cb; + lxb_css_syntax_declaration_name_f name; + lxb_css_syntax_declaration_end_f end; +}; + +struct lxb_css_syntax_cb_function { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f value; +}; + +struct lxb_css_syntax_cb_components { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f prelude; +}; + +struct lxb_css_syntax_cb_pipe { + lxb_css_syntax_cb_base_t cb; + lxb_css_parser_state_f prelude; +}; + +struct lxb_css_syntax_declaration_offset { + size_t value_begin; + size_t value_end; + size_t important_begin; + size_t important_end; + size_t end; +}; + +struct lxb_css_syntax_rule { + lxb_css_syntax_state_f phase; + lxb_css_parser_state_f state; + + /* + * This callback will be called before rule->state is called. + * Exclusively from the lxb_css_parser_run(...). + */ + lxb_css_syntax_state_f back; + lxb_css_parser_state_f back_state; + void *context; + void *context_old; + void *returned; + + union { + const lxb_css_syntax_cb_base_t *cb; + const lxb_css_syntax_cb_list_rules_t *list_rules; + const lxb_css_syntax_cb_at_rule_t *at_rule; + const lxb_css_syntax_cb_qualified_rule_t *qualified_rule; + const lxb_css_syntax_cb_components_t *components; + const lxb_css_syntax_cb_declarations_t *declarations; + const lxb_css_syntax_cb_function_t *func; + const lxb_css_syntax_cb_block_t *block; + const lxb_css_syntax_cb_pipe_t *pipe; + void *user; + } cbx; + + size_t offset; + size_t deep; + size_t begin; + lxb_css_syntax_token_type_t block_end; + bool nested; + bool skip_consume; + bool important; + bool failed; +}; + + +LXB_API lxb_css_rule_list_t * +lxb_css_syntax_parse_list_rules(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_list_rules_t *cb, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_rule_declaration_list_t * +lxb_css_syntax_parse_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_declarations_t *cb, + const lxb_char_t *data, size_t length); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_list_rules(lxb_css_parser_t *parser, + const lxb_css_syntax_cb_list_rules_t *list_rules, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_at_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_at_rule_t *at_rule, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_qualified_rule(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_qualified_rule_t *qualified, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_block(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_block_t *block, + lxb_css_parser_state_f back, void *ctx); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_declarations(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_declarations_t *declr, + lxb_css_parser_state_f back, void *ctx, + lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_components(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_components_t *comp, + lxb_css_parser_state_f back, + void *ctx, lxb_css_syntax_token_type_t stop); + +LXB_API lxb_css_syntax_rule_t * +lxb_css_syntax_consume_function(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const lxb_css_syntax_cb_function_t *func, + lxb_css_parser_state_f back, void *ctx); + + +LXB_API lxb_status_t +lxb_css_syntax_stack_expand(lxb_css_parser_t *parser, size_t count); + +LXB_API void +lxb_css_syntax_codepoint_to_ascii(lxb_css_syntax_tokenizer_t *tkz, + lxb_codepoint_t cp); + +LXB_API lxb_status_t +lxb_css_syntax_ident_serialize(const lxb_char_t *data, size_t length, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_syntax_string_serialize(const lxb_char_t *data, size_t length, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_syntax_ident_or_string_serialize(const lxb_char_t *data, size_t length, + lexbor_serialize_cb_f cb, void *ctx); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token.c new file mode 100644 index 0000000..fdfc621 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token.c @@ -0,0 +1,664 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/shs.h" +#include "lexbor/core/conv.h" +#include "lexbor/core/serialize.h" +#include "lexbor/core/print.h" + +#include "lexbor/css/parser.h" +#include "lexbor/css/syntax/token.h" +#include "lexbor/css/syntax/state.h" +#include "lexbor/css/syntax/token_res.h" + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_ansi_replacement_character[4]; + LXB_EXTERN const lxb_char_t lexbor_str_res_map_hex[256]; +#endif + +lxb_css_syntax_token_t * +lxb_css_syntax_tokenizer_token(lxb_css_syntax_tokenizer_t *tkz); + + +typedef struct { + lexbor_str_t *str; + lexbor_mraw_t *mraw; +} +lxb_css_syntax_token_ctx_t; + + +static lxb_status_t +lxb_css_syntax_token_str_cb(const lxb_char_t *data, size_t len, void *ctx); + +static int8_t +lxb_css_syntax_token_encode_utf_8(lxb_char_t *data, lxb_codepoint_t cp); + + +lxb_css_syntax_token_t * +lxb_css_syntax_token(lxb_css_syntax_tokenizer_t *tkz) +{ + if (tkz->first != NULL) { + return tkz->first; + } + + return lxb_css_syntax_tokenizer_token(tkz); +} + +lxb_css_syntax_token_t * +lxb_css_syntax_token_next(lxb_css_syntax_tokenizer_t *tkz) +{ + return lxb_css_syntax_tokenizer_token(tkz); +} + +void +lxb_css_syntax_token_consume(lxb_css_syntax_tokenizer_t *tkz) +{ + lxb_css_syntax_token_t *token; + + if (tkz->first) { + token = tkz->first; + tkz->first = token->next; + + if (tkz->last == token) { + tkz->last = NULL; + } + + lxb_css_syntax_token_string_free(tkz, token); + lexbor_dobject_free(tkz->tokens, token); + } +} + +void +lxb_css_syntax_token_consume_n(lxb_css_syntax_tokenizer_t *tkz, unsigned count) +{ + while (count != 0) { + count--; + lxb_css_syntax_token_consume(tkz); + } +} + +lxb_status_t +lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string_t *token, + lexbor_str_t *str, lexbor_mraw_t *mraw) +{ + size_t length; + + length = token->length + 1; + + if (length > str->length) { + if (str->data == NULL) { + str->data = lexbor_mraw_alloc(mraw, length); + if (str->data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + str->length = 0; + } + else { + if (lexbor_str_realloc(str, mraw, length) == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + } + + /* + 1 = '\0' */ + memcpy(str->data, token->data, length); + + str->length = token->length; + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_syntax_token_string_make(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token) +{ + lxb_char_t *data; + lxb_css_syntax_token_string_t *token_string; + + if (token->type >= LXB_CSS_SYNTAX_TOKEN_IDENT + && token->type <= LXB_CSS_SYNTAX_TOKEN_WHITESPACE) + { + token_string = lxb_css_syntax_token_string(token); + goto copy; + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_DIMENSION) { + token_string = lxb_css_syntax_token_dimension_string(token); + goto copy; + } + + return LXB_STATUS_OK; + +copy: + + data = lexbor_mraw_alloc(tkz->mraw, token_string->length + 1); + if (data == NULL) { + tkz->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + return tkz->status; + } + + /* + 1 = '\0' */ + memcpy(data, token_string->data, token_string->length + 1); + + token_string->data = data; + token->cloned = true; + + return LXB_STATUS_OK; +} + +void +lxb_css_syntax_token_string_free(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token) +{ + lxb_css_syntax_token_string_t *token_string; + + if (token->cloned) { + if (token->type == LXB_CSS_SYNTAX_TOKEN_DIMENSION) { + token_string = lxb_css_syntax_token_dimension_string(token); + } + else { + token_string = lxb_css_syntax_token_string(token); + } + + lexbor_mraw_free(tkz->mraw, (lxb_char_t *) token_string->data); + } +} + +const lxb_char_t * +lxb_css_syntax_token_type_name_by_id(lxb_css_syntax_token_type_t type) +{ + switch (type) { + case LXB_CSS_SYNTAX_TOKEN_IDENT: + return (lxb_char_t *) "ident"; + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + return (lxb_char_t *) "function"; + case LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD: + return (lxb_char_t *) "at-keyword"; + case LXB_CSS_SYNTAX_TOKEN_HASH: + return (lxb_char_t *) "hash"; + case LXB_CSS_SYNTAX_TOKEN_STRING: + return (lxb_char_t *) "string"; + case LXB_CSS_SYNTAX_TOKEN_BAD_STRING: + return (lxb_char_t *) "bad-string"; + case LXB_CSS_SYNTAX_TOKEN_URL: + return (lxb_char_t *) "url"; + case LXB_CSS_SYNTAX_TOKEN_BAD_URL: + return (lxb_char_t *) "bad-url"; + case LXB_CSS_SYNTAX_TOKEN_DELIM: + return (lxb_char_t *) "delim"; + case LXB_CSS_SYNTAX_TOKEN_UNICODE_RANGE: + return (lxb_char_t *) "unicode-range"; + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + return (lxb_char_t *) "number"; + case LXB_CSS_SYNTAX_TOKEN_PERCENTAGE: + return (lxb_char_t *) "percentage"; + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + return (lxb_char_t *) "dimension"; + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + return (lxb_char_t *) "whitespace"; + case LXB_CSS_SYNTAX_TOKEN_CDO: + return (lxb_char_t *) "CDO"; + case LXB_CSS_SYNTAX_TOKEN_CDC: + return (lxb_char_t *) "CDC"; + case LXB_CSS_SYNTAX_TOKEN_COLON: + return (lxb_char_t *) "colon"; + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + return (lxb_char_t *) "semicolon"; + case LXB_CSS_SYNTAX_TOKEN_COMMA: + return (lxb_char_t *) "comma"; + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + return (lxb_char_t *) "left-square-bracket"; + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + return (lxb_char_t *) "right-square-bracket"; + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + return (lxb_char_t *) "left-parenthesis"; + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + return (lxb_char_t *) "right-parenthesis"; + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + return (lxb_char_t *) "left-curly-bracket"; + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + return (lxb_char_t *) "right-curly-bracket"; + case LXB_CSS_SYNTAX_TOKEN_COMMENT: + return (lxb_char_t *) "comment"; + case LXB_CSS_SYNTAX_TOKEN__EOF: + return (lxb_char_t *) "end-of-file"; + case LXB_CSS_SYNTAX_TOKEN__END: + return (lxb_char_t *) "end"; + default: + return (lxb_char_t *) "undefined"; + } +} + +lxb_css_syntax_token_type_t +lxb_css_syntax_token_type_id_by_name(const lxb_char_t *type_name, size_t len) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_syntax_token_res_name_shs_map, + type_name, len); + if (entry == NULL) { + return LXB_CSS_SYNTAX_TOKEN_UNDEF; + } + + return (lxb_css_syntax_token_type_t) (uintptr_t) entry->value; +} + + +lxb_status_t +lxb_css_syntax_token_serialize(const lxb_css_syntax_token_t *token, + lxb_css_syntax_token_cb_f cb, void *ctx) +{ + size_t len; + lxb_status_t status; + lxb_char_t buf[128]; + const lxb_css_syntax_token_string_t *str; + const lxb_css_syntax_token_dimension_t *dim; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DELIM: + len = lxb_css_syntax_token_encode_utf_8(buf, + token->types.delim.character); + buf[len] = 0x00; + + return cb(buf, len, ctx); + + case LXB_CSS_SYNTAX_TOKEN_UNICODE_RANGE: + /* Start */ + buf[0] = 'U'; + buf[1] = '+'; + len = 2; + len += lexbor_conv_dec_to_hex(token->types.unicode_range.start, + &buf[len], (sizeof(buf) - 1) - len, + true); + + /* End */ + buf[len] = '-'; + len += 1; + len += lexbor_conv_dec_to_hex(token->types.unicode_range.end, + &buf[len], (sizeof(buf) - 1) - len, + true); + buf[len] = 0x00; + + return cb(buf, len, ctx); + + case LXB_CSS_SYNTAX_TOKEN_NUMBER: + len = lexbor_conv_float_to_data(token->types.number.num, + buf, (sizeof(buf) - 1)); + + buf[len] = 0x00; + + return cb(buf, len, ctx); + + case LXB_CSS_SYNTAX_TOKEN_PERCENTAGE: + len = lexbor_conv_float_to_data(token->types.number.num, + buf, (sizeof(buf) - 1)); + + buf[len] = 0x00; + + status = cb(buf, len, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb((lxb_char_t *) "%", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_CDO: + return cb((lxb_char_t *) "", 3, ctx); + + case LXB_CSS_SYNTAX_TOKEN_COLON: + return cb((lxb_char_t *) ":", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + return cb((lxb_char_t *) ";", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_COMMA: + return cb((lxb_char_t *) ",", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_LS_BRACKET: + return cb((lxb_char_t *) "[", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_RS_BRACKET: + return cb((lxb_char_t *) "]", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS: + return cb((lxb_char_t *) "(", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS: + return cb((lxb_char_t *) ")", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_LC_BRACKET: + return cb((lxb_char_t *) "{", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_RC_BRACKET: + return cb((lxb_char_t *) "}", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_HASH: + status = cb((lxb_char_t *) "#", 1, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + str = &token->types.string; + + return cb(str->data, str->length, ctx); + + case LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD: + status = cb((lxb_char_t *) "@", 1, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + str = &token->types.string; + + return cb(str->data, str->length, ctx); + + case LXB_CSS_SYNTAX_TOKEN_WHITESPACE: + case LXB_CSS_SYNTAX_TOKEN_IDENT: + str = &token->types.string; + + return cb(str->data, str->length, ctx); + + case LXB_CSS_SYNTAX_TOKEN_FUNCTION: + str = &token->types.string; + + status = cb(str->data, str->length, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb((lxb_char_t *) "(", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_STRING: + case LXB_CSS_SYNTAX_TOKEN_BAD_STRING: { + status = cb((lxb_char_t *) "\"", 1, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + const lxb_char_t *begin = token->types.string.data; + const lxb_char_t *end = begin + token->types.string.length; + + const lxb_char_t *ptr = begin; + + for (; begin < end; begin++) { + /* 0x5C; '\'; Inverse/backward slash */ + if (*begin == 0x5C) { + begin += 1; + + status = cb(ptr, (begin - ptr), ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (begin == end) { + status = cb((const lxb_char_t *) "\\", 1, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ptr = begin; + + break; + } + + begin -= 1; + ptr = begin; + } + /* 0x22; '"'; Only quotes above */ + else if (*begin == 0x22) { + if (ptr != begin) { + status = cb(ptr, (begin - ptr), ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + status = cb((const lxb_char_t *) "\\", 1, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + ptr = begin; + } + } + + if (ptr != begin) { + status = cb(ptr, (begin - ptr), ctx); + if (status != LXB_STATUS_OK) { + return status; + } + } + + return cb((const lxb_char_t *) "\"", 1, ctx); + } + + case LXB_CSS_SYNTAX_TOKEN_URL: + case LXB_CSS_SYNTAX_TOKEN_BAD_URL: + status = cb((lxb_char_t *) "url(", 4, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + str = &token->types.string; + + status = cb(str->data, str->length, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb((lxb_char_t *) ")", 1, ctx); + + case LXB_CSS_SYNTAX_TOKEN_COMMENT: + status = cb((lxb_char_t *) "/*", 2, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + str = &token->types.string; + + status = cb(str->data, str->length, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb((lxb_char_t *) "*/", 2, ctx); + + case LXB_CSS_SYNTAX_TOKEN_DIMENSION: + len = lexbor_conv_float_to_data(token->types.number.num, + buf, (sizeof(buf) - 1)); + + buf[len] = 0x00; + + status = cb(buf, len, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + dim = &token->types.dimension; + + return cb(dim->str.data, dim->str.length, ctx); + + case LXB_CSS_SYNTAX_TOKEN__EOF: + return cb((lxb_char_t *) "END-OF-FILE", 11, ctx); + + case LXB_CSS_SYNTAX_TOKEN__END: + return cb((lxb_char_t *) "END", 3, ctx); + + default: + return LXB_STATUS_ERROR; + } +} + +lxb_status_t +lxb_css_syntax_token_serialize_str(const lxb_css_syntax_token_t *token, + lexbor_str_t *str, lexbor_mraw_t *mraw) +{ + lxb_css_syntax_token_ctx_t ctx; + + ctx.str = str; + ctx.mraw = mraw; + + if (str->data == NULL) { + lexbor_str_init(str, mraw, 1); + if (str->data == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + } + + return lxb_css_syntax_token_serialize(token, lxb_css_syntax_token_str_cb, + &ctx); +} + +static lxb_status_t +lxb_css_syntax_token_str_cb(const lxb_char_t *data, size_t len, void *cb_ctx) +{ + lxb_char_t *ptr; + lxb_css_syntax_token_ctx_t *ctx = (lxb_css_syntax_token_ctx_t *) cb_ctx; + + ptr = lexbor_str_append(ctx->str, ctx->mraw, data, len); + if (ptr == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + return LXB_STATUS_OK; +} + + +lxb_char_t * +lxb_css_syntax_token_serialize_char(const lxb_css_syntax_token_t *token, + size_t *out_length) +{ + size_t length = 0; + lxb_status_t status; + lexbor_str_t str; + + status = lxb_css_syntax_token_serialize(token, lexbor_serialize_length_cb, + &length); + if (status != LXB_STATUS_OK) { + goto failed; + } + + /* + 1 == '\0' */ + str.data = lexbor_malloc(length + 1); + if (str.data == NULL) { + goto failed; + } + + str.length = 0; + + status = lxb_css_syntax_token_serialize(token, lexbor_serialize_copy_cb, + &str); + if (status != LXB_STATUS_OK) { + lexbor_free(str.data); + goto failed; + } + + str.data[str.length] = '\0'; + + if (out_length != NULL) { + *out_length = str.length; + } + + return str.data; + +failed: + + if (out_length != NULL) { + *out_length = 0; + } + + return NULL; +} + +lxb_css_log_message_t * +lxb_css_syntax_token_error(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const char *module_name) +{ + (void) token; (void) module_name; + + /* Size patch: the token text is never read by the shim (parser->status is + * the only observable), so it is not serialized; callers only require a + * non-NULL message record. */ + return lxb_css_log_push(parser->log, LXB_CSS_LOG_SYNTAX_ERROR, 0); +} + +static int8_t +lxb_css_syntax_token_encode_utf_8(lxb_char_t *data, lxb_codepoint_t cp) +{ + if (cp < 0x80) { + /* 0xxxxxxx */ + *data = (lxb_char_t) cp; + + return 1; + } + + if (cp < 0x800) { + /* 110xxxxx 10xxxxxx */ + *data++ = (lxb_char_t) (0xC0 | (cp >> 6 )); + *data = (lxb_char_t) (0x80 | (cp & 0x3F)); + + return 2; + } + + if (cp < 0x10000) { + /* 1110xxxx 10xxxxxx 10xxxxxx */ + *data++ = (lxb_char_t) (0xE0 | ((cp >> 12))); + *data++ = (lxb_char_t) (0x80 | ((cp >> 6 ) & 0x3F)); + *data = (lxb_char_t) (0x80 | ( cp & 0x3F)); + + return 3; + } + + if (cp < 0x110000) { + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + *data++ = (lxb_char_t) (0xF0 | ( cp >> 18)); + *data++ = (lxb_char_t) (0x80 | ((cp >> 12) & 0x3F)); + *data++ = (lxb_char_t) (0x80 | ((cp >> 6 ) & 0x3F)); + *data = (lxb_char_t) (0x80 | ( cp & 0x3F)); + + return 4; + } + + return 0; +} + +/* + * No inline functions for ABI. + */ +lxb_css_syntax_token_t * +lxb_css_syntax_token_create_noi(lexbor_dobject_t *dobj) +{ + return lxb_css_syntax_token_create(dobj); +} + +void +lxb_css_syntax_token_clean_noi(lxb_css_syntax_token_t *token) +{ + lxb_css_syntax_token_clean(token); +} + +lxb_css_syntax_token_t * +lxb_css_syntax_token_destroy_noi(lxb_css_syntax_token_t *token, + lexbor_dobject_t *dobj) +{ + return lxb_css_syntax_token_destroy(token, dobj); +} + +const lxb_char_t * +lxb_css_syntax_token_type_name_noi(lxb_css_syntax_token_t *token) +{ + return lxb_css_syntax_token_type_name(token); +} + +lxb_css_syntax_token_type_t +lxb_css_syntax_token_type_noi(lxb_css_syntax_token_t *token) +{ + return lxb_css_syntax_token_type(token); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token.h new file mode 100644 index 0000000..229ebb1 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token.h @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2018-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_TOKEN_H +#define LEXBOR_CSS_SYNTAX_TOKEN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/str.h" + +#include "lexbor/css/log.h" +#include "lexbor/css/syntax/base.h" + + +#define lxb_css_syntax_token_base(token) ((lxb_css_syntax_token_base_t *) (token)) +#define lxb_css_syntax_token_ident(token) ((lxb_css_syntax_token_ident_t *) (token)) +#define lxb_css_syntax_token_function(token) ((lxb_css_syntax_token_function_t *) (token)) +#define lxb_css_syntax_token_at_keyword(token) ((lxb_css_syntax_token_at_keyword_t *) (token)) +#define lxb_css_syntax_token_hash(token) ((lxb_css_syntax_token_hash_t *) (token)) +#define lxb_css_syntax_token_string(token) ((lxb_css_syntax_token_string_t *) (token)) +#define lxb_css_syntax_token_bad_string(token) ((lxb_css_syntax_token_bad_string_t *) (token)) +#define lxb_css_syntax_token_url(token) ((lxb_css_syntax_token_url_t *) (token)) +#define lxb_css_syntax_token_bad_url(token) ((lxb_css_syntax_token_bad_url_t *) (token)) +#define lxb_css_syntax_token_delim(token) ((lxb_css_syntax_token_delim_t *) (token)) +#define lxb_css_syntax_token_delim_char(token) (((lxb_css_syntax_token_delim_t *) (token))->character) +#define lxb_css_syntax_token_unicode_range(token) ((lxb_css_syntax_token_unicode_range_t *) (token)) +#define lxb_css_syntax_token_number(token) ((lxb_css_syntax_token_number_t *) (token)) +#define lxb_css_syntax_token_percentage(token) ((lxb_css_syntax_token_percentage_t *) (token)) +#define lxb_css_syntax_token_dimension(token) ((lxb_css_syntax_token_dimension_t *) (token)) +#define lxb_css_syntax_token_dimension_string(token) (&((lxb_css_syntax_token_dimension_t *) (token))->str) +#define lxb_css_syntax_token_whitespace(token) ((lxb_css_syntax_token_whitespace_t *) (token)) +#define lxb_css_syntax_token_cdo(token) ((lxb_css_syntax_token_cdo_t *) (token)) +#define lxb_css_syntax_token_cdc(token) ((lxb_css_syntax_token_cdc_t *) (token)) +#define lxb_css_syntax_token_colon(token) ((lxb_css_syntax_token_colon_t *) (token)) +#define lxb_css_syntax_token_semicolon(token) ((lxb_css_syntax_token_semicolon_t *) (token)) +#define lxb_css_syntax_token_comma(token) ((lxb_css_syntax_token_comma_t *) (token)) +#define lxb_css_syntax_token_ls_bracket(token) ((lxb_css_syntax_token_ls_bracket_t *) (token)) +#define lxb_css_syntax_token_rs_bracket(token) ((lxb_css_syntax_token_rs_bracket_t *) (token)) +#define lxb_css_syntax_token_l_parenthesis(token) ((lxb_css_syntax_token_l_parenthesis_t *) (token)) +#define lxb_css_syntax_token_r_parenthesis(token) ((lxb_css_syntax_token_r_parenthesis_t *) (token)) +#define lxb_css_syntax_token_lc_bracket(token) ((lxb_css_syntax_token_lc_bracket_t *) (token)) +#define lxb_css_syntax_token_rc_bracket(token) ((lxb_css_syntax_token_rc_bracket_t *) (token)) +#define lxb_css_syntax_token_comment(token) ((lxb_css_syntax_token_comment_t *) (token)) + + +typedef struct lxb_css_syntax_token_data lxb_css_syntax_token_data_t; + +typedef const lxb_char_t * +(*lxb_css_syntax_token_data_cb_f)(const lxb_char_t *begin, const lxb_char_t *end, + lexbor_str_t *str, lexbor_mraw_t *mraw, + lxb_css_syntax_token_data_t *td); + +typedef lxb_status_t +(*lxb_css_syntax_token_cb_f)(const lxb_char_t *data, size_t len, void *ctx); + +struct lxb_css_syntax_token_data { + lxb_css_syntax_token_data_cb_f cb; + lxb_status_t status; + int count; + uint32_t num; + bool is_last; +}; + +typedef enum { + LXB_CSS_SYNTAX_TOKEN_UNDEF = 0x00, + + /* String tokens. */ + LXB_CSS_SYNTAX_TOKEN_IDENT, + LXB_CSS_SYNTAX_TOKEN_FUNCTION, + LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD, + LXB_CSS_SYNTAX_TOKEN_HASH, + LXB_CSS_SYNTAX_TOKEN_STRING, + LXB_CSS_SYNTAX_TOKEN_BAD_STRING, + LXB_CSS_SYNTAX_TOKEN_URL, + LXB_CSS_SYNTAX_TOKEN_BAD_URL, + LXB_CSS_SYNTAX_TOKEN_COMMENT, /* not in specification */ + LXB_CSS_SYNTAX_TOKEN_WHITESPACE, + + /* Has a string. */ + LXB_CSS_SYNTAX_TOKEN_DIMENSION, + + /* Other tokens. */ + LXB_CSS_SYNTAX_TOKEN_DELIM, + LXB_CSS_SYNTAX_TOKEN_UNICODE_RANGE, + LXB_CSS_SYNTAX_TOKEN_NUMBER, + LXB_CSS_SYNTAX_TOKEN_PERCENTAGE, + LXB_CSS_SYNTAX_TOKEN_CDO, + LXB_CSS_SYNTAX_TOKEN_CDC, + LXB_CSS_SYNTAX_TOKEN_COLON, + LXB_CSS_SYNTAX_TOKEN_SEMICOLON, + LXB_CSS_SYNTAX_TOKEN_COMMA, + LXB_CSS_SYNTAX_TOKEN_LS_BRACKET, /* U+005B LEFT SQUARE BRACKET ([) */ + LXB_CSS_SYNTAX_TOKEN_RS_BRACKET, /* U+005D RIGHT SQUARE BRACKET (]) */ + LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS, /* U+0028 LEFT PARENTHESIS (() */ + LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS, /* U+0029 RIGHT PARENTHESIS ()) */ + LXB_CSS_SYNTAX_TOKEN_LC_BRACKET, /* U+007B LEFT CURLY BRACKET ({) */ + LXB_CSS_SYNTAX_TOKEN_RC_BRACKET, /* U+007D RIGHT CURLY BRACKET (}) */ + LXB_CSS_SYNTAX_TOKEN__EOF, + LXB_CSS_SYNTAX_TOKEN__TERMINATED, /* Deprecated, use LXB_CSS_SYNTAX_TOKEN__END. */ + LXB_CSS_SYNTAX_TOKEN__END = LXB_CSS_SYNTAX_TOKEN__TERMINATED, + LXB_CSS_SYNTAX_TOKEN__LAST_ENTRY +} +lxb_css_syntax_token_type_t; + +typedef struct lxb_css_syntax_token_base { + const lxb_char_t *begin; + size_t length; + + uintptr_t user_id; +} +lxb_css_syntax_token_base_t; + +typedef struct lxb_css_syntax_token_number { + lxb_css_syntax_token_base_t base; + + double num; + bool is_float; + bool have_sign; +} +lxb_css_syntax_token_number_t; + +typedef struct lxb_css_syntax_token_string { + lxb_css_syntax_token_base_t base; + + const lxb_char_t *data; + size_t length; +} +lxb_css_syntax_token_string_t; + +typedef struct lxb_css_syntax_token_dimension { + lxb_css_syntax_token_number_t num; + lxb_css_syntax_token_string_t str; +} +lxb_css_syntax_token_dimension_t; + +typedef struct lxb_css_syntax_token_delim { + lxb_css_syntax_token_base_t base; + lxb_codepoint_t character; +} +lxb_css_syntax_token_delim_t; + +typedef struct lxb_css_syntax_token_unicode_range { + lxb_css_syntax_token_base_t base; + lxb_codepoint_t start; + lxb_codepoint_t end; +} +lxb_css_syntax_token_unicode_range_t; + +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_ident_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_function_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_at_keyword_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_hash_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_bad_string_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_url_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_bad_url_t; +typedef lxb_css_syntax_token_number_t lxb_css_syntax_token_percentage_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_whitespace_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_cdo_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_cdc_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_colon_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_semicolon_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_comma_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_ls_bracket_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_rs_bracket_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_l_parenthesis_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_r_parenthesis_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_lc_bracket_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_rc_bracket_t; +typedef lxb_css_syntax_token_string_t lxb_css_syntax_token_comment_t; +typedef lxb_css_syntax_token_base_t lxb_css_syntax_token_terminated_t; + +struct lxb_css_syntax_token { + union lxb_css_syntax_token_u { + lxb_css_syntax_token_base_t base; + lxb_css_syntax_token_comment_t comment; + lxb_css_syntax_token_number_t number; + lxb_css_syntax_token_dimension_t dimension; + lxb_css_syntax_token_percentage_t percentage; + lxb_css_syntax_token_hash_t hash; + lxb_css_syntax_token_string_t string; + lxb_css_syntax_token_bad_string_t bad_string; + lxb_css_syntax_token_delim_t delim; + lxb_css_syntax_token_unicode_range_t unicode_range; + lxb_css_syntax_token_l_parenthesis_t lparenthesis; + lxb_css_syntax_token_r_parenthesis_t rparenthesis; + lxb_css_syntax_token_cdc_t cdc; + lxb_css_syntax_token_function_t function; + lxb_css_syntax_token_ident_t ident; + lxb_css_syntax_token_url_t url; + lxb_css_syntax_token_bad_url_t bad_url; + lxb_css_syntax_token_at_keyword_t at_keyword; + lxb_css_syntax_token_whitespace_t whitespace; + lxb_css_syntax_token_terminated_t terminated; + } + types; + + lxb_css_syntax_token_type_t type; + uintptr_t offset; + bool cloned; + + lxb_css_syntax_token_t *next; +}; + + +LXB_API lxb_css_syntax_token_t * +lxb_css_syntax_token(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API lxb_css_syntax_token_t * +lxb_css_syntax_token_next(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API void +lxb_css_syntax_token_consume(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API void +lxb_css_syntax_token_consume_n(lxb_css_syntax_tokenizer_t *tkz, unsigned count); + +LXB_API lxb_status_t +lxb_css_syntax_token_string_dup(lxb_css_syntax_token_string_t *token, + lexbor_str_t *str, lexbor_mraw_t *mraw); + +LXB_API lxb_status_t +lxb_css_syntax_token_string_make(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token); + +LXB_API void +lxb_css_syntax_token_string_free(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token); + +LXB_API const lxb_char_t * +lxb_css_syntax_token_type_name_by_id(lxb_css_syntax_token_type_t type); + +LXB_API lxb_css_syntax_token_type_t +lxb_css_syntax_token_type_id_by_name(const lxb_char_t *type_name, size_t len); + +LXB_API lxb_status_t +lxb_css_syntax_token_serialize(const lxb_css_syntax_token_t *token, + lxb_css_syntax_token_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_syntax_token_serialize_str(const lxb_css_syntax_token_t *token, + lexbor_str_t *str, lexbor_mraw_t *mraw); + +LXB_API lxb_char_t * +lxb_css_syntax_token_serialize_char(const lxb_css_syntax_token_t *token, + size_t *out_length); + +LXB_API lxb_css_log_message_t * +lxb_css_syntax_token_error(lxb_css_parser_t *parser, + const lxb_css_syntax_token_t *token, + const char *module_name); + +/* + * Inline functions + */ +lxb_inline lxb_css_syntax_token_t * +lxb_css_syntax_token_create(lexbor_dobject_t *dobj) +{ + return (lxb_css_syntax_token_t *) lexbor_dobject_calloc(dobj); +} + +lxb_inline void +lxb_css_syntax_token_clean(lxb_css_syntax_token_t *token) +{ + memset(token, 0, sizeof(lxb_css_syntax_token_t)); +} + +lxb_inline lxb_css_syntax_token_t * +lxb_css_syntax_token_destroy(lxb_css_syntax_token_t *token, + lexbor_dobject_t *dobj) +{ + return (lxb_css_syntax_token_t *) lexbor_dobject_free(dobj, token); +} + +lxb_inline const lxb_char_t * +lxb_css_syntax_token_type_name(const lxb_css_syntax_token_t *token) +{ + return lxb_css_syntax_token_type_name_by_id(token->type); +} + +lxb_inline lxb_css_syntax_token_type_t +lxb_css_syntax_token_type(const lxb_css_syntax_token_t *token) +{ + return token->type; +} + +lxb_inline lxb_css_syntax_token_t * +lxb_css_syntax_token_wo_ws(lxb_css_syntax_tokenizer_t *tkz) +{ + lxb_css_syntax_token_t *token; + + token = lxb_css_syntax_token(tkz); + if (token == NULL) { + return NULL; + } + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + lxb_css_syntax_token_consume(tkz); + token = lxb_css_syntax_token(tkz); + } + + return token; +} + +/* + * No inline functions for ABI. + */ +LXB_API lxb_css_syntax_token_t * +lxb_css_syntax_token_create_noi(lexbor_dobject_t *dobj); + +LXB_API void +lxb_css_syntax_token_clean_noi(lxb_css_syntax_token_t *token); + +LXB_API lxb_css_syntax_token_t * +lxb_css_syntax_token_destroy_noi(lxb_css_syntax_token_t *token, + lexbor_dobject_t *dobj); + +LXB_API const lxb_char_t * +lxb_css_syntax_token_type_name_noi(lxb_css_syntax_token_t *token); + +LXB_API lxb_css_syntax_token_type_t +lxb_css_syntax_token_type_noi(lxb_css_syntax_token_t *token); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_TOKEN_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token_res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token_res.h new file mode 100644 index 0000000..d5ee29c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/token_res.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_TOKEN_RES_H +#define LEXBOR_CSS_SYNTAX_TOKEN_RES_H + +static const lexbor_shs_entry_t lxb_css_syntax_token_res_name_shs_map[136] = +{ + {NULL, NULL, 135, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"colon", (void *) LXB_CSS_SYNTAX_TOKEN_COLON, 5, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"undefined", (void *) LXB_CSS_SYNTAX_TOKEN_UNDEF, 9, 0}, {"right-curly-bracket", (void *) LXB_CSS_SYNTAX_TOKEN_RC_BRACKET, 19, 0}, + {"right-square-bracket", (void *) LXB_CSS_SYNTAX_TOKEN_RS_BRACKET, 20, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"delim", (void *) LXB_CSS_SYNTAX_TOKEN_DELIM, 5, 0}, {"left-parenthesis", (void *) LXB_CSS_SYNTAX_TOKEN_L_PARENTHESIS, 16, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"dimension", (void *) LXB_CSS_SYNTAX_TOKEN_DIMENSION, 9, 0}, {"url", (void *) LXB_CSS_SYNTAX_TOKEN_URL, 3, 0}, + {"string", (void *) LXB_CSS_SYNTAX_TOKEN_STRING, 6, 0}, {"comma", (void *) LXB_CSS_SYNTAX_TOKEN_COMMA, 5, 0}, + {NULL, NULL, 0, 0}, {"bad-url", (void *) LXB_CSS_SYNTAX_TOKEN_BAD_URL, 7, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {"hash", (void *) LXB_CSS_SYNTAX_TOKEN_HASH, 4, 0}, + {NULL, NULL, 0, 0}, {"ident", (void *) LXB_CSS_SYNTAX_TOKEN_IDENT, 5, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"function", (void *) LXB_CSS_SYNTAX_TOKEN_FUNCTION, 8, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"cdc", (void *) LXB_CSS_SYNTAX_TOKEN_CDC, 3, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"unicode-range", (void *) LXB_CSS_SYNTAX_TOKEN_UNICODE_RANGE, 13, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {"left-curly-bracket", (void *) LXB_CSS_SYNTAX_TOKEN_LC_BRACKET, 18, 0}, + {"left-square-bracket", (void *) LXB_CSS_SYNTAX_TOKEN_LS_BRACKET, 19, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"bad-string", (void *) LXB_CSS_SYNTAX_TOKEN_BAD_STRING, 10, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"whitespace", (void *) LXB_CSS_SYNTAX_TOKEN_WHITESPACE, 10, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {"cdo", (void *) LXB_CSS_SYNTAX_TOKEN_CDO, 3, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {"comment", (void *) LXB_CSS_SYNTAX_TOKEN_COMMENT, 7, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"at-keyword", (void *) LXB_CSS_SYNTAX_TOKEN_AT_KEYWORD, 10, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"right-parenthesis", (void *) LXB_CSS_SYNTAX_TOKEN_R_PARENTHESIS, 17, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"number", (void *) LXB_CSS_SYNTAX_TOKEN_NUMBER, 6, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {"percentage", (void *) LXB_CSS_SYNTAX_TOKEN_PERCENTAGE, 10, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {"end-of-file", (void *) LXB_CSS_SYNTAX_TOKEN__EOF, 11, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, {"semicolon", (void *) LXB_CSS_SYNTAX_TOKEN_SEMICOLON, 9, 0} +}; + +#endif /* LEXBOR_CSS_SYNTAX_TOKEN_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer.c new file mode 100644 index 0000000..a44b2c7 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer.c @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2018-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/syntax/tokenizer.h" +#include "lexbor/css/syntax/tokenizer/error.h" +#include "lexbor/css/syntax/state.h" +#include "lexbor/css/syntax/state_res.h" +#include "lexbor/css/syntax/token.h" + +#include "lexbor/core/array.h" + + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_map_lowercase[256]; +#endif + +static const lxb_char_t lxb_css_syntax_tokenizer_important[] = "important"; + + +static bool +lxb_css_syntax_tokenizer_lookup_important_ch(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *p, + const lxb_char_t *end, + const lxb_char_t stop_ch); + +static bool +lxb_css_syntax_tokenizer_lookup_important_end(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *p, + const lxb_char_t *end, + const lxb_char_t stop_ch); + +lxb_css_syntax_tokenizer_t * +lxb_css_syntax_tokenizer_create(void) +{ + return lexbor_calloc(1, sizeof(lxb_css_syntax_tokenizer_t)); +} + +lxb_status_t +lxb_css_syntax_tokenizer_init(lxb_css_syntax_tokenizer_t *tkz) +{ + lxb_status_t status; + static const unsigned tmp_size = 1024; + + if (tkz == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + /* Tokens. */ + + tkz->tokens = lexbor_dobject_create(); + status = lexbor_dobject_init(tkz->tokens, 128, + sizeof(lxb_css_syntax_token_t)); + if (status != LXB_STATUS_OK) { + return status; + } + + /* Memory for text. */ + + tkz->mraw = lexbor_mraw_create(); + status = lexbor_mraw_init(tkz->mraw, 4096); + if (status != LXB_STATUS_OK) { + return status; + } + + /* Temp */ + tkz->start = lexbor_malloc(tmp_size); + if (tkz->start == NULL) { + return LXB_STATUS_ERROR_MEMORY_ALLOCATION; + } + + tkz->pos = tkz->start; + tkz->end = tkz->start + tmp_size; + + /* Parse errors */ + tkz->parse_errors = lexbor_array_obj_create(); + status = lexbor_array_obj_init(tkz->parse_errors, 16, + sizeof(lxb_css_syntax_tokenizer_error_t)); + if (status != LXB_STATUS_OK) { + return status; + } + + tkz->first = NULL; + tkz->last = NULL; + + tkz->offset = 0; + + tkz->with_comment = false; + tkz->with_unicode_range = false; + tkz->status = LXB_STATUS_OK; + tkz->opt = LXB_CSS_SYNTAX_TOKENIZER_OPT_UNDEF; + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_syntax_tokenizer_clean(lxb_css_syntax_tokenizer_t *tkz) +{ + lexbor_mraw_clean(tkz->mraw); + lexbor_array_obj_clean(tkz->parse_errors); + lexbor_dobject_clean(tkz->tokens); + + tkz->in_begin = NULL; + tkz->in_p = NULL; + tkz->in_end = NULL; + tkz->first = NULL; + tkz->last = NULL; + tkz->pos = tkz->start; + tkz->offset = 0; + tkz->status = LXB_STATUS_OK; + + return LXB_STATUS_OK; +} + +lxb_css_syntax_tokenizer_t * +lxb_css_syntax_tokenizer_destroy(lxb_css_syntax_tokenizer_t *tkz) +{ + if (tkz == NULL) { + return NULL; + } + + if (tkz->tokens != NULL) { + tkz->tokens = lexbor_dobject_destroy(tkz->tokens, true); + } + + tkz->mraw = lexbor_mraw_destroy(tkz->mraw, true); + tkz->parse_errors = lexbor_array_obj_destroy(tkz->parse_errors, true); + + if (tkz->start != NULL) { + tkz->start = lexbor_free(tkz->start); + } + + return lexbor_free(tkz); +} + +lxb_css_syntax_token_t * +lxb_css_syntax_tokenizer_token(lxb_css_syntax_tokenizer_t *tkz) +{ + lxb_status_t status; + lxb_css_syntax_token_t *token; + const lxb_char_t *begin, *end; + + begin = tkz->in_p; + end = tkz->in_end; + + token = lexbor_dobject_calloc(tkz->tokens); + if (token == NULL) { + tkz->status = LXB_STATUS_ERROR_MEMORY_ALLOCATION; + return NULL; + } + + if (tkz->first == NULL) { + tkz->first = token; + } + + if (tkz->last != NULL) { + status = lxb_css_syntax_token_string_make(tkz, tkz->last); + if (status != LXB_STATUS_OK) { + return NULL; + } + + tkz->last->next = token; + } + + tkz->last = token; + +again: + + lxb_css_syntax_token_base(token)->begin = begin; + + if (begin < end) { + begin = lxb_css_syntax_state_res_map[*begin](tkz, token, begin, end); + if (begin == NULL) { + return NULL; + } + } + else { + token->type = LXB_CSS_SYNTAX_TOKEN__EOF; + } + + token->offset = tkz->offset; + lxb_css_syntax_token_base(token)->length = begin - tkz->in_p; + tkz->offset += lxb_css_syntax_token_base(token)->length; + + tkz->in_p = begin; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_COMMENT && !tkz->with_comment) { + goto again; + } + + return token; +} + +bool +lxb_css_syntax_tokenizer_lookup_colon(lxb_css_syntax_tokenizer_t *tkz) +{ + const lxb_char_t *p, *end; + lxb_css_syntax_token_t *token; + + if (tkz->first != NULL && tkz->first->next != NULL) { + token = tkz->first->next; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + if (token->next != NULL) { + return token->next->type == LXB_CSS_SYNTAX_TOKEN_COLON; + } + } + else if (token->type == LXB_CSS_SYNTAX_TOKEN_COLON) { + return true; + } + + return false; + } + + p = tkz->in_p; + end = tkz->in_end; + + while (p < end) { + switch (*p) { + case 0x3A: + return true; + + case 0x0D: + case 0x0C: + case 0x09: + case 0x20: + case 0x0A: + p += 1; + break; + + default: + return false; + } + } + + return false; +} + +bool +lxb_css_syntax_tokenizer_lookup_important(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_type_t stop, + const lxb_char_t stop_ch) +{ + const lxb_char_t *p, *end; + lxb_css_syntax_token_t *token; + + static const size_t length = sizeof(lxb_css_syntax_tokenizer_important) - 1; + + p = tkz->in_p; + end = tkz->in_end; + + if (tkz->first != NULL && tkz->first->next != NULL) { + token = tkz->first->next; + + if (token->type != LXB_CSS_SYNTAX_TOKEN_IDENT) { + return false; + } + + if (!(lxb_css_syntax_token_ident(token)->length == length + && lexbor_str_data_ncasecmp(lxb_css_syntax_token_ident(token)->data, + lxb_css_syntax_tokenizer_important, + length))) + { + return false; + } + + if (token->next != NULL) { + token = token->next; + + if (token->type == LXB_CSS_SYNTAX_TOKEN_WHITESPACE) { + if (token->next == NULL) { + return lxb_css_syntax_tokenizer_lookup_important_end(tkz, + p, end, stop_ch); + } + + token = token->next; + } + + return (token->type == LXB_CSS_SYNTAX_TOKEN_SEMICOLON + || token->type == stop + || token->type == LXB_CSS_SYNTAX_TOKEN__EOF); + } + + return lxb_css_syntax_tokenizer_lookup_important_end(tkz, p, end, + stop_ch); + } + + return lxb_css_syntax_tokenizer_lookup_important_ch(tkz, p, end, stop_ch); +} + +static bool +lxb_css_syntax_tokenizer_lookup_important_ch(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *p, + const lxb_char_t *end, + const lxb_char_t stop_ch) +{ + static const size_t length = sizeof(lxb_css_syntax_tokenizer_important) - 1; + + if (!(lxb_size(end - p) >= length + && lexbor_str_data_ncasecmp(p, lxb_css_syntax_tokenizer_important, + length))) + { + return false; + } + + return lxb_css_syntax_tokenizer_lookup_important_end(tkz, p + length, + end, stop_ch); +} + +static bool +lxb_css_syntax_tokenizer_lookup_important_end(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *p, + const lxb_char_t *end, + const lxb_char_t stop_ch) +{ + while (p < end) { + switch (*p) { + case 0x3B: + return true; + + case 0x0D: + case 0x0C: + case 0x09: + case 0x20: + case 0x0A: + p += 1; + break; + + default: + return (stop_ch != 0x00 && stop_ch == *p); + } + } + + /* EOF */ + return true; +} + +bool +lxb_css_syntax_tokenizer_lookup_declaration_ws_end(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_type_t stop, + const lxb_char_t stop_ch) +{ + lxb_css_syntax_token_t *token; + const lxb_char_t *p, *end; + + if (tkz->first != NULL && tkz->first->next) { + token = tkz->first->next; + + switch (token->type) { + case LXB_CSS_SYNTAX_TOKEN_DELIM: + if (lxb_css_syntax_token_delim(token)->character != '!') { + return lxb_css_syntax_tokenizer_lookup_important(tkz, stop, + stop_ch); + } + + return false; + + case LXB_CSS_SYNTAX_TOKEN_SEMICOLON: + return true; + + default: + return token->type == stop_ch || + token->type == LXB_CSS_SYNTAX_TOKEN__EOF; + } + } + + p = tkz->in_p; + end = tkz->in_end; + + while (p < end) { + switch (*p) { + case 0x3B: + return true; + + case 0x21: + p += 1; + return lxb_css_syntax_tokenizer_lookup_important_ch(tkz, p, end, + stop_ch); + + default: + return (stop_ch != 0x00 && stop_ch == *p); + } + } + + return false; +} + +/* + * No inline functions for ABI. + */ +lxb_status_t +lxb_css_syntax_tokenizer_status_noi(lxb_css_syntax_tokenizer_t *tkz) +{ + return lxb_css_syntax_tokenizer_status(tkz); +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer.h new file mode 100644 index 0000000..c72ed76 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2018-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_TOKENIZER_H +#define LEXBOR_CSS_SYNTAX_TOKENIZER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/array_obj.h" + +#include "lexbor/css/syntax/base.h" +#include "lexbor/css/syntax/token.h" + + +/* State */ +typedef const lxb_char_t * +(*lxb_css_syntax_tokenizer_state_f)(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_t *token, + const lxb_char_t *data, const lxb_char_t *end); + +enum lxb_css_syntax_tokenizer_opt { + LXB_CSS_SYNTAX_TOKENIZER_OPT_UNDEF = 0x00, +}; + +struct lxb_css_syntax_tokenizer { + lexbor_dobject_t *tokens; + lexbor_array_obj_t *parse_errors; + lexbor_mraw_t *mraw; + + lxb_css_syntax_token_t *first; + lxb_css_syntax_token_t *last; + + const lxb_char_t *in_begin; + const lxb_char_t *in_end; + const lxb_char_t *in_p; + + /* Temp */ + lxb_char_t *start; + lxb_char_t *pos; + const lxb_char_t *end; + + size_t offset; + + /* Process */ + unsigned int opt; /* bitmap */ + lxb_status_t status; + bool with_comment; + bool with_unicode_range; +}; + + +LXB_API lxb_css_syntax_tokenizer_t * +lxb_css_syntax_tokenizer_create(void); + +LXB_API lxb_status_t +lxb_css_syntax_tokenizer_init(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API lxb_status_t +lxb_css_syntax_tokenizer_clean(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API lxb_css_syntax_tokenizer_t * +lxb_css_syntax_tokenizer_destroy(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API lxb_status_t +lxb_css_syntax_tokenizer_next_chunk(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t **data, const lxb_char_t **end); + +LXB_API bool +lxb_css_syntax_tokenizer_lookup_colon(lxb_css_syntax_tokenizer_t *tkz); + +LXB_API bool +lxb_css_syntax_tokenizer_lookup_important(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_type_t stop, + const lxb_char_t stop_ch); + +LXB_API bool +lxb_css_syntax_tokenizer_lookup_declaration_ws_end(lxb_css_syntax_tokenizer_t *tkz, + lxb_css_syntax_token_type_t stop, + const lxb_char_t stop_ch); + +/* + * Inline functions + */ +lxb_inline lxb_status_t +lxb_css_syntax_tokenizer_status(lxb_css_syntax_tokenizer_t *tkz) +{ + return tkz->status; +} + +lxb_inline void +lxb_css_syntax_tokenizer_buffer_set(lxb_css_syntax_tokenizer_t *tkz, + const lxb_char_t *data, size_t size) +{ + tkz->in_begin = data; + tkz->in_p = data; + tkz->in_end = data + size; +} + +lxb_inline void +lxb_css_syntax_tokenizer_with_unicode_range(lxb_css_syntax_tokenizer_t *tkz, + bool with_range) +{ + tkz->with_unicode_range = with_range; +} + + +/* + * No inline functions for ABI. + */ +LXB_API lxb_status_t +lxb_css_syntax_tokenizer_status_noi(lxb_css_syntax_tokenizer_t *tkz); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_TOKENIZER_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer/error.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer/error.c new file mode 100644 index 0000000..a95723c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer/error.c @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018-2019 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/syntax/tokenizer/error.h" + + +lxb_css_syntax_tokenizer_error_t * +lxb_css_syntax_tokenizer_error_add(lexbor_array_obj_t *parse_errors, + const lxb_char_t *pos, + lxb_css_syntax_tokenizer_error_id_t id) +{ + if (parse_errors == NULL) { + return NULL; + } + + lxb_css_syntax_tokenizer_error_t *entry; + + entry = lexbor_array_obj_push(parse_errors); + if (entry == NULL) { + return NULL; + } + + entry->id = id; + entry->pos = pos; + + return entry; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer/error.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer/error.h new file mode 100644 index 0000000..66a1e17 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/syntax/tokenizer/error.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018-2025 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LEXBOR_CSS_SYNTAX_TOKENIZER_ERROR_H +#define LEXBOR_CSS_SYNTAX_TOKENIZER_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/core/base.h" +#include "lexbor/core/array_obj.h" + + +typedef enum { + /* unexpected-eof */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_UNEOF = 0x0000, + /* eof-in-comment */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINCO, + /* eof-in-string */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINST, + /* eof-in-url */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINUR, + /* eof-in-escaped */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_EOINES, + /* qo-in-url */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_QOINUR, + /* wrong-escape-in-url */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_WRESINUR, + /* newline-in-string */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_NEINST, + /* bad-char */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_BACH, + /* bad-code-point */ + LXB_CSS_SYNTAX_TOKENIZER_ERROR_BACOPO, +} +lxb_css_syntax_tokenizer_error_id_t; + +typedef struct { + const lxb_char_t *pos; + lxb_css_syntax_tokenizer_error_id_t id; +} +lxb_css_syntax_tokenizer_error_t; + + +LXB_API lxb_css_syntax_tokenizer_error_t * +lxb_css_syntax_tokenizer_error_add(lexbor_array_obj_t *parse_errors, + const lxb_char_t *pos, + lxb_css_syntax_tokenizer_error_id_t id); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LEXBOR_CSS_SYNTAX_TOKENIZER_ERROR_H */ + diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit.c new file mode 100644 index 0000000..f3cc9c8 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/unit/res.h" + + +const lxb_css_data_t * +lxb_css_unit_absolute_relative_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_absolute_relative_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_absolute_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_absolute_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_relative_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_relative_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_angle_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_angle_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_frequency_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_frequency_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_resolution_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_resolution_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_duration_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_unit_duration_shs, + name, length); + if (entry == NULL) { + return NULL; + } + + return entry->value; +} + +const lxb_css_data_t * +lxb_css_unit_by_id(lxb_css_type_t id) +{ + return &lxb_css_unit_data[id]; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit.h new file mode 100644 index 0000000..06dba0d --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_UNIT_H +#define LXB_CSS_UNIT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" + + +LXB_API const lxb_css_data_t * +lxb_css_unit_absolute_relative_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_absolute_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_relative_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_angle_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_frequency_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_resolution_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_duration_by_name(const lxb_char_t *name, size_t length); + +LXB_API const lxb_css_data_t * +lxb_css_unit_by_id(lxb_css_type_t id); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_UNIT_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit/const.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit/const.h new file mode 100644 index 0000000..9f5e515 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit/const.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_UNIT_CONST_H +#define LXB_CSS_UNIT_CONST_H + + +#include "lexbor/css/value/const.h" + + +typedef enum { + LXB_CSS_UNIT__UNDEF = 0x0000, + LXB_CSS_UNIT__LAST_ENTRY = 0x0022 +} +lxb_css_unit_t; + +typedef enum { + LXB_CSS_UNIT_ABSOLUTE__BEGIN = 0x0001, + LXB_CSS_UNIT_Q = 0x0001, + LXB_CSS_UNIT_CM = 0x0002, + LXB_CSS_UNIT_IN = 0x0003, + LXB_CSS_UNIT_MM = 0x0004, + LXB_CSS_UNIT_PC = 0x0005, + LXB_CSS_UNIT_PT = 0x0006, + LXB_CSS_UNIT_PX = 0x0007, + LXB_CSS_UNIT_ABSOLUTE__LAST_ENTRY = 0x0008 +} +lxb_css_unit_absolute_t; + +typedef enum { + LXB_CSS_UNIT_RELATIVE__BEGIN = 0x0008, + LXB_CSS_UNIT_CAP = 0x0008, + LXB_CSS_UNIT_CH = 0x0009, + LXB_CSS_UNIT_EM = 0x000a, + LXB_CSS_UNIT_EX = 0x000b, + LXB_CSS_UNIT_IC = 0x000c, + LXB_CSS_UNIT_LH = 0x000d, + LXB_CSS_UNIT_REM = 0x000e, + LXB_CSS_UNIT_RLH = 0x000f, + LXB_CSS_UNIT_VB = 0x0010, + LXB_CSS_UNIT_VH = 0x0011, + LXB_CSS_UNIT_VI = 0x0012, + LXB_CSS_UNIT_VMAX = 0x0013, + LXB_CSS_UNIT_VMIN = 0x0014, + LXB_CSS_UNIT_VW = 0x0015, + LXB_CSS_UNIT_RELATIVE__LAST_ENTRY = 0x0016 +} +lxb_css_unit_relative_t; + +typedef enum { + LXB_CSS_UNIT_ANGLE__BEGIN = 0x0016, + LXB_CSS_UNIT_DEG = 0x0016, + LXB_CSS_UNIT_GRAD = 0x0017, + LXB_CSS_UNIT_RAD = 0x0018, + LXB_CSS_UNIT_TURN = 0x0019, + LXB_CSS_UNIT_ANGLE__LAST_ENTRY = 0x001a +} +lxb_css_unit_angle_t; + +typedef enum { + LXB_CSS_UNIT_FREQUENCY__BEGIN = 0x001a, + LXB_CSS_UNIT_HZ = 0x001a, + LXB_CSS_UNIT_KHZ = 0x001b, + LXB_CSS_UNIT_FREQUENCY__LAST_ENTRY = 0x001c +} +lxb_css_unit_frequency_t; + +typedef enum { + LXB_CSS_UNIT_RESOLUTION__BEGIN = 0x001c, + LXB_CSS_UNIT_DPCM = 0x001c, + LXB_CSS_UNIT_DPI = 0x001d, + LXB_CSS_UNIT_DPPX = 0x001e, + LXB_CSS_UNIT_X = 0x001f, + LXB_CSS_UNIT_RESOLUTION__LAST_ENTRY = 0x0020 +} +lxb_css_unit_resolution_t; + +typedef enum { + LXB_CSS_UNIT_DURATION__BEGIN = 0x0020, + LXB_CSS_UNIT_MS = 0x0020, + LXB_CSS_UNIT_S = 0x0021, + LXB_CSS_UNIT_DURATION__LAST_ENTRY = 0x0022 +} +lxb_css_unit_duration_t; + + + +#endif /* LXB_CSS_UNIT_CONST_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit/res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit/res.h new file mode 100644 index 0000000..ac24503 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/unit/res.h @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_UNIT_RES_H +#define LXB_CSS_UNIT_RES_H + +#include "lexbor/core/shs.h" +#include "lexbor/css/unit/const.h" + + +static const lxb_css_data_t lxb_css_unit_data[LXB_CSS_UNIT__LAST_ENTRY] = +{ + {(lxb_char_t *) "#undef", 6, LXB_CSS_UNIT__UNDEF}, + {(lxb_char_t *) "Q", 1, LXB_CSS_UNIT_Q}, + {(lxb_char_t *) "cm", 2, LXB_CSS_UNIT_CM}, + {(lxb_char_t *) "in", 2, LXB_CSS_UNIT_IN}, + {(lxb_char_t *) "mm", 2, LXB_CSS_UNIT_MM}, + {(lxb_char_t *) "pc", 2, LXB_CSS_UNIT_PC}, + {(lxb_char_t *) "pt", 2, LXB_CSS_UNIT_PT}, + {(lxb_char_t *) "px", 2, LXB_CSS_UNIT_PX}, + {(lxb_char_t *) "cap", 3, LXB_CSS_UNIT_CAP}, + {(lxb_char_t *) "ch", 2, LXB_CSS_UNIT_CH}, + {(lxb_char_t *) "em", 2, LXB_CSS_UNIT_EM}, + {(lxb_char_t *) "ex", 2, LXB_CSS_UNIT_EX}, + {(lxb_char_t *) "ic", 2, LXB_CSS_UNIT_IC}, + {(lxb_char_t *) "lh", 2, LXB_CSS_UNIT_LH}, + {(lxb_char_t *) "rem", 3, LXB_CSS_UNIT_REM}, + {(lxb_char_t *) "rlh", 3, LXB_CSS_UNIT_RLH}, + {(lxb_char_t *) "vb", 2, LXB_CSS_UNIT_VB}, + {(lxb_char_t *) "vh", 2, LXB_CSS_UNIT_VH}, + {(lxb_char_t *) "vi", 2, LXB_CSS_UNIT_VI}, + {(lxb_char_t *) "vmax", 4, LXB_CSS_UNIT_VMAX}, + {(lxb_char_t *) "vmin", 4, LXB_CSS_UNIT_VMIN}, + {(lxb_char_t *) "vw", 2, LXB_CSS_UNIT_VW}, + {(lxb_char_t *) "deg", 3, LXB_CSS_UNIT_DEG}, + {(lxb_char_t *) "grad", 4, LXB_CSS_UNIT_GRAD}, + {(lxb_char_t *) "rad", 3, LXB_CSS_UNIT_RAD}, + {(lxb_char_t *) "turn", 4, LXB_CSS_UNIT_TURN}, + {(lxb_char_t *) "Hz", 2, LXB_CSS_UNIT_HZ}, + {(lxb_char_t *) "kHz", 3, LXB_CSS_UNIT_KHZ}, + {(lxb_char_t *) "dpcm", 4, LXB_CSS_UNIT_DPCM}, + {(lxb_char_t *) "dpi", 3, LXB_CSS_UNIT_DPI}, + {(lxb_char_t *) "dppx", 4, LXB_CSS_UNIT_DPPX}, + {(lxb_char_t *) "x", 1, LXB_CSS_UNIT_X}, + {(lxb_char_t *) "ms", 2, LXB_CSS_UNIT_MS}, + {(lxb_char_t *) "s", 1, LXB_CSS_UNIT_S} +}; + +static const lexbor_shs_entry_t lxb_css_unit_absolute_relative_shs[84] = +{ + {NULL, NULL, 83, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"rem", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_REM], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vmax", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VMAX], 4, 0}, + {"pc", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_PC], 2, 0}, + {"lh", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_LH], 2, 0}, + {NULL, NULL, 0, 0}, + {"rlh", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_RLH], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"cm", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_CM], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"q", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_Q], 1, 0}, + {"ic", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_IC], 2, 0}, + {NULL, NULL, 0, 0}, + {"vw", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VW], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"pt", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_PT], 2, 0}, + {"vb", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VB], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"ex", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_EX], 2, 0}, + {"in", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_IN], 2, 0}, + {"cap", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_CAP], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"em", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_EM], 2, 0}, + {NULL, NULL, 0, 0}, + {"vmin", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VMIN], 4, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vi", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VI], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"mm", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_MM], 2, 0}, + {"ch", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_CH], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"px", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_PX], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vh", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VH], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_unit_absolute_shs[30] = +{ + {NULL, NULL, 29, 0}, + {NULL, NULL, 0, 0}, + {"in", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_IN], 2, 0}, + {"pt", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_PT], 2, 0}, + {"q", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_Q], 1, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"mm", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_MM], 2, 0}, + {"px", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_PX], 2, 0}, + {"cm", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_CM], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"pc", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_PC], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_unit_relative_shs[64] = +{ + {NULL, NULL, 63, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"ic", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_IC], 2, 0}, + {"cap", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_CAP], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"rem", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_REM], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"em", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_EM], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"ch", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_CH], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"ex", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_EX], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vb", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VB], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vh", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VH], 2, 0}, + {"vi", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VI], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"rlh", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_RLH], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vmin", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VMIN], 4, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"lh", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_LH], 2, 0}, + {NULL, NULL, 0, 0}, + {"vw", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VW], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"vmax", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_VMAX], 4, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_unit_angle_shs[7] = +{ + {NULL, NULL, 6, 0}, + {"turn", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_TURN], 4, 0}, + {"deg", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_DEG], 3, 0}, + {"grad", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_GRAD], 4, 0}, + {"rad", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_RAD], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_unit_frequency_shs[6] = +{ + {NULL, NULL, 5, 0}, + {NULL, NULL, 0, 0}, + {"khz", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_KHZ], 3, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0}, + {"hz", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_HZ], 2, 0} +}; + +static const lexbor_shs_entry_t lxb_css_unit_resolution_shs[7] = +{ + {NULL, NULL, 6, 0}, + {NULL, NULL, 0, 0}, + {"x", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_X], 1, 0}, + {"dpcm", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_DPCM], 4, 0}, + {"dpi", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_DPI], 3, 0}, + {"dppx", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_DPPX], 4, 0}, + {NULL, NULL, 0, 0} +}; + +static const lexbor_shs_entry_t lxb_css_unit_duration_shs[6] = +{ + {NULL, NULL, 5, 0}, + {NULL, NULL, 0, 0}, + {"s", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_S], 1, 0}, + {"ms", (void *) &lxb_css_unit_data[LXB_CSS_UNIT_MS], 2, 0}, + {NULL, NULL, 0, 0}, + {NULL, NULL, 0, 0} +}; + + + + +#endif /* LXB_CSS_UNIT_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value.c new file mode 100644 index 0000000..23e2472 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value.c @@ -0,0 +1,678 @@ +/* + * Copyright (C) 2022-2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/css/css.h" +#include "lexbor/css/value/res.h" + +#include "lexbor/core/serialize.h" +#include "lexbor/core/conv.h" + + +#ifndef LEXBOR_DISABLE_INTERNAL_EXTERN + LXB_EXTERN const lxb_char_t lexbor_str_res_map_hex_to_char_lowercase[17]; + LXB_EXTERN const char *lexbor_str_res_char_to_two_hex_value_lowercase[257]; +#endif + +static const lexbor_str_t lxb_css_value_str_ws = lexbor_str(" "); +static const lexbor_str_t lxb_str_comma = lexbor_str(", "); +static const lexbor_str_t lxb_str_alpha = lexbor_str(" / "); +static const lexbor_str_t lxb_str_rp = lexbor_str(")"); + + +const lxb_css_data_t * +lxb_css_value_by_id(uintptr_t id) +{ + if (id < LXB_CSS_VALUE__LAST_ENTRY) { + return &lxb_css_value_data[id]; + } + + return NULL; +} + +lxb_css_value_type_t +lxb_css_value_by_name(const lxb_char_t *name, size_t length) +{ + const lexbor_shs_entry_t *entry; + + entry = lexbor_shs_entry_get_lower_static(lxb_css_value_shs, name, length); + if (entry == NULL) { + return LXB_CSS_VALUE__UNDEF; + } + + return (lxb_css_value_type_t) (uintptr_t) entry->value; +} + +lxb_status_t +lxb_css_value_serialize(lxb_css_value_type_t type, + lexbor_serialize_cb_f cb, void *ctx) +{ + const lxb_css_data_t *data; + + if (type >= LXB_CSS_VALUE__LAST_ENTRY) { + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + data = &lxb_css_value_data[type]; + + return cb(data->name, data->length, ctx); +} + +lxb_status_t +lxb_css_value_percentage_sr(const lxb_css_value_percentage_t *percent, + lexbor_serialize_cb_f cb, void *ctx) +{ + size_t length; + lxb_char_t buf[128]; + lxb_status_t status; + + static const lexbor_str_t str_per = lexbor_str("%"); + + /* FIXME: If length != sizeof(buf)? */ + length = lexbor_conv_float_to_data(percent->num, buf, sizeof(buf)); + + lexbor_serialize_write(cb, buf, length, ctx, status); + lexbor_serialize_write(cb, str_per.data, str_per.length, ctx, status); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_length_sr(const lxb_css_value_length_t *len, + lexbor_serialize_cb_f cb, void *ctx) +{ + size_t length; + lxb_char_t buf[128]; + lxb_status_t status; + const lxb_css_data_t *unit; + + /* FIXME: If length != sizeof(buf)? */ + length = lexbor_conv_float_to_data(len->num, buf, sizeof(buf)); + + lexbor_serialize_write(cb, buf, length, ctx, status); + + if (len->unit == LXB_CSS_UNIT__UNDEF) { + return LXB_STATUS_OK; + } + + unit = lxb_css_unit_by_id(len->unit); + if (unit == NULL) { + return LXB_STATUS_OK; + } + + lexbor_serialize_write(cb, unit->name, unit->length, ctx, status); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_number_sr(const lxb_css_value_number_t *number, + lexbor_serialize_cb_f cb, void *ctx) +{ + size_t length; + lxb_char_t buf[128]; + lxb_status_t status; + + /* FIXME: If length != sizeof(buf)? */ + length = lexbor_conv_float_to_data(number->num, buf, sizeof(buf)); + + lexbor_serialize_write(cb, buf, length, ctx, status); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_integer_sr(const lxb_css_value_integer_t *integer, + lexbor_serialize_cb_f cb, void *ctx) +{ + size_t length; + lxb_char_t buf[128]; + lxb_status_t status; + + /* FIXME: If length != sizeof(buf)? */ + length = lexbor_conv_long_to_data(integer->num, buf, sizeof(buf)); + + lexbor_serialize_write(cb, buf, length, ctx, status); + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_length_percentage_sr(const lxb_css_value_length_percentage_t *lp, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (lp->type) { + case LXB_CSS_VALUE__LENGTH: + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_length_sr(&lp->u.length, cb, ctx); + + case LXB_CSS_VALUE__PERCENTAGE: + return lxb_css_value_percentage_sr(&lp->u.percentage, cb, ctx); + + case LXB_CSS_VALUE__UNDEF: + /* FIXME: ???? */ + break; + + default: + return lxb_css_value_serialize(lp->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_number_length_sr(const lxb_css_value_number_length_t *nl, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (nl->type) { + case LXB_CSS_VALUE__LENGTH: + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_length_sr(&nl->u.length, cb, ctx); + + default: + return lxb_css_value_serialize(nl->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_number_percentage_sr(const lxb_css_value_number_percentage_t *np, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (np->type) { + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_number_sr(&np->u.number, cb, ctx); + + case LXB_CSS_VALUE__PERCENTAGE: + return lxb_css_value_percentage_sr(&np->u.percentage, cb, ctx); + + case LXB_CSS_VALUE__UNDEF: + /* FIXME: ???? */ + break; + + default: + return lxb_css_value_serialize(np->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_length_type_sr(const lxb_css_value_length_type_t *lt, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (lt->type) { + case LXB_CSS_VALUE__LENGTH: + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_length_sr(<->length, cb, ctx); + + case LXB_CSS_VALUE__UNDEF: + /* FIXME: ???? */ + break; + + default: + return lxb_css_value_serialize(lt->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_percentage_type_sr(const lxb_css_value_percentage_type_t *pt, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (pt->type) { + case LXB_CSS_VALUE__PERCENTAGE: + return lxb_css_value_percentage_sr(&pt->percentage, cb, ctx); + + case LXB_CSS_VALUE__UNDEF: + /* FIXME: ???? */ + break; + + default: + return lxb_css_value_serialize(pt->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_number_type_sr(const lxb_css_value_number_type_t *num, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (num->type) { + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_number_sr(&num->number, cb, ctx); + + default: + return lxb_css_value_serialize(num->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_integer_type_sr(const lxb_css_value_integer_type_t *num, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (num->type) { + case LXB_CSS_VALUE__INTEGER: + return lxb_css_value_integer_sr(&num->integer, cb, ctx); + + default: + return lxb_css_value_serialize(num->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_length_percentage_type_sr(const lxb_css_value_length_percentage_type_t *lpt, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (lpt->type) { + case LXB_CSS_VALUE__LENGTH: + return lxb_css_value_length_percentage_sr(&lpt->length, cb, ctx); + + default: + return lxb_css_value_serialize(lpt->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_number_length_percentage_type_sr(const lxb_css_value_number_length_percentage_t *nlp, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (nlp->type) { + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_number_sr(&nlp->u.number, cb, ctx); + + case LXB_CSS_VALUE__LENGTH: + return lxb_css_value_length_sr(&nlp->u.length, cb, ctx); + + case LXB_CSS_VALUE__PERCENTAGE: + return lxb_css_value_percentage_sr(&nlp->u.percentage, cb, ctx); + + default: + return lxb_css_value_serialize(nlp->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +lxb_status_t +lxb_css_value_angle_sr(const lxb_css_value_angle_t *angle, + lexbor_serialize_cb_f cb, void *ctx) +{ + size_t length; + lxb_char_t buf[128]; + lxb_status_t status; + const lxb_css_data_t *data; + + /* FIXME: If length != sizeof(buf)? */ + length = lexbor_conv_float_to_data(angle->num, buf, sizeof(buf)); + + lexbor_serialize_write(cb, buf, length, ctx, status); + + data = lxb_css_unit_by_id(angle->unit); + + return cb(data->name, data->length, ctx); +} + +lxb_status_t +lxb_css_value_hue_sr(const lxb_css_value_hue_t *hue, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (hue->type) { + case LXB_CSS_VALUE__NUMBER: + return lxb_css_value_number_sr(&hue->u.number, cb, ctx); + + case LXB_CSS_VALUE__ANGLE: + return lxb_css_value_angle_sr(&hue->u.angle, cb, ctx); + + case LXB_CSS_VALUE__UNDEF: + /* FIXME: ???? */ + break; + + default: + return lxb_css_value_serialize(hue->type, cb, ctx); + } + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_value_color_hex_sr(const lxb_css_value_color_hex_t *hex, + lexbor_serialize_cb_f cb, void *ctx) +{ + lxb_status_t status; + static const lexbor_str_t str_hash = lexbor_str("#"); + const lxb_css_value_color_hex_rgba_t *rgba = &hex->rgba; + + const lxb_char_t *hmo = lexbor_str_res_map_hex_to_char_lowercase; + const char **hmt = lexbor_str_res_char_to_two_hex_value_lowercase; + + lexbor_serialize_write(cb, str_hash.data, str_hash.length, ctx, status); + + switch (hex->type) { + case LXB_CSS_PROPERTY_COLOR_HEX_TYPE_3: + case LXB_CSS_PROPERTY_COLOR_HEX_TYPE_4: + lexbor_serialize_write(cb, &hmo[rgba->r], 1, ctx, status); + lexbor_serialize_write(cb, &hmo[rgba->g], 1, ctx, status); + lexbor_serialize_write(cb, &hmo[rgba->b], 1, ctx, status); + + if (hex->type == LXB_CSS_PROPERTY_COLOR_HEX_TYPE_4) { + lexbor_serialize_write(cb, &hmo[rgba->a], 1, ctx, status); + } + + break; + + case LXB_CSS_PROPERTY_COLOR_HEX_TYPE_6: + case LXB_CSS_PROPERTY_COLOR_HEX_TYPE_8: + lexbor_serialize_write(cb, hmt[rgba->r], 2, ctx, status); + lexbor_serialize_write(cb, hmt[rgba->g], 2, ctx, status); + lexbor_serialize_write(cb, hmt[rgba->b], 2, ctx, status); + + if (hex->type == LXB_CSS_PROPERTY_COLOR_HEX_TYPE_8) { + lexbor_serialize_write(cb, hmt[rgba->a], 2, ctx, status); + } + + break; + + default: + break; + } + + return LXB_STATUS_OK; +} + +static lxb_status_t +lxb_css_value_color_rgb_sr(const lxb_css_value_color_rgba_t *rgb, + lexbor_serialize_cb_f cb, void *ctx, + lxb_css_value_type_t type) +{ + lxb_status_t status; + const lexbor_str_t *sep; + static const lexbor_str_t str_rgb = lexbor_str("rgb("); + static const lexbor_str_t str_rgba = lexbor_str("rgba("); + + if (type == LXB_CSS_COLOR_RGB) { + lexbor_serialize_write(cb, str_rgb.data, str_rgb.length, ctx, status); + } + else { + lexbor_serialize_write(cb, str_rgba.data, str_rgba.length, ctx, status); + } + + sep = (rgb->old) ? &lxb_str_comma : &lxb_css_value_str_ws; + + status = lxb_css_value_number_percentage_sr(&rgb->r, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, sep->data, sep->length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&rgb->g, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, sep->data, sep->length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&rgb->b, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (rgb->a.type == LXB_CSS_VALUE__UNDEF) { + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); + } + + sep = (rgb->old) ? &lxb_str_comma : &lxb_str_alpha; + + lexbor_serialize_write(cb, sep->data, sep->length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&rgb->a, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); +} + +static lxb_status_t +lxb_css_value_color_hsl_sr(const lxb_css_value_color_hsla_t *hsl, + lexbor_serialize_cb_f cb, void *ctx, + lxb_css_value_type_t type) +{ + lxb_status_t status; + const lexbor_str_t *sep; + static const lexbor_str_t str_hsl = lexbor_str("hsl("); + static const lexbor_str_t str_hsla = lexbor_str("hsla("); + static const lexbor_str_t str_hwb = lexbor_str("hwb("); + + switch (type) { + case LXB_CSS_COLOR_HSL: + status = cb(str_hsl.data, str_hsl.length, ctx); + break; + + case LXB_CSS_COLOR_HSLA: + status = cb(str_hsla.data, str_hsla.length, ctx); + break; + + case LXB_CSS_COLOR_HWB: + status = cb(str_hwb.data, str_hwb.length, ctx); + break; + + default: + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + if (status != LXB_STATUS_OK) { + return status; + } + + sep = (hsl->old) ? &lxb_str_comma : &lxb_css_value_str_ws; + + status = lxb_css_value_hue_sr(&hsl->h, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, sep->data, sep->length, ctx, status); + + status = lxb_css_value_percentage_type_sr(&hsl->s, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, sep->data, sep->length, ctx, status); + + status = lxb_css_value_percentage_type_sr(&hsl->l, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (hsl->a.type == LXB_CSS_VALUE__UNDEF) { + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); + } + + sep = (hsl->old) ? &lxb_str_comma : &lxb_str_alpha; + + lexbor_serialize_write(cb, sep->data, sep->length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&hsl->a, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); +} + +static lxb_status_t +lxb_css_value_color_lab_sr(const lxb_css_value_color_lab_t *lab, + lexbor_serialize_cb_f cb, void *ctx, + lxb_css_value_type_t type) +{ + lxb_status_t status; + static const lexbor_str_t str_lab = lexbor_str("lab("); + static const lexbor_str_t str_oklab = lexbor_str("oklab("); + + switch (type) { + case LXB_CSS_COLOR_LAB: + status = cb(str_lab.data, str_lab.length, ctx); + break; + + case LXB_CSS_COLOR_OKLAB: + status = cb(str_oklab.data, str_oklab.length, ctx); + break; + + default: + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + if (status != LXB_STATUS_OK) { + return status; + } + + status = lxb_css_value_number_percentage_sr(&lab->l, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, lxb_css_value_str_ws.data, + lxb_css_value_str_ws.length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&lab->a, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, lxb_css_value_str_ws.data, + lxb_css_value_str_ws.length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&lab->b, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (lab->alpha.type == LXB_CSS_VALUE__UNDEF) { + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); + } + + lexbor_serialize_write(cb, lxb_str_alpha.data, lxb_str_alpha.length, + ctx, status); + + status = lxb_css_value_number_percentage_sr(&lab->alpha, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); +} + +static lxb_status_t +lxb_css_value_color_lch_sr(const lxb_css_value_color_lch_t *lch, + lexbor_serialize_cb_f cb, void *ctx, + lxb_css_value_type_t type) +{ + lxb_status_t status; + static const lexbor_str_t str_lch = lexbor_str("lch("); + static const lexbor_str_t str_oklch = lexbor_str("oklch("); + + switch (type) { + case LXB_CSS_COLOR_LCH: + status = cb(str_lch.data, str_lch.length, ctx); + break; + + case LXB_CSS_COLOR_OKLCH: + status = cb(str_oklch.data, str_oklch.length, ctx); + break; + + default: + return LXB_STATUS_ERROR_WRONG_ARGS; + } + + if (status != LXB_STATUS_OK) { + return status; + } + + status = lxb_css_value_number_percentage_sr(&lch->l, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, lxb_css_value_str_ws.data, + lxb_css_value_str_ws.length, ctx, status); + + status = lxb_css_value_number_percentage_sr(&lch->c, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + lexbor_serialize_write(cb, lxb_css_value_str_ws.data, + lxb_css_value_str_ws.length, ctx, status); + + status = lxb_css_value_hue_sr(&lch->h, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + if (lch->a.type == LXB_CSS_VALUE__UNDEF) { + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); + } + + lexbor_serialize_write(cb, lxb_str_alpha.data, lxb_str_alpha.length, + ctx, status); + + status = lxb_css_value_number_percentage_sr(&lch->a, cb, ctx); + if (status != LXB_STATUS_OK) { + return status; + } + + return cb(lxb_str_rp.data, lxb_str_rp.length, ctx); +} + +lxb_status_t +lxb_css_value_color_serialize(const lxb_css_value_color_t *color, + lexbor_serialize_cb_f cb, void *ctx) +{ + switch (color->type) { + case LXB_CSS_COLOR_HEX: + return lxb_css_value_color_hex_sr(&color->u.hex, cb, ctx); + + case LXB_CSS_COLOR_RGB: + case LXB_CSS_COLOR_RGBA: + return lxb_css_value_color_rgb_sr(&color->u.rgb, cb, ctx, + color->type); + + case LXB_CSS_COLOR_HSL: + case LXB_CSS_COLOR_HSLA: + case LXB_CSS_COLOR_HWB: + return lxb_css_value_color_hsl_sr(&color->u.hsl, cb, ctx, + color->type); + + case LXB_CSS_COLOR_LAB: + case LXB_CSS_COLOR_OKLAB: + return lxb_css_value_color_lab_sr(&color->u.lab, cb, ctx, + color->type); + + case LXB_CSS_COLOR_LCH: + case LXB_CSS_COLOR_OKLCH: + return lxb_css_value_color_lch_sr(&color->u.lch, cb, ctx, + color->type); + + case LXB_CSS_VALUE__UNDEF: + break; + + default: + return lxb_css_value_serialize(color->type, cb, ctx); + } + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value.h new file mode 100644 index 0000000..eb26aa8 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value.h @@ -0,0 +1,290 @@ +/* + * Copyright (C) 2022-2023 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#ifndef LXB_CSS_VALUE_H +#define LXB_CSS_VALUE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "lexbor/css/base.h" +#include "lexbor/css/value/const.h" +#include "lexbor/css/unit/const.h" + +typedef struct { + double num; + bool is_float; +} +lxb_css_value_number_t; + +typedef struct { + long num; +} +lxb_css_value_integer_t; + +typedef lxb_css_value_number_t lxb_css_value_percentage_t; + +typedef struct { + double num; + bool is_float; + lxb_css_unit_t unit; +} +lxb_css_value_length_t; + +typedef struct { + lxb_css_value_type_t type; + + union { + lxb_css_value_length_t length; + lxb_css_value_percentage_t percentage; + } u; +} +lxb_css_value_length_percentage_t; + +typedef struct { + lxb_css_value_type_t type; + + union { + lxb_css_value_number_t number; + lxb_css_value_length_t length; + lxb_css_value_percentage_t percentage; + } u; +} +lxb_css_value_number_length_percentage_t; + +typedef struct { + lxb_css_value_type_t type; + + union { + lxb_css_value_number_t number; + lxb_css_value_length_t length; + } u; +} +lxb_css_value_number_length_t; + +typedef struct { + lxb_css_value_type_t type; + + union { + lxb_css_value_number_t number; + lxb_css_value_percentage_t percentage; + } u; +} +lxb_css_value_number_percentage_t; + +typedef struct { + lxb_css_value_type_t type; + lxb_css_value_number_t number; +} +lxb_css_value_number_type_t; + +typedef struct { + lxb_css_value_type_t type; + lxb_css_value_integer_t integer; +} +lxb_css_value_integer_type_t; + +typedef struct { + lxb_css_value_type_t type; + lxb_css_value_percentage_t percentage; +} +lxb_css_value_percentage_type_t; + +typedef struct { + lxb_css_value_type_t type; + lxb_css_value_length_t length; +} +lxb_css_value_length_type_t; + +typedef struct { + lxb_css_value_type_t type; + lxb_css_value_length_percentage_t length; +} +lxb_css_value_length_percentage_type_t; + +typedef struct { + double num; + bool is_float; + lxb_css_unit_angle_t unit; +} +lxb_css_value_angle_t; + +typedef struct { + lxb_css_value_type_t type; + lxb_css_value_angle_t angle; +} +lxb_css_value_angle_type_t; + +typedef struct { + lxb_css_value_type_t type; + + union { + lxb_css_value_number_t number; + lxb_css_value_angle_t angle; + } u; +} +lxb_css_value_hue_t; + +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} +lxb_css_value_color_hex_rgba_t; + +typedef enum { + LXB_CSS_PROPERTY_COLOR_HEX_TYPE_3 = 0x00, + LXB_CSS_PROPERTY_COLOR_HEX_TYPE_4, + LXB_CSS_PROPERTY_COLOR_HEX_TYPE_6, + LXB_CSS_PROPERTY_COLOR_HEX_TYPE_8 +} +lxb_css_value_color_hex_type_t; + +typedef struct { + lxb_css_value_color_hex_rgba_t rgba; + lxb_css_value_color_hex_type_t type; +} +lxb_css_value_color_hex_t; + +typedef struct { + /* + * If R is when G and B should be to. + * If R is when G and B should be to. + * R, G, B can be NONE regardless of neighboring values. + * 'A' can be or or NONE. + */ + + lxb_css_value_number_percentage_t r; + lxb_css_value_number_percentage_t g; + lxb_css_value_number_percentage_t b; + lxb_css_value_number_percentage_t a; + + bool old; +} +lxb_css_value_color_rgba_t; + +typedef struct { + lxb_css_value_hue_t h; + lxb_css_value_percentage_type_t s; + lxb_css_value_percentage_type_t l; + lxb_css_value_number_percentage_t a; + + bool old; +} +lxb_css_value_color_hsla_t; + +typedef struct { + lxb_css_value_number_percentage_t l; + lxb_css_value_number_percentage_t a; + lxb_css_value_number_percentage_t b; + lxb_css_value_number_percentage_t alpha; +} +lxb_css_value_color_lab_t; + +typedef struct { + lxb_css_value_number_percentage_t l; + lxb_css_value_number_percentage_t c; + lxb_css_value_hue_t h; + lxb_css_value_number_percentage_t a; +} +lxb_css_value_color_lch_t; + +typedef struct { + lxb_css_value_type_t type; + + union { + lxb_css_value_color_hex_t hex; + lxb_css_value_color_rgba_t rgb; + lxb_css_value_color_hsla_t hsl; + lxb_css_value_color_hsla_t hwb; + lxb_css_value_color_lab_t lab; + lxb_css_value_color_lch_t lch; + } u; +} +lxb_css_value_color_t; + + +LXB_API const lxb_css_data_t * +lxb_css_value_by_id(uintptr_t id); + +LXB_API lxb_css_value_type_t +lxb_css_value_by_name(const lxb_char_t *name, size_t length); + +LXB_API lxb_status_t +lxb_css_value_serialize(lxb_css_value_type_t type, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_percentage_sr(const lxb_css_value_percentage_t *percent, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_length_sr(const lxb_css_value_length_t *len, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_number_sr(const lxb_css_value_number_t *number, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_integer_sr(const lxb_css_value_integer_t *integer, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_length_percentage_sr(const lxb_css_value_length_percentage_t *lp, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_number_length_sr(const lxb_css_value_number_length_t *nl, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_number_percentage_sr(const lxb_css_value_number_percentage_t *np, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_length_type_sr(const lxb_css_value_length_type_t *lt, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_percentage_type_sr(const lxb_css_value_percentage_type_t *pt, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_number_type_sr(const lxb_css_value_number_type_t *num, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_integer_type_sr(const lxb_css_value_integer_type_t *num, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_length_percentage_type_sr(const lxb_css_value_length_percentage_type_t *lpt, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_number_length_percentage_type_sr(const lxb_css_value_number_length_percentage_t *nlp, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_angle_sr(const lxb_css_value_angle_t *angle, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_hue_sr(const lxb_css_value_hue_t *hue, + lexbor_serialize_cb_f cb, void *ctx); + +LXB_API lxb_status_t +lxb_css_value_color_serialize(const lxb_css_value_color_t *color, + lexbor_serialize_cb_f cb, void *ctx); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LXB_CSS_VALUE_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value/const.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value/const.h new file mode 100644 index 0000000..a7bd64c --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value/const.h @@ -0,0 +1,397 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_VALUE_CONST_H +#define LXB_CSS_VALUE_CONST_H + + +enum { + LXB_CSS_VALUE__UNDEF = 0x0000, + LXB_CSS_VALUE_INITIAL = 0x0001, + LXB_CSS_VALUE_INHERIT = 0x0002, + LXB_CSS_VALUE_UNSET = 0x0003, + LXB_CSS_VALUE_REVERT = 0x0004, + LXB_CSS_VALUE_FLEX_START = 0x0005, + LXB_CSS_VALUE_FLEX_END = 0x0006, + LXB_CSS_VALUE_CENTER = 0x0007, + LXB_CSS_VALUE_SPACE_BETWEEN = 0x0008, + LXB_CSS_VALUE_SPACE_AROUND = 0x0009, + LXB_CSS_VALUE_STRETCH = 0x000a, + LXB_CSS_VALUE_BASELINE = 0x000b, + LXB_CSS_VALUE_AUTO = 0x000c, + LXB_CSS_VALUE_TEXT_BOTTOM = 0x000d, + LXB_CSS_VALUE_ALPHABETIC = 0x000e, + LXB_CSS_VALUE_IDEOGRAPHIC = 0x000f, + LXB_CSS_VALUE_MIDDLE = 0x0010, + LXB_CSS_VALUE_CENTRAL = 0x0011, + LXB_CSS_VALUE_MATHEMATICAL = 0x0012, + LXB_CSS_VALUE_TEXT_TOP = 0x0013, + LXB_CSS_VALUE__LENGTH = 0x0014, + LXB_CSS_VALUE__PERCENTAGE = 0x0015, + LXB_CSS_VALUE_SUB = 0x0016, + LXB_CSS_VALUE_SUPER = 0x0017, + LXB_CSS_VALUE_TOP = 0x0018, + LXB_CSS_VALUE_BOTTOM = 0x0019, + LXB_CSS_VALUE_FIRST = 0x001a, + LXB_CSS_VALUE_LAST = 0x001b, + LXB_CSS_VALUE_THIN = 0x001c, + LXB_CSS_VALUE_MEDIUM = 0x001d, + LXB_CSS_VALUE_THICK = 0x001e, + LXB_CSS_VALUE_NONE = 0x001f, + LXB_CSS_VALUE_HIDDEN = 0x0020, + LXB_CSS_VALUE_DOTTED = 0x0021, + LXB_CSS_VALUE_DASHED = 0x0022, + LXB_CSS_VALUE_SOLID = 0x0023, + LXB_CSS_VALUE_DOUBLE = 0x0024, + LXB_CSS_VALUE_GROOVE = 0x0025, + LXB_CSS_VALUE_RIDGE = 0x0026, + LXB_CSS_VALUE_INSET = 0x0027, + LXB_CSS_VALUE_OUTSET = 0x0028, + LXB_CSS_VALUE_CONTENT_BOX = 0x0029, + LXB_CSS_VALUE_BORDER_BOX = 0x002a, + LXB_CSS_VALUE_INLINE_START = 0x002b, + LXB_CSS_VALUE_INLINE_END = 0x002c, + LXB_CSS_VALUE_BLOCK_START = 0x002d, + LXB_CSS_VALUE_BLOCK_END = 0x002e, + LXB_CSS_VALUE_LEFT = 0x002f, + LXB_CSS_VALUE_RIGHT = 0x0030, + LXB_CSS_VALUE_CURRENTCOLOR = 0x0031, + LXB_CSS_VALUE_TRANSPARENT = 0x0032, + LXB_CSS_VALUE_HEX = 0x0033, + LXB_CSS_VALUE_ALICEBLUE = 0x0034, + LXB_CSS_VALUE_ANTIQUEWHITE = 0x0035, + LXB_CSS_VALUE_AQUA = 0x0036, + LXB_CSS_VALUE_AQUAMARINE = 0x0037, + LXB_CSS_VALUE_AZURE = 0x0038, + LXB_CSS_VALUE_BEIGE = 0x0039, + LXB_CSS_VALUE_BISQUE = 0x003a, + LXB_CSS_VALUE_BLACK = 0x003b, + LXB_CSS_VALUE_BLANCHEDALMOND = 0x003c, + LXB_CSS_VALUE_BLUE = 0x003d, + LXB_CSS_VALUE_BLUEVIOLET = 0x003e, + LXB_CSS_VALUE_BROWN = 0x003f, + LXB_CSS_VALUE_BURLYWOOD = 0x0040, + LXB_CSS_VALUE_CADETBLUE = 0x0041, + LXB_CSS_VALUE_CHARTREUSE = 0x0042, + LXB_CSS_VALUE_CHOCOLATE = 0x0043, + LXB_CSS_VALUE_CORAL = 0x0044, + LXB_CSS_VALUE_CORNFLOWERBLUE = 0x0045, + LXB_CSS_VALUE_CORNSILK = 0x0046, + LXB_CSS_VALUE_CRIMSON = 0x0047, + LXB_CSS_VALUE_CYAN = 0x0048, + LXB_CSS_VALUE_DARKBLUE = 0x0049, + LXB_CSS_VALUE_DARKCYAN = 0x004a, + LXB_CSS_VALUE_DARKGOLDENROD = 0x004b, + LXB_CSS_VALUE_DARKGRAY = 0x004c, + LXB_CSS_VALUE_DARKGREEN = 0x004d, + LXB_CSS_VALUE_DARKGREY = 0x004e, + LXB_CSS_VALUE_DARKKHAKI = 0x004f, + LXB_CSS_VALUE_DARKMAGENTA = 0x0050, + LXB_CSS_VALUE_DARKOLIVEGREEN = 0x0051, + LXB_CSS_VALUE_DARKORANGE = 0x0052, + LXB_CSS_VALUE_DARKORCHID = 0x0053, + LXB_CSS_VALUE_DARKRED = 0x0054, + LXB_CSS_VALUE_DARKSALMON = 0x0055, + LXB_CSS_VALUE_DARKSEAGREEN = 0x0056, + LXB_CSS_VALUE_DARKSLATEBLUE = 0x0057, + LXB_CSS_VALUE_DARKSLATEGRAY = 0x0058, + LXB_CSS_VALUE_DARKSLATEGREY = 0x0059, + LXB_CSS_VALUE_DARKTURQUOISE = 0x005a, + LXB_CSS_VALUE_DARKVIOLET = 0x005b, + LXB_CSS_VALUE_DEEPPINK = 0x005c, + LXB_CSS_VALUE_DEEPSKYBLUE = 0x005d, + LXB_CSS_VALUE_DIMGRAY = 0x005e, + LXB_CSS_VALUE_DIMGREY = 0x005f, + LXB_CSS_VALUE_DODGERBLUE = 0x0060, + LXB_CSS_VALUE_FIREBRICK = 0x0061, + LXB_CSS_VALUE_FLORALWHITE = 0x0062, + LXB_CSS_VALUE_FORESTGREEN = 0x0063, + LXB_CSS_VALUE_FUCHSIA = 0x0064, + LXB_CSS_VALUE_GAINSBORO = 0x0065, + LXB_CSS_VALUE_GHOSTWHITE = 0x0066, + LXB_CSS_VALUE_GOLD = 0x0067, + LXB_CSS_VALUE_GOLDENROD = 0x0068, + LXB_CSS_VALUE_GRAY = 0x0069, + LXB_CSS_VALUE_GREEN = 0x006a, + LXB_CSS_VALUE_GREENYELLOW = 0x006b, + LXB_CSS_VALUE_GREY = 0x006c, + LXB_CSS_VALUE_HONEYDEW = 0x006d, + LXB_CSS_VALUE_HOTPINK = 0x006e, + LXB_CSS_VALUE_INDIANRED = 0x006f, + LXB_CSS_VALUE_INDIGO = 0x0070, + LXB_CSS_VALUE_IVORY = 0x0071, + LXB_CSS_VALUE_KHAKI = 0x0072, + LXB_CSS_VALUE_LAVENDER = 0x0073, + LXB_CSS_VALUE_LAVENDERBLUSH = 0x0074, + LXB_CSS_VALUE_LAWNGREEN = 0x0075, + LXB_CSS_VALUE_LEMONCHIFFON = 0x0076, + LXB_CSS_VALUE_LIGHTBLUE = 0x0077, + LXB_CSS_VALUE_LIGHTCORAL = 0x0078, + LXB_CSS_VALUE_LIGHTCYAN = 0x0079, + LXB_CSS_VALUE_LIGHTGOLDENRODYELLOW = 0x007a, + LXB_CSS_VALUE_LIGHTGRAY = 0x007b, + LXB_CSS_VALUE_LIGHTGREEN = 0x007c, + LXB_CSS_VALUE_LIGHTGREY = 0x007d, + LXB_CSS_VALUE_LIGHTPINK = 0x007e, + LXB_CSS_VALUE_LIGHTSALMON = 0x007f, + LXB_CSS_VALUE_LIGHTSEAGREEN = 0x0080, + LXB_CSS_VALUE_LIGHTSKYBLUE = 0x0081, + LXB_CSS_VALUE_LIGHTSLATEGRAY = 0x0082, + LXB_CSS_VALUE_LIGHTSLATEGREY = 0x0083, + LXB_CSS_VALUE_LIGHTSTEELBLUE = 0x0084, + LXB_CSS_VALUE_LIGHTYELLOW = 0x0085, + LXB_CSS_VALUE_LIME = 0x0086, + LXB_CSS_VALUE_LIMEGREEN = 0x0087, + LXB_CSS_VALUE_LINEN = 0x0088, + LXB_CSS_VALUE_MAGENTA = 0x0089, + LXB_CSS_VALUE_MAROON = 0x008a, + LXB_CSS_VALUE_MEDIUMAQUAMARINE = 0x008b, + LXB_CSS_VALUE_MEDIUMBLUE = 0x008c, + LXB_CSS_VALUE_MEDIUMORCHID = 0x008d, + LXB_CSS_VALUE_MEDIUMPURPLE = 0x008e, + LXB_CSS_VALUE_MEDIUMSEAGREEN = 0x008f, + LXB_CSS_VALUE_MEDIUMSLATEBLUE = 0x0090, + LXB_CSS_VALUE_MEDIUMSPRINGGREEN = 0x0091, + LXB_CSS_VALUE_MEDIUMTURQUOISE = 0x0092, + LXB_CSS_VALUE_MEDIUMVIOLETRED = 0x0093, + LXB_CSS_VALUE_MIDNIGHTBLUE = 0x0094, + LXB_CSS_VALUE_MINTCREAM = 0x0095, + LXB_CSS_VALUE_MISTYROSE = 0x0096, + LXB_CSS_VALUE_MOCCASIN = 0x0097, + LXB_CSS_VALUE_NAVAJOWHITE = 0x0098, + LXB_CSS_VALUE_NAVY = 0x0099, + LXB_CSS_VALUE_OLDLACE = 0x009a, + LXB_CSS_VALUE_OLIVE = 0x009b, + LXB_CSS_VALUE_OLIVEDRAB = 0x009c, + LXB_CSS_VALUE_ORANGE = 0x009d, + LXB_CSS_VALUE_ORANGERED = 0x009e, + LXB_CSS_VALUE_ORCHID = 0x009f, + LXB_CSS_VALUE_PALEGOLDENROD = 0x00a0, + LXB_CSS_VALUE_PALEGREEN = 0x00a1, + LXB_CSS_VALUE_PALETURQUOISE = 0x00a2, + LXB_CSS_VALUE_PALEVIOLETRED = 0x00a3, + LXB_CSS_VALUE_PAPAYAWHIP = 0x00a4, + LXB_CSS_VALUE_PEACHPUFF = 0x00a5, + LXB_CSS_VALUE_PERU = 0x00a6, + LXB_CSS_VALUE_PINK = 0x00a7, + LXB_CSS_VALUE_PLUM = 0x00a8, + LXB_CSS_VALUE_POWDERBLUE = 0x00a9, + LXB_CSS_VALUE_PURPLE = 0x00aa, + LXB_CSS_VALUE_REBECCAPURPLE = 0x00ab, + LXB_CSS_VALUE_RED = 0x00ac, + LXB_CSS_VALUE_ROSYBROWN = 0x00ad, + LXB_CSS_VALUE_ROYALBLUE = 0x00ae, + LXB_CSS_VALUE_SADDLEBROWN = 0x00af, + LXB_CSS_VALUE_SALMON = 0x00b0, + LXB_CSS_VALUE_SANDYBROWN = 0x00b1, + LXB_CSS_VALUE_SEAGREEN = 0x00b2, + LXB_CSS_VALUE_SEASHELL = 0x00b3, + LXB_CSS_VALUE_SIENNA = 0x00b4, + LXB_CSS_VALUE_SILVER = 0x00b5, + LXB_CSS_VALUE_SKYBLUE = 0x00b6, + LXB_CSS_VALUE_SLATEBLUE = 0x00b7, + LXB_CSS_VALUE_SLATEGRAY = 0x00b8, + LXB_CSS_VALUE_SLATEGREY = 0x00b9, + LXB_CSS_VALUE_SNOW = 0x00ba, + LXB_CSS_VALUE_SPRINGGREEN = 0x00bb, + LXB_CSS_VALUE_STEELBLUE = 0x00bc, + LXB_CSS_VALUE_TAN = 0x00bd, + LXB_CSS_VALUE_TEAL = 0x00be, + LXB_CSS_VALUE_THISTLE = 0x00bf, + LXB_CSS_VALUE_TOMATO = 0x00c0, + LXB_CSS_VALUE_TURQUOISE = 0x00c1, + LXB_CSS_VALUE_VIOLET = 0x00c2, + LXB_CSS_VALUE_WHEAT = 0x00c3, + LXB_CSS_VALUE_WHITE = 0x00c4, + LXB_CSS_VALUE_WHITESMOKE = 0x00c5, + LXB_CSS_VALUE_YELLOW = 0x00c6, + LXB_CSS_VALUE_YELLOWGREEN = 0x00c7, + LXB_CSS_VALUE_CANVAS = 0x00c8, + LXB_CSS_VALUE_CANVASTEXT = 0x00c9, + LXB_CSS_VALUE_LINKTEXT = 0x00ca, + LXB_CSS_VALUE_VISITEDTEXT = 0x00cb, + LXB_CSS_VALUE_ACTIVETEXT = 0x00cc, + LXB_CSS_VALUE_BUTTONFACE = 0x00cd, + LXB_CSS_VALUE_BUTTONTEXT = 0x00ce, + LXB_CSS_VALUE_BUTTONBORDER = 0x00cf, + LXB_CSS_VALUE_FIELD = 0x00d0, + LXB_CSS_VALUE_FIELDTEXT = 0x00d1, + LXB_CSS_VALUE_HIGHLIGHT = 0x00d2, + LXB_CSS_VALUE_HIGHLIGHTTEXT = 0x00d3, + LXB_CSS_VALUE_SELECTEDITEM = 0x00d4, + LXB_CSS_VALUE_SELECTEDITEMTEXT = 0x00d5, + LXB_CSS_VALUE_MARK = 0x00d6, + LXB_CSS_VALUE_MARKTEXT = 0x00d7, + LXB_CSS_VALUE_GRAYTEXT = 0x00d8, + LXB_CSS_VALUE_ACCENTCOLOR = 0x00d9, + LXB_CSS_VALUE_ACCENTCOLORTEXT = 0x00da, + LXB_CSS_VALUE_RGB = 0x00db, + LXB_CSS_VALUE_RGBA = 0x00dc, + LXB_CSS_VALUE_HSL = 0x00dd, + LXB_CSS_VALUE_HSLA = 0x00de, + LXB_CSS_VALUE_HWB = 0x00df, + LXB_CSS_VALUE_LAB = 0x00e0, + LXB_CSS_VALUE_LCH = 0x00e1, + LXB_CSS_VALUE_OKLAB = 0x00e2, + LXB_CSS_VALUE_OKLCH = 0x00e3, + LXB_CSS_VALUE_COLOR = 0x00e4, + LXB_CSS_VALUE_LTR = 0x00e5, + LXB_CSS_VALUE_RTL = 0x00e6, + LXB_CSS_VALUE_BLOCK = 0x00e7, + LXB_CSS_VALUE_INLINE = 0x00e8, + LXB_CSS_VALUE_RUN_IN = 0x00e9, + LXB_CSS_VALUE_FLOW = 0x00ea, + LXB_CSS_VALUE_FLOW_ROOT = 0x00eb, + LXB_CSS_VALUE_TABLE = 0x00ec, + LXB_CSS_VALUE_FLEX = 0x00ed, + LXB_CSS_VALUE_GRID = 0x00ee, + LXB_CSS_VALUE_RUBY = 0x00ef, + LXB_CSS_VALUE_LIST_ITEM = 0x00f0, + LXB_CSS_VALUE_TABLE_ROW_GROUP = 0x00f1, + LXB_CSS_VALUE_TABLE_HEADER_GROUP = 0x00f2, + LXB_CSS_VALUE_TABLE_FOOTER_GROUP = 0x00f3, + LXB_CSS_VALUE_TABLE_ROW = 0x00f4, + LXB_CSS_VALUE_TABLE_CELL = 0x00f5, + LXB_CSS_VALUE_TABLE_COLUMN_GROUP = 0x00f6, + LXB_CSS_VALUE_TABLE_COLUMN = 0x00f7, + LXB_CSS_VALUE_TABLE_CAPTION = 0x00f8, + LXB_CSS_VALUE_RUBY_BASE = 0x00f9, + LXB_CSS_VALUE_RUBY_TEXT = 0x00fa, + LXB_CSS_VALUE_RUBY_BASE_CONTAINER = 0x00fb, + LXB_CSS_VALUE_RUBY_TEXT_CONTAINER = 0x00fc, + LXB_CSS_VALUE_CONTENTS = 0x00fd, + LXB_CSS_VALUE_INLINE_BLOCK = 0x00fe, + LXB_CSS_VALUE_INLINE_TABLE = 0x00ff, + LXB_CSS_VALUE_INLINE_FLEX = 0x0100, + LXB_CSS_VALUE_INLINE_GRID = 0x0101, + LXB_CSS_VALUE_HANGING = 0x0102, + LXB_CSS_VALUE_CONTENT = 0x0103, + LXB_CSS_VALUE_ROW = 0x0104, + LXB_CSS_VALUE_ROW_REVERSE = 0x0105, + LXB_CSS_VALUE_COLUMN = 0x0106, + LXB_CSS_VALUE_COLUMN_REVERSE = 0x0107, + LXB_CSS_VALUE__NUMBER = 0x0108, + LXB_CSS_VALUE_NOWRAP = 0x0109, + LXB_CSS_VALUE_WRAP = 0x010a, + LXB_CSS_VALUE_WRAP_REVERSE = 0x010b, + LXB_CSS_VALUE_SNAP_BLOCK = 0x010c, + LXB_CSS_VALUE_START = 0x010d, + LXB_CSS_VALUE_END = 0x010e, + LXB_CSS_VALUE_NEAR = 0x010f, + LXB_CSS_VALUE_SNAP_INLINE = 0x0110, + LXB_CSS_VALUE__INTEGER = 0x0111, + LXB_CSS_VALUE_REGION = 0x0112, + LXB_CSS_VALUE_PAGE = 0x0113, + LXB_CSS_VALUE_SERIF = 0x0114, + LXB_CSS_VALUE_SANS_SERIF = 0x0115, + LXB_CSS_VALUE_CURSIVE = 0x0116, + LXB_CSS_VALUE_FANTASY = 0x0117, + LXB_CSS_VALUE_MONOSPACE = 0x0118, + LXB_CSS_VALUE_SYSTEM_UI = 0x0119, + LXB_CSS_VALUE_EMOJI = 0x011a, + LXB_CSS_VALUE_MATH = 0x011b, + LXB_CSS_VALUE_FANGSONG = 0x011c, + LXB_CSS_VALUE_UI_SERIF = 0x011d, + LXB_CSS_VALUE_UI_SANS_SERIF = 0x011e, + LXB_CSS_VALUE_UI_MONOSPACE = 0x011f, + LXB_CSS_VALUE_UI_ROUNDED = 0x0120, + LXB_CSS_VALUE_XX_SMALL = 0x0121, + LXB_CSS_VALUE_X_SMALL = 0x0122, + LXB_CSS_VALUE_SMALL = 0x0123, + LXB_CSS_VALUE_LARGE = 0x0124, + LXB_CSS_VALUE_X_LARGE = 0x0125, + LXB_CSS_VALUE_XX_LARGE = 0x0126, + LXB_CSS_VALUE_XXX_LARGE = 0x0127, + LXB_CSS_VALUE_LARGER = 0x0128, + LXB_CSS_VALUE_SMALLER = 0x0129, + LXB_CSS_VALUE_NORMAL = 0x012a, + LXB_CSS_VALUE_ULTRA_CONDENSED = 0x012b, + LXB_CSS_VALUE_EXTRA_CONDENSED = 0x012c, + LXB_CSS_VALUE_CONDENSED = 0x012d, + LXB_CSS_VALUE_SEMI_CONDENSED = 0x012e, + LXB_CSS_VALUE_SEMI_EXPANDED = 0x012f, + LXB_CSS_VALUE_EXPANDED = 0x0130, + LXB_CSS_VALUE_EXTRA_EXPANDED = 0x0131, + LXB_CSS_VALUE_ULTRA_EXPANDED = 0x0132, + LXB_CSS_VALUE_ITALIC = 0x0133, + LXB_CSS_VALUE_OBLIQUE = 0x0134, + LXB_CSS_VALUE_BOLD = 0x0135, + LXB_CSS_VALUE_BOLDER = 0x0136, + LXB_CSS_VALUE_LIGHTER = 0x0137, + LXB_CSS_VALUE_FORCE_END = 0x0138, + LXB_CSS_VALUE_ALLOW_END = 0x0139, + LXB_CSS_VALUE_MIN_CONTENT = 0x013a, + LXB_CSS_VALUE_MAX_CONTENT = 0x013b, + LXB_CSS_VALUE__ANGLE = 0x013c, + LXB_CSS_VALUE_MANUAL = 0x013d, + LXB_CSS_VALUE_LOOSE = 0x013e, + LXB_CSS_VALUE_STRICT = 0x013f, + LXB_CSS_VALUE_ANYWHERE = 0x0140, + LXB_CSS_VALUE_VISIBLE = 0x0141, + LXB_CSS_VALUE_CLIP = 0x0142, + LXB_CSS_VALUE_SCROLL = 0x0143, + LXB_CSS_VALUE_BREAK_WORD = 0x0144, + LXB_CSS_VALUE_STATIC = 0x0145, + LXB_CSS_VALUE_RELATIVE = 0x0146, + LXB_CSS_VALUE_ABSOLUTE = 0x0147, + LXB_CSS_VALUE_STICKY = 0x0148, + LXB_CSS_VALUE_FIXED = 0x0149, + LXB_CSS_VALUE_JUSTIFY = 0x014a, + LXB_CSS_VALUE_MATCH_PARENT = 0x014b, + LXB_CSS_VALUE_JUSTIFY_ALL = 0x014c, + LXB_CSS_VALUE_ALL = 0x014d, + LXB_CSS_VALUE_DIGITS = 0x014e, + LXB_CSS_VALUE_UNDERLINE = 0x014f, + LXB_CSS_VALUE_OVERLINE = 0x0150, + LXB_CSS_VALUE_LINE_THROUGH = 0x0151, + LXB_CSS_VALUE_BLINK = 0x0152, + LXB_CSS_VALUE_WAVY = 0x0153, + LXB_CSS_VALUE_EACH_LINE = 0x0154, + LXB_CSS_VALUE_INTER_WORD = 0x0155, + LXB_CSS_VALUE_INTER_CHARACTER = 0x0156, + LXB_CSS_VALUE_MIXED = 0x0157, + LXB_CSS_VALUE_UPRIGHT = 0x0158, + LXB_CSS_VALUE_SIDEWAYS = 0x0159, + LXB_CSS_VALUE_ELLIPSIS = 0x015a, + LXB_CSS_VALUE_CAPITALIZE = 0x015b, + LXB_CSS_VALUE_UPPERCASE = 0x015c, + LXB_CSS_VALUE_LOWERCASE = 0x015d, + LXB_CSS_VALUE_FULL_WIDTH = 0x015e, + LXB_CSS_VALUE_FULL_SIZE_KANA = 0x015f, + LXB_CSS_VALUE_EMBED = 0x0160, + LXB_CSS_VALUE_ISOLATE = 0x0161, + LXB_CSS_VALUE_BIDI_OVERRIDE = 0x0162, + LXB_CSS_VALUE_ISOLATE_OVERRIDE = 0x0163, + LXB_CSS_VALUE_PLAINTEXT = 0x0164, + LXB_CSS_VALUE_COLLAPSE = 0x0165, + LXB_CSS_VALUE_PRE = 0x0166, + LXB_CSS_VALUE_PRE_WRAP = 0x0167, + LXB_CSS_VALUE_BREAK_SPACES = 0x0168, + LXB_CSS_VALUE_PRE_LINE = 0x0169, + LXB_CSS_VALUE_KEEP_ALL = 0x016a, + LXB_CSS_VALUE_BREAK_ALL = 0x016b, + LXB_CSS_VALUE_BOTH = 0x016c, + LXB_CSS_VALUE_MINIMUM = 0x016d, + LXB_CSS_VALUE_MAXIMUM = 0x016e, + LXB_CSS_VALUE_CLEAR = 0x016f, + LXB_CSS_VALUE_HORIZONTAL_TB = 0x0170, + LXB_CSS_VALUE_VERTICAL_RL = 0x0171, + LXB_CSS_VALUE_VERTICAL_LR = 0x0172, + LXB_CSS_VALUE_SIDEWAYS_RL = 0x0173, + LXB_CSS_VALUE_SIDEWAYS_LR = 0x0174, + LXB_CSS_VALUE__LAST_ENTRY = 0x0175 +}; +typedef unsigned int lxb_css_value_type_t; + + +#endif /* LXB_CSS_VALUE_CONST_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value/res.h b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value/res.h new file mode 100644 index 0000000..180dc95 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/css/value/res.h @@ -0,0 +1,775 @@ +/* + * Copyright (C) 2026 Alexander Borisov + * + * Author: Alexander Borisov + */ + +/* + * Caution! + * This file generated by the script "utils/lexbor/css/names.py"! + * Do not change this file! + */ + + +#ifndef LXB_CSS_VALUE_RES_H +#define LXB_CSS_VALUE_RES_H + +#include "lexbor/core/shs.h" +#include "lexbor/css/value/const.h" + +static const lxb_css_data_t lxb_css_value_data[LXB_CSS_VALUE__LAST_ENTRY] = +{ + {(lxb_char_t *) "_undef", 6, LXB_CSS_VALUE__UNDEF}, + {(lxb_char_t *) "initial", 7, LXB_CSS_VALUE_INITIAL}, + {(lxb_char_t *) "inherit", 7, LXB_CSS_VALUE_INHERIT}, + {(lxb_char_t *) "unset", 5, LXB_CSS_VALUE_UNSET}, + {(lxb_char_t *) "revert", 6, LXB_CSS_VALUE_REVERT}, + {(lxb_char_t *) "flex-start", 10, LXB_CSS_VALUE_FLEX_START}, + {(lxb_char_t *) "flex-end", 8, LXB_CSS_VALUE_FLEX_END}, + {(lxb_char_t *) "center", 6, LXB_CSS_VALUE_CENTER}, + {(lxb_char_t *) "space-between", 13, LXB_CSS_VALUE_SPACE_BETWEEN}, + {(lxb_char_t *) "space-around", 12, LXB_CSS_VALUE_SPACE_AROUND}, + {(lxb_char_t *) "stretch", 7, LXB_CSS_VALUE_STRETCH}, + {(lxb_char_t *) "baseline", 8, LXB_CSS_VALUE_BASELINE}, + {(lxb_char_t *) "auto", 4, LXB_CSS_VALUE_AUTO}, + {(lxb_char_t *) "text-bottom", 11, LXB_CSS_VALUE_TEXT_BOTTOM}, + {(lxb_char_t *) "alphabetic", 10, LXB_CSS_VALUE_ALPHABETIC}, + {(lxb_char_t *) "ideographic", 11, LXB_CSS_VALUE_IDEOGRAPHIC}, + {(lxb_char_t *) "middle", 6, LXB_CSS_VALUE_MIDDLE}, + {(lxb_char_t *) "central", 7, LXB_CSS_VALUE_CENTRAL}, + {(lxb_char_t *) "mathematical", 12, LXB_CSS_VALUE_MATHEMATICAL}, + {(lxb_char_t *) "text-top", 8, LXB_CSS_VALUE_TEXT_TOP}, + {(lxb_char_t *) "_length", 7, LXB_CSS_VALUE__LENGTH}, + {(lxb_char_t *) "_percentage", 11, LXB_CSS_VALUE__PERCENTAGE}, + {(lxb_char_t *) "sub", 3, LXB_CSS_VALUE_SUB}, + {(lxb_char_t *) "super", 5, LXB_CSS_VALUE_SUPER}, + {(lxb_char_t *) "top", 3, LXB_CSS_VALUE_TOP}, + {(lxb_char_t *) "bottom", 6, LXB_CSS_VALUE_BOTTOM}, + {(lxb_char_t *) "first", 5, LXB_CSS_VALUE_FIRST}, + {(lxb_char_t *) "last", 4, LXB_CSS_VALUE_LAST}, + {(lxb_char_t *) "thin", 4, LXB_CSS_VALUE_THIN}, + {(lxb_char_t *) "medium", 6, LXB_CSS_VALUE_MEDIUM}, + {(lxb_char_t *) "thick", 5, LXB_CSS_VALUE_THICK}, + {(lxb_char_t *) "none", 4, LXB_CSS_VALUE_NONE}, + {(lxb_char_t *) "hidden", 6, LXB_CSS_VALUE_HIDDEN}, + {(lxb_char_t *) "dotted", 6, LXB_CSS_VALUE_DOTTED}, + {(lxb_char_t *) "dashed", 6, LXB_CSS_VALUE_DASHED}, + {(lxb_char_t *) "solid", 5, LXB_CSS_VALUE_SOLID}, + {(lxb_char_t *) "double", 6, LXB_CSS_VALUE_DOUBLE}, + {(lxb_char_t *) "groove", 6, LXB_CSS_VALUE_GROOVE}, + {(lxb_char_t *) "ridge", 5, LXB_CSS_VALUE_RIDGE}, + {(lxb_char_t *) "inset", 5, LXB_CSS_VALUE_INSET}, + {(lxb_char_t *) "outset", 6, LXB_CSS_VALUE_OUTSET}, + {(lxb_char_t *) "content-box", 11, LXB_CSS_VALUE_CONTENT_BOX}, + {(lxb_char_t *) "border-box", 10, LXB_CSS_VALUE_BORDER_BOX}, + {(lxb_char_t *) "inline-start", 12, LXB_CSS_VALUE_INLINE_START}, + {(lxb_char_t *) "inline-end", 10, LXB_CSS_VALUE_INLINE_END}, + {(lxb_char_t *) "block-start", 11, LXB_CSS_VALUE_BLOCK_START}, + {(lxb_char_t *) "block-end", 9, LXB_CSS_VALUE_BLOCK_END}, + {(lxb_char_t *) "left", 4, LXB_CSS_VALUE_LEFT}, + {(lxb_char_t *) "right", 5, LXB_CSS_VALUE_RIGHT}, + {(lxb_char_t *) "currentcolor", 12, LXB_CSS_VALUE_CURRENTCOLOR}, + {(lxb_char_t *) "transparent", 11, LXB_CSS_VALUE_TRANSPARENT}, + {(lxb_char_t *) "hex", 3, LXB_CSS_VALUE_HEX}, + {(lxb_char_t *) "aliceblue", 9, LXB_CSS_VALUE_ALICEBLUE}, + {(lxb_char_t *) "antiquewhite", 12, LXB_CSS_VALUE_ANTIQUEWHITE}, + {(lxb_char_t *) "aqua", 4, LXB_CSS_VALUE_AQUA}, + {(lxb_char_t *) "aquamarine", 10, LXB_CSS_VALUE_AQUAMARINE}, + {(lxb_char_t *) "azure", 5, LXB_CSS_VALUE_AZURE}, + {(lxb_char_t *) "beige", 5, LXB_CSS_VALUE_BEIGE}, + {(lxb_char_t *) "bisque", 6, LXB_CSS_VALUE_BISQUE}, + {(lxb_char_t *) "black", 5, LXB_CSS_VALUE_BLACK}, + {(lxb_char_t *) "blanchedalmond", 14, LXB_CSS_VALUE_BLANCHEDALMOND}, + {(lxb_char_t *) "blue", 4, LXB_CSS_VALUE_BLUE}, + {(lxb_char_t *) "blueviolet", 10, LXB_CSS_VALUE_BLUEVIOLET}, + {(lxb_char_t *) "brown", 5, LXB_CSS_VALUE_BROWN}, + {(lxb_char_t *) "burlywood", 9, LXB_CSS_VALUE_BURLYWOOD}, + {(lxb_char_t *) "cadetblue", 9, LXB_CSS_VALUE_CADETBLUE}, + {(lxb_char_t *) "chartreuse", 10, LXB_CSS_VALUE_CHARTREUSE}, + {(lxb_char_t *) "chocolate", 9, LXB_CSS_VALUE_CHOCOLATE}, + {(lxb_char_t *) "coral", 5, LXB_CSS_VALUE_CORAL}, + {(lxb_char_t *) "cornflowerblue", 14, LXB_CSS_VALUE_CORNFLOWERBLUE}, + {(lxb_char_t *) "cornsilk", 8, LXB_CSS_VALUE_CORNSILK}, + {(lxb_char_t *) "crimson", 7, LXB_CSS_VALUE_CRIMSON}, + {(lxb_char_t *) "cyan", 4, LXB_CSS_VALUE_CYAN}, + {(lxb_char_t *) "darkblue", 8, LXB_CSS_VALUE_DARKBLUE}, + {(lxb_char_t *) "darkcyan", 8, LXB_CSS_VALUE_DARKCYAN}, + {(lxb_char_t *) "darkgoldenrod", 13, LXB_CSS_VALUE_DARKGOLDENROD}, + {(lxb_char_t *) "darkgray", 8, LXB_CSS_VALUE_DARKGRAY}, + {(lxb_char_t *) "darkgreen", 9, LXB_CSS_VALUE_DARKGREEN}, + {(lxb_char_t *) "darkgrey", 8, LXB_CSS_VALUE_DARKGREY}, + {(lxb_char_t *) "darkkhaki", 9, LXB_CSS_VALUE_DARKKHAKI}, + {(lxb_char_t *) "darkmagenta", 11, LXB_CSS_VALUE_DARKMAGENTA}, + {(lxb_char_t *) "darkolivegreen", 14, LXB_CSS_VALUE_DARKOLIVEGREEN}, + {(lxb_char_t *) "darkorange", 10, LXB_CSS_VALUE_DARKORANGE}, + {(lxb_char_t *) "darkorchid", 10, LXB_CSS_VALUE_DARKORCHID}, + {(lxb_char_t *) "darkred", 7, LXB_CSS_VALUE_DARKRED}, + {(lxb_char_t *) "darksalmon", 10, LXB_CSS_VALUE_DARKSALMON}, + {(lxb_char_t *) "darkseagreen", 12, LXB_CSS_VALUE_DARKSEAGREEN}, + {(lxb_char_t *) "darkslateblue", 13, LXB_CSS_VALUE_DARKSLATEBLUE}, + {(lxb_char_t *) "darkslategray", 13, LXB_CSS_VALUE_DARKSLATEGRAY}, + {(lxb_char_t *) "darkslategrey", 13, LXB_CSS_VALUE_DARKSLATEGREY}, + {(lxb_char_t *) "darkturquoise", 13, LXB_CSS_VALUE_DARKTURQUOISE}, + {(lxb_char_t *) "darkviolet", 10, LXB_CSS_VALUE_DARKVIOLET}, + {(lxb_char_t *) "deeppink", 8, LXB_CSS_VALUE_DEEPPINK}, + {(lxb_char_t *) "deepskyblue", 11, LXB_CSS_VALUE_DEEPSKYBLUE}, + {(lxb_char_t *) "dimgray", 7, LXB_CSS_VALUE_DIMGRAY}, + {(lxb_char_t *) "dimgrey", 7, LXB_CSS_VALUE_DIMGREY}, + {(lxb_char_t *) "dodgerblue", 10, LXB_CSS_VALUE_DODGERBLUE}, + {(lxb_char_t *) "firebrick", 9, LXB_CSS_VALUE_FIREBRICK}, + {(lxb_char_t *) "floralwhite", 11, LXB_CSS_VALUE_FLORALWHITE}, + {(lxb_char_t *) "forestgreen", 11, LXB_CSS_VALUE_FORESTGREEN}, + {(lxb_char_t *) "fuchsia", 7, LXB_CSS_VALUE_FUCHSIA}, + {(lxb_char_t *) "gainsboro", 9, LXB_CSS_VALUE_GAINSBORO}, + {(lxb_char_t *) "ghostwhite", 10, LXB_CSS_VALUE_GHOSTWHITE}, + {(lxb_char_t *) "gold", 4, LXB_CSS_VALUE_GOLD}, + {(lxb_char_t *) "goldenrod", 9, LXB_CSS_VALUE_GOLDENROD}, + {(lxb_char_t *) "gray", 4, LXB_CSS_VALUE_GRAY}, + {(lxb_char_t *) "green", 5, LXB_CSS_VALUE_GREEN}, + {(lxb_char_t *) "greenyellow", 11, LXB_CSS_VALUE_GREENYELLOW}, + {(lxb_char_t *) "grey", 4, LXB_CSS_VALUE_GREY}, + {(lxb_char_t *) "honeydew", 8, LXB_CSS_VALUE_HONEYDEW}, + {(lxb_char_t *) "hotpink", 7, LXB_CSS_VALUE_HOTPINK}, + {(lxb_char_t *) "indianred", 9, LXB_CSS_VALUE_INDIANRED}, + {(lxb_char_t *) "indigo", 6, LXB_CSS_VALUE_INDIGO}, + {(lxb_char_t *) "ivory", 5, LXB_CSS_VALUE_IVORY}, + {(lxb_char_t *) "khaki", 5, LXB_CSS_VALUE_KHAKI}, + {(lxb_char_t *) "lavender", 8, LXB_CSS_VALUE_LAVENDER}, + {(lxb_char_t *) "lavenderblush", 13, LXB_CSS_VALUE_LAVENDERBLUSH}, + {(lxb_char_t *) "lawngreen", 9, LXB_CSS_VALUE_LAWNGREEN}, + {(lxb_char_t *) "lemonchiffon", 12, LXB_CSS_VALUE_LEMONCHIFFON}, + {(lxb_char_t *) "lightblue", 9, LXB_CSS_VALUE_LIGHTBLUE}, + {(lxb_char_t *) "lightcoral", 10, LXB_CSS_VALUE_LIGHTCORAL}, + {(lxb_char_t *) "lightcyan", 9, LXB_CSS_VALUE_LIGHTCYAN}, + {(lxb_char_t *) "lightgoldenrodyellow", 20, LXB_CSS_VALUE_LIGHTGOLDENRODYELLOW}, + {(lxb_char_t *) "lightgray", 9, LXB_CSS_VALUE_LIGHTGRAY}, + {(lxb_char_t *) "lightgreen", 10, LXB_CSS_VALUE_LIGHTGREEN}, + {(lxb_char_t *) "lightgrey", 9, LXB_CSS_VALUE_LIGHTGREY}, + {(lxb_char_t *) "lightpink", 9, LXB_CSS_VALUE_LIGHTPINK}, + {(lxb_char_t *) "lightsalmon", 11, LXB_CSS_VALUE_LIGHTSALMON}, + {(lxb_char_t *) "lightseagreen", 13, LXB_CSS_VALUE_LIGHTSEAGREEN}, + {(lxb_char_t *) "lightskyblue", 12, LXB_CSS_VALUE_LIGHTSKYBLUE}, + {(lxb_char_t *) "lightslategray", 14, LXB_CSS_VALUE_LIGHTSLATEGRAY}, + {(lxb_char_t *) "lightslategrey", 14, LXB_CSS_VALUE_LIGHTSLATEGREY}, + {(lxb_char_t *) "lightsteelblue", 14, LXB_CSS_VALUE_LIGHTSTEELBLUE}, + {(lxb_char_t *) "lightyellow", 11, LXB_CSS_VALUE_LIGHTYELLOW}, + {(lxb_char_t *) "lime", 4, LXB_CSS_VALUE_LIME}, + {(lxb_char_t *) "limegreen", 9, LXB_CSS_VALUE_LIMEGREEN}, + {(lxb_char_t *) "linen", 5, LXB_CSS_VALUE_LINEN}, + {(lxb_char_t *) "magenta", 7, LXB_CSS_VALUE_MAGENTA}, + {(lxb_char_t *) "maroon", 6, LXB_CSS_VALUE_MAROON}, + {(lxb_char_t *) "mediumaquamarine", 16, LXB_CSS_VALUE_MEDIUMAQUAMARINE}, + {(lxb_char_t *) "mediumblue", 10, LXB_CSS_VALUE_MEDIUMBLUE}, + {(lxb_char_t *) "mediumorchid", 12, LXB_CSS_VALUE_MEDIUMORCHID}, + {(lxb_char_t *) "mediumpurple", 12, LXB_CSS_VALUE_MEDIUMPURPLE}, + {(lxb_char_t *) "mediumseagreen", 14, LXB_CSS_VALUE_MEDIUMSEAGREEN}, + {(lxb_char_t *) "mediumslateblue", 15, LXB_CSS_VALUE_MEDIUMSLATEBLUE}, + {(lxb_char_t *) "mediumspringgreen", 17, LXB_CSS_VALUE_MEDIUMSPRINGGREEN}, + {(lxb_char_t *) "mediumturquoise", 15, LXB_CSS_VALUE_MEDIUMTURQUOISE}, + {(lxb_char_t *) "mediumvioletred", 15, LXB_CSS_VALUE_MEDIUMVIOLETRED}, + {(lxb_char_t *) "midnightblue", 12, LXB_CSS_VALUE_MIDNIGHTBLUE}, + {(lxb_char_t *) "mintcream", 9, LXB_CSS_VALUE_MINTCREAM}, + {(lxb_char_t *) "mistyrose", 9, LXB_CSS_VALUE_MISTYROSE}, + {(lxb_char_t *) "moccasin", 8, LXB_CSS_VALUE_MOCCASIN}, + {(lxb_char_t *) "navajowhite", 11, LXB_CSS_VALUE_NAVAJOWHITE}, + {(lxb_char_t *) "navy", 4, LXB_CSS_VALUE_NAVY}, + {(lxb_char_t *) "oldlace", 7, LXB_CSS_VALUE_OLDLACE}, + {(lxb_char_t *) "olive", 5, LXB_CSS_VALUE_OLIVE}, + {(lxb_char_t *) "olivedrab", 9, LXB_CSS_VALUE_OLIVEDRAB}, + {(lxb_char_t *) "orange", 6, LXB_CSS_VALUE_ORANGE}, + {(lxb_char_t *) "orangered", 9, LXB_CSS_VALUE_ORANGERED}, + {(lxb_char_t *) "orchid", 6, LXB_CSS_VALUE_ORCHID}, + {(lxb_char_t *) "palegoldenrod", 13, LXB_CSS_VALUE_PALEGOLDENROD}, + {(lxb_char_t *) "palegreen", 9, LXB_CSS_VALUE_PALEGREEN}, + {(lxb_char_t *) "paleturquoise", 13, LXB_CSS_VALUE_PALETURQUOISE}, + {(lxb_char_t *) "palevioletred", 13, LXB_CSS_VALUE_PALEVIOLETRED}, + {(lxb_char_t *) "papayawhip", 10, LXB_CSS_VALUE_PAPAYAWHIP}, + {(lxb_char_t *) "peachpuff", 9, LXB_CSS_VALUE_PEACHPUFF}, + {(lxb_char_t *) "peru", 4, LXB_CSS_VALUE_PERU}, + {(lxb_char_t *) "pink", 4, LXB_CSS_VALUE_PINK}, + {(lxb_char_t *) "plum", 4, LXB_CSS_VALUE_PLUM}, + {(lxb_char_t *) "powderblue", 10, LXB_CSS_VALUE_POWDERBLUE}, + {(lxb_char_t *) "purple", 6, LXB_CSS_VALUE_PURPLE}, + {(lxb_char_t *) "rebeccapurple", 13, LXB_CSS_VALUE_REBECCAPURPLE}, + {(lxb_char_t *) "red", 3, LXB_CSS_VALUE_RED}, + {(lxb_char_t *) "rosybrown", 9, LXB_CSS_VALUE_ROSYBROWN}, + {(lxb_char_t *) "royalblue", 9, LXB_CSS_VALUE_ROYALBLUE}, + {(lxb_char_t *) "saddlebrown", 11, LXB_CSS_VALUE_SADDLEBROWN}, + {(lxb_char_t *) "salmon", 6, LXB_CSS_VALUE_SALMON}, + {(lxb_char_t *) "sandybrown", 10, LXB_CSS_VALUE_SANDYBROWN}, + {(lxb_char_t *) "seagreen", 8, LXB_CSS_VALUE_SEAGREEN}, + {(lxb_char_t *) "seashell", 8, LXB_CSS_VALUE_SEASHELL}, + {(lxb_char_t *) "sienna", 6, LXB_CSS_VALUE_SIENNA}, + {(lxb_char_t *) "silver", 6, LXB_CSS_VALUE_SILVER}, + {(lxb_char_t *) "skyblue", 7, LXB_CSS_VALUE_SKYBLUE}, + {(lxb_char_t *) "slateblue", 9, LXB_CSS_VALUE_SLATEBLUE}, + {(lxb_char_t *) "slategray", 9, LXB_CSS_VALUE_SLATEGRAY}, + {(lxb_char_t *) "slategrey", 9, LXB_CSS_VALUE_SLATEGREY}, + {(lxb_char_t *) "snow", 4, LXB_CSS_VALUE_SNOW}, + {(lxb_char_t *) "springgreen", 11, LXB_CSS_VALUE_SPRINGGREEN}, + {(lxb_char_t *) "steelblue", 9, LXB_CSS_VALUE_STEELBLUE}, + {(lxb_char_t *) "tan", 3, LXB_CSS_VALUE_TAN}, + {(lxb_char_t *) "teal", 4, LXB_CSS_VALUE_TEAL}, + {(lxb_char_t *) "thistle", 7, LXB_CSS_VALUE_THISTLE}, + {(lxb_char_t *) "tomato", 6, LXB_CSS_VALUE_TOMATO}, + {(lxb_char_t *) "turquoise", 9, LXB_CSS_VALUE_TURQUOISE}, + {(lxb_char_t *) "violet", 6, LXB_CSS_VALUE_VIOLET}, + {(lxb_char_t *) "wheat", 5, LXB_CSS_VALUE_WHEAT}, + {(lxb_char_t *) "white", 5, LXB_CSS_VALUE_WHITE}, + {(lxb_char_t *) "whitesmoke", 10, LXB_CSS_VALUE_WHITESMOKE}, + {(lxb_char_t *) "yellow", 6, LXB_CSS_VALUE_YELLOW}, + {(lxb_char_t *) "yellowgreen", 11, LXB_CSS_VALUE_YELLOWGREEN}, + {(lxb_char_t *) "Canvas", 6, LXB_CSS_VALUE_CANVAS}, + {(lxb_char_t *) "CanvasText", 10, LXB_CSS_VALUE_CANVASTEXT}, + {(lxb_char_t *) "LinkText", 8, LXB_CSS_VALUE_LINKTEXT}, + {(lxb_char_t *) "VisitedText", 11, LXB_CSS_VALUE_VISITEDTEXT}, + {(lxb_char_t *) "ActiveText", 10, LXB_CSS_VALUE_ACTIVETEXT}, + {(lxb_char_t *) "ButtonFace", 10, LXB_CSS_VALUE_BUTTONFACE}, + {(lxb_char_t *) "ButtonText", 10, LXB_CSS_VALUE_BUTTONTEXT}, + {(lxb_char_t *) "ButtonBorder", 12, LXB_CSS_VALUE_BUTTONBORDER}, + {(lxb_char_t *) "Field", 5, LXB_CSS_VALUE_FIELD}, + {(lxb_char_t *) "FieldText", 9, LXB_CSS_VALUE_FIELDTEXT}, + {(lxb_char_t *) "Highlight", 9, LXB_CSS_VALUE_HIGHLIGHT}, + {(lxb_char_t *) "HighlightText", 13, LXB_CSS_VALUE_HIGHLIGHTTEXT}, + {(lxb_char_t *) "SelectedItem", 12, LXB_CSS_VALUE_SELECTEDITEM}, + {(lxb_char_t *) "SelectedItemText", 16, LXB_CSS_VALUE_SELECTEDITEMTEXT}, + {(lxb_char_t *) "Mark", 4, LXB_CSS_VALUE_MARK}, + {(lxb_char_t *) "MarkText", 8, LXB_CSS_VALUE_MARKTEXT}, + {(lxb_char_t *) "GrayText", 8, LXB_CSS_VALUE_GRAYTEXT}, + {(lxb_char_t *) "AccentColor", 11, LXB_CSS_VALUE_ACCENTCOLOR}, + {(lxb_char_t *) "AccentColorText", 15, LXB_CSS_VALUE_ACCENTCOLORTEXT}, + {(lxb_char_t *) "rgb", 3, LXB_CSS_VALUE_RGB}, + {(lxb_char_t *) "rgba", 4, LXB_CSS_VALUE_RGBA}, + {(lxb_char_t *) "hsl", 3, LXB_CSS_VALUE_HSL}, + {(lxb_char_t *) "hsla", 4, LXB_CSS_VALUE_HSLA}, + {(lxb_char_t *) "hwb", 3, LXB_CSS_VALUE_HWB}, + {(lxb_char_t *) "lab", 3, LXB_CSS_VALUE_LAB}, + {(lxb_char_t *) "lch", 3, LXB_CSS_VALUE_LCH}, + {(lxb_char_t *) "oklab", 5, LXB_CSS_VALUE_OKLAB}, + {(lxb_char_t *) "oklch", 5, LXB_CSS_VALUE_OKLCH}, + {(lxb_char_t *) "color", 5, LXB_CSS_VALUE_COLOR}, + {(lxb_char_t *) "ltr", 3, LXB_CSS_VALUE_LTR}, + {(lxb_char_t *) "rtl", 3, LXB_CSS_VALUE_RTL}, + {(lxb_char_t *) "block", 5, LXB_CSS_VALUE_BLOCK}, + {(lxb_char_t *) "inline", 6, LXB_CSS_VALUE_INLINE}, + {(lxb_char_t *) "run-in", 6, LXB_CSS_VALUE_RUN_IN}, + {(lxb_char_t *) "flow", 4, LXB_CSS_VALUE_FLOW}, + {(lxb_char_t *) "flow-root", 9, LXB_CSS_VALUE_FLOW_ROOT}, + {(lxb_char_t *) "table", 5, LXB_CSS_VALUE_TABLE}, + {(lxb_char_t *) "flex", 4, LXB_CSS_VALUE_FLEX}, + {(lxb_char_t *) "grid", 4, LXB_CSS_VALUE_GRID}, + {(lxb_char_t *) "ruby", 4, LXB_CSS_VALUE_RUBY}, + {(lxb_char_t *) "list-item", 9, LXB_CSS_VALUE_LIST_ITEM}, + {(lxb_char_t *) "table-row-group", 15, LXB_CSS_VALUE_TABLE_ROW_GROUP}, + {(lxb_char_t *) "table-header-group", 18, LXB_CSS_VALUE_TABLE_HEADER_GROUP}, + {(lxb_char_t *) "table-footer-group", 18, LXB_CSS_VALUE_TABLE_FOOTER_GROUP}, + {(lxb_char_t *) "table-row", 9, LXB_CSS_VALUE_TABLE_ROW}, + {(lxb_char_t *) "table-cell", 10, LXB_CSS_VALUE_TABLE_CELL}, + {(lxb_char_t *) "table-column-group", 18, LXB_CSS_VALUE_TABLE_COLUMN_GROUP}, + {(lxb_char_t *) "table-column", 12, LXB_CSS_VALUE_TABLE_COLUMN}, + {(lxb_char_t *) "table-caption", 13, LXB_CSS_VALUE_TABLE_CAPTION}, + {(lxb_char_t *) "ruby-base", 9, LXB_CSS_VALUE_RUBY_BASE}, + {(lxb_char_t *) "ruby-text", 9, LXB_CSS_VALUE_RUBY_TEXT}, + {(lxb_char_t *) "ruby-base-container", 19, LXB_CSS_VALUE_RUBY_BASE_CONTAINER}, + {(lxb_char_t *) "ruby-text-container", 19, LXB_CSS_VALUE_RUBY_TEXT_CONTAINER}, + {(lxb_char_t *) "contents", 8, LXB_CSS_VALUE_CONTENTS}, + {(lxb_char_t *) "inline-block", 12, LXB_CSS_VALUE_INLINE_BLOCK}, + {(lxb_char_t *) "inline-table", 12, LXB_CSS_VALUE_INLINE_TABLE}, + {(lxb_char_t *) "inline-flex", 11, LXB_CSS_VALUE_INLINE_FLEX}, + {(lxb_char_t *) "inline-grid", 11, LXB_CSS_VALUE_INLINE_GRID}, + {(lxb_char_t *) "hanging", 7, LXB_CSS_VALUE_HANGING}, + {(lxb_char_t *) "content", 7, LXB_CSS_VALUE_CONTENT}, + {(lxb_char_t *) "row", 3, LXB_CSS_VALUE_ROW}, + {(lxb_char_t *) "row-reverse", 11, LXB_CSS_VALUE_ROW_REVERSE}, + {(lxb_char_t *) "column", 6, LXB_CSS_VALUE_COLUMN}, + {(lxb_char_t *) "column-reverse", 14, LXB_CSS_VALUE_COLUMN_REVERSE}, + {(lxb_char_t *) "_number", 7, LXB_CSS_VALUE__NUMBER}, + {(lxb_char_t *) "nowrap", 6, LXB_CSS_VALUE_NOWRAP}, + {(lxb_char_t *) "wrap", 4, LXB_CSS_VALUE_WRAP}, + {(lxb_char_t *) "wrap-reverse", 12, LXB_CSS_VALUE_WRAP_REVERSE}, + {(lxb_char_t *) "snap-block", 10, LXB_CSS_VALUE_SNAP_BLOCK}, + {(lxb_char_t *) "start", 5, LXB_CSS_VALUE_START}, + {(lxb_char_t *) "end", 3, LXB_CSS_VALUE_END}, + {(lxb_char_t *) "near", 4, LXB_CSS_VALUE_NEAR}, + {(lxb_char_t *) "snap-inline", 11, LXB_CSS_VALUE_SNAP_INLINE}, + {(lxb_char_t *) "_integer", 8, LXB_CSS_VALUE__INTEGER}, + {(lxb_char_t *) "region", 6, LXB_CSS_VALUE_REGION}, + {(lxb_char_t *) "page", 4, LXB_CSS_VALUE_PAGE}, + {(lxb_char_t *) "serif", 5, LXB_CSS_VALUE_SERIF}, + {(lxb_char_t *) "sans-serif", 10, LXB_CSS_VALUE_SANS_SERIF}, + {(lxb_char_t *) "cursive", 7, LXB_CSS_VALUE_CURSIVE}, + {(lxb_char_t *) "fantasy", 7, LXB_CSS_VALUE_FANTASY}, + {(lxb_char_t *) "monospace", 9, LXB_CSS_VALUE_MONOSPACE}, + {(lxb_char_t *) "system-ui", 9, LXB_CSS_VALUE_SYSTEM_UI}, + {(lxb_char_t *) "emoji", 5, LXB_CSS_VALUE_EMOJI}, + {(lxb_char_t *) "math", 4, LXB_CSS_VALUE_MATH}, + {(lxb_char_t *) "fangsong", 8, LXB_CSS_VALUE_FANGSONG}, + {(lxb_char_t *) "ui-serif", 8, LXB_CSS_VALUE_UI_SERIF}, + {(lxb_char_t *) "ui-sans-serif", 13, LXB_CSS_VALUE_UI_SANS_SERIF}, + {(lxb_char_t *) "ui-monospace", 12, LXB_CSS_VALUE_UI_MONOSPACE}, + {(lxb_char_t *) "ui-rounded", 10, LXB_CSS_VALUE_UI_ROUNDED}, + {(lxb_char_t *) "xx-small", 8, LXB_CSS_VALUE_XX_SMALL}, + {(lxb_char_t *) "x-small", 7, LXB_CSS_VALUE_X_SMALL}, + {(lxb_char_t *) "small", 5, LXB_CSS_VALUE_SMALL}, + {(lxb_char_t *) "large", 5, LXB_CSS_VALUE_LARGE}, + {(lxb_char_t *) "x-large", 7, LXB_CSS_VALUE_X_LARGE}, + {(lxb_char_t *) "xx-large", 8, LXB_CSS_VALUE_XX_LARGE}, + {(lxb_char_t *) "xxx-large", 9, LXB_CSS_VALUE_XXX_LARGE}, + {(lxb_char_t *) "larger", 6, LXB_CSS_VALUE_LARGER}, + {(lxb_char_t *) "smaller", 7, LXB_CSS_VALUE_SMALLER}, + {(lxb_char_t *) "normal", 6, LXB_CSS_VALUE_NORMAL}, + {(lxb_char_t *) "ultra-condensed", 15, LXB_CSS_VALUE_ULTRA_CONDENSED}, + {(lxb_char_t *) "extra-condensed", 15, LXB_CSS_VALUE_EXTRA_CONDENSED}, + {(lxb_char_t *) "condensed", 9, LXB_CSS_VALUE_CONDENSED}, + {(lxb_char_t *) "semi-condensed", 14, LXB_CSS_VALUE_SEMI_CONDENSED}, + {(lxb_char_t *) "semi-expanded", 13, LXB_CSS_VALUE_SEMI_EXPANDED}, + {(lxb_char_t *) "expanded", 8, LXB_CSS_VALUE_EXPANDED}, + {(lxb_char_t *) "extra-expanded", 14, LXB_CSS_VALUE_EXTRA_EXPANDED}, + {(lxb_char_t *) "ultra-expanded", 14, LXB_CSS_VALUE_ULTRA_EXPANDED}, + {(lxb_char_t *) "italic", 6, LXB_CSS_VALUE_ITALIC}, + {(lxb_char_t *) "oblique", 7, LXB_CSS_VALUE_OBLIQUE}, + {(lxb_char_t *) "bold", 4, LXB_CSS_VALUE_BOLD}, + {(lxb_char_t *) "bolder", 6, LXB_CSS_VALUE_BOLDER}, + {(lxb_char_t *) "lighter", 7, LXB_CSS_VALUE_LIGHTER}, + {(lxb_char_t *) "force-end", 9, LXB_CSS_VALUE_FORCE_END}, + {(lxb_char_t *) "allow-end", 9, LXB_CSS_VALUE_ALLOW_END}, + {(lxb_char_t *) "min-content", 11, LXB_CSS_VALUE_MIN_CONTENT}, + {(lxb_char_t *) "max-content", 11, LXB_CSS_VALUE_MAX_CONTENT}, + {(lxb_char_t *) "_angle", 6, LXB_CSS_VALUE__ANGLE}, + {(lxb_char_t *) "manual", 6, LXB_CSS_VALUE_MANUAL}, + {(lxb_char_t *) "loose", 5, LXB_CSS_VALUE_LOOSE}, + {(lxb_char_t *) "strict", 6, LXB_CSS_VALUE_STRICT}, + {(lxb_char_t *) "anywhere", 8, LXB_CSS_VALUE_ANYWHERE}, + {(lxb_char_t *) "visible", 7, LXB_CSS_VALUE_VISIBLE}, + {(lxb_char_t *) "clip", 4, LXB_CSS_VALUE_CLIP}, + {(lxb_char_t *) "scroll", 6, LXB_CSS_VALUE_SCROLL}, + {(lxb_char_t *) "break-word", 10, LXB_CSS_VALUE_BREAK_WORD}, + {(lxb_char_t *) "static", 6, LXB_CSS_VALUE_STATIC}, + {(lxb_char_t *) "relative", 8, LXB_CSS_VALUE_RELATIVE}, + {(lxb_char_t *) "absolute", 8, LXB_CSS_VALUE_ABSOLUTE}, + {(lxb_char_t *) "sticky", 6, LXB_CSS_VALUE_STICKY}, + {(lxb_char_t *) "fixed", 5, LXB_CSS_VALUE_FIXED}, + {(lxb_char_t *) "justify", 7, LXB_CSS_VALUE_JUSTIFY}, + {(lxb_char_t *) "match-parent", 12, LXB_CSS_VALUE_MATCH_PARENT}, + {(lxb_char_t *) "justify-all", 11, LXB_CSS_VALUE_JUSTIFY_ALL}, + {(lxb_char_t *) "all", 3, LXB_CSS_VALUE_ALL}, + {(lxb_char_t *) "digits", 6, LXB_CSS_VALUE_DIGITS}, + {(lxb_char_t *) "underline", 9, LXB_CSS_VALUE_UNDERLINE}, + {(lxb_char_t *) "overline", 8, LXB_CSS_VALUE_OVERLINE}, + {(lxb_char_t *) "line-through", 12, LXB_CSS_VALUE_LINE_THROUGH}, + {(lxb_char_t *) "blink", 5, LXB_CSS_VALUE_BLINK}, + {(lxb_char_t *) "wavy", 4, LXB_CSS_VALUE_WAVY}, + {(lxb_char_t *) "each-line", 9, LXB_CSS_VALUE_EACH_LINE}, + {(lxb_char_t *) "inter-word", 10, LXB_CSS_VALUE_INTER_WORD}, + {(lxb_char_t *) "inter-character", 15, LXB_CSS_VALUE_INTER_CHARACTER}, + {(lxb_char_t *) "mixed", 5, LXB_CSS_VALUE_MIXED}, + {(lxb_char_t *) "upright", 7, LXB_CSS_VALUE_UPRIGHT}, + {(lxb_char_t *) "sideways", 8, LXB_CSS_VALUE_SIDEWAYS}, + {(lxb_char_t *) "ellipsis", 8, LXB_CSS_VALUE_ELLIPSIS}, + {(lxb_char_t *) "capitalize", 10, LXB_CSS_VALUE_CAPITALIZE}, + {(lxb_char_t *) "uppercase", 9, LXB_CSS_VALUE_UPPERCASE}, + {(lxb_char_t *) "lowercase", 9, LXB_CSS_VALUE_LOWERCASE}, + {(lxb_char_t *) "full-width", 10, LXB_CSS_VALUE_FULL_WIDTH}, + {(lxb_char_t *) "full-size-kana", 14, LXB_CSS_VALUE_FULL_SIZE_KANA}, + {(lxb_char_t *) "embed", 5, LXB_CSS_VALUE_EMBED}, + {(lxb_char_t *) "isolate", 7, LXB_CSS_VALUE_ISOLATE}, + {(lxb_char_t *) "bidi-override", 13, LXB_CSS_VALUE_BIDI_OVERRIDE}, + {(lxb_char_t *) "isolate-override", 16, LXB_CSS_VALUE_ISOLATE_OVERRIDE}, + {(lxb_char_t *) "plaintext", 9, LXB_CSS_VALUE_PLAINTEXT}, + {(lxb_char_t *) "collapse", 8, LXB_CSS_VALUE_COLLAPSE}, + {(lxb_char_t *) "pre", 3, LXB_CSS_VALUE_PRE}, + {(lxb_char_t *) "pre-wrap", 8, LXB_CSS_VALUE_PRE_WRAP}, + {(lxb_char_t *) "break-spaces", 12, LXB_CSS_VALUE_BREAK_SPACES}, + {(lxb_char_t *) "pre-line", 8, LXB_CSS_VALUE_PRE_LINE}, + {(lxb_char_t *) "keep-all", 8, LXB_CSS_VALUE_KEEP_ALL}, + {(lxb_char_t *) "break-all", 9, LXB_CSS_VALUE_BREAK_ALL}, + {(lxb_char_t *) "both", 4, LXB_CSS_VALUE_BOTH}, + {(lxb_char_t *) "minimum", 7, LXB_CSS_VALUE_MINIMUM}, + {(lxb_char_t *) "maximum", 7, LXB_CSS_VALUE_MAXIMUM}, + {(lxb_char_t *) "clear", 5, LXB_CSS_VALUE_CLEAR}, + {(lxb_char_t *) "horizontal-tb", 13, LXB_CSS_VALUE_HORIZONTAL_TB}, + {(lxb_char_t *) "vertical-rl", 11, LXB_CSS_VALUE_VERTICAL_RL}, + {(lxb_char_t *) "vertical-lr", 11, LXB_CSS_VALUE_VERTICAL_LR}, + {(lxb_char_t *) "sideways-rl", 11, LXB_CSS_VALUE_SIDEWAYS_RL}, + {(lxb_char_t *) "sideways-lr", 11, LXB_CSS_VALUE_SIDEWAYS_LR} +}; + +static const lexbor_shs_entry_t lxb_css_value_shs[373] = +{ + {NULL, NULL, 253, 0}, + {"salmon", (void *) LXB_CSS_VALUE_SALMON, 6, 2}, + {"canvas", (void *) LXB_CSS_VALUE_CANVAS, 6, 4}, + {"allow-end", (void *) LXB_CSS_VALUE_ALLOW_END, 9, 0}, + {"static", (void *) LXB_CSS_VALUE_STATIC, 6, 5}, + {"sticky", (void *) LXB_CSS_VALUE_STICKY, 6, 0}, + {"darkviolet", (void *) LXB_CSS_VALUE_DARKVIOLET, 10, 0}, + {"blue", (void *) LXB_CSS_VALUE_BLUE, 4, 1}, + {"end", (void *) LXB_CSS_VALUE_END, 3, 24}, + {"middle", (void *) LXB_CSS_VALUE_MIDDLE, 6, 32}, + {"rgb", (void *) LXB_CSS_VALUE_RGB, 3, 59}, + {"baseline", (void *) LXB_CSS_VALUE_BASELINE, 8, 69}, + {"mistyrose", (void *) LXB_CSS_VALUE_MISTYROSE, 9, 71}, + {"expanded", (void *) LXB_CSS_VALUE_EXPANDED, 8, 92}, + {"space-between", (void *) LXB_CSS_VALUE_SPACE_BETWEEN, 13, 0}, + {"mediumpurple", (void *) LXB_CSS_VALUE_MEDIUMPURPLE, 12, 99}, + {"bidi-override", (void *) LXB_CSS_VALUE_BIDI_OVERRIDE, 13, 0}, + {"bold", (void *) LXB_CSS_VALUE_BOLD, 4, 103}, + {"mixed", (void *) LXB_CSS_VALUE_MIXED, 5, 105}, + {"extra-expanded", (void *) LXB_CSS_VALUE_EXTRA_EXPANDED, 14, 119}, + {"auto", (void *) LXB_CSS_VALUE_AUTO, 4, 129}, + {"teal", (void *) LXB_CSS_VALUE_TEAL, 4, 130}, + {"lab", (void *) LXB_CSS_VALUE_LAB, 3, 131}, + {"break-word", (void *) LXB_CSS_VALUE_BREAK_WORD, 10, 0}, + {"beige", (void *) LXB_CSS_VALUE_BEIGE, 5, 0}, + {"mediumorchid", (void *) LXB_CSS_VALUE_MEDIUMORCHID, 12, 0}, + {"vertical-lr", (void *) LXB_CSS_VALUE_VERTICAL_LR, 11, 0}, + {"table-cell", (void *) LXB_CSS_VALUE_TABLE_CELL, 10, 135}, + {"pre-wrap", (void *) LXB_CSS_VALUE_PRE_WRAP, 8, 136}, + {"super", (void *) LXB_CSS_VALUE_SUPER, 5, 0}, + {"silver", (void *) LXB_CSS_VALUE_SILVER, 6, 137}, + {"hsl", (void *) LXB_CSS_VALUE_HSL, 3, 140}, + {"bisque", (void *) LXB_CSS_VALUE_BISQUE, 6, 53}, + {"darkblue", (void *) LXB_CSS_VALUE_DARKBLUE, 8, 0}, + {"hex", (void *) LXB_CSS_VALUE_HEX, 3, 0}, + {"darkorange", (void *) LXB_CSS_VALUE_DARKORANGE, 10, 143}, + {"lightcoral", (void *) LXB_CSS_VALUE_LIGHTCORAL, 10, 145}, + {"table-row", (void *) LXB_CSS_VALUE_TABLE_ROW, 9, 0}, + {"ridge", (void *) LXB_CSS_VALUE_RIDGE, 5, 149}, + {"violet", (void *) LXB_CSS_VALUE_VIOLET, 6, 156}, + {"italic", (void *) LXB_CSS_VALUE_ITALIC, 6, 157}, + {"relative", (void *) LXB_CSS_VALUE_RELATIVE, 8, 0}, + {"royalblue", (void *) LXB_CSS_VALUE_ROYALBLUE, 9, 179}, + {"highlighttext", (void *) LXB_CSS_VALUE_HIGHLIGHTTEXT, 13, 0}, + {"visitedtext", (void *) LXB_CSS_VALUE_VISITEDTEXT, 11, 193}, + {"ideographic", (void *) LXB_CSS_VALUE_IDEOGRAPHIC, 11, 0}, + {"outset", (void *) LXB_CSS_VALUE_OUTSET, 6, 194}, + {"azure", (void *) LXB_CSS_VALUE_AZURE, 5, 0}, + {"pink", (void *) LXB_CSS_VALUE_PINK, 4, 0}, + {"near", (void *) LXB_CSS_VALUE_NEAR, 4, 0}, + {"magenta", (void *) LXB_CSS_VALUE_MAGENTA, 7, 204}, + {"aliceblue", (void *) LXB_CSS_VALUE_ALICEBLUE, 9, 0}, + {"aquamarine", (void *) LXB_CSS_VALUE_AQUAMARINE, 10, 0}, + {"seagreen", (void *) LXB_CSS_VALUE_SEAGREEN, 8, 55}, + {"antiquewhite", (void *) LXB_CSS_VALUE_ANTIQUEWHITE, 12, 0}, + {"contents", (void *) LXB_CSS_VALUE_CONTENTS, 8, 56}, + {"lightpink", (void *) LXB_CSS_VALUE_LIGHTPINK, 9, 0}, + {"snap-block", (void *) LXB_CSS_VALUE_SNAP_BLOCK, 10, 0}, + {"white", (void *) LXB_CSS_VALUE_WHITE, 5, 0}, + {"embed", (void *) LXB_CSS_VALUE_EMBED, 5, 66}, + {"first", (void *) LXB_CSS_VALUE_FIRST, 5, 211}, + {"groove", (void *) LXB_CSS_VALUE_GROOVE, 6, 212}, + {"normal", (void *) LXB_CSS_VALUE_NORMAL, 6, 0}, + {"whitesmoke", (void *) LXB_CSS_VALUE_WHITESMOKE, 10, 0}, + {"fieldtext", (void *) LXB_CSS_VALUE_FIELDTEXT, 9, 221}, + {"flex-start", (void *) LXB_CSS_VALUE_FLEX_START, 10, 227}, + {"slategray", (void *) LXB_CSS_VALUE_SLATEGRAY, 9, 67}, + {"slategrey", (void *) LXB_CSS_VALUE_SLATEGREY, 9, 68}, + {"darkmagenta", (void *) LXB_CSS_VALUE_DARKMAGENTA, 11, 0}, + {"sandybrown", (void *) LXB_CSS_VALUE_SANDYBROWN, 10, 0}, + {"field", (void *) LXB_CSS_VALUE_FIELD, 5, 234}, + {"monospace", (void *) LXB_CSS_VALUE_MONOSPACE, 9, 78}, + {"color", (void *) LXB_CSS_VALUE_COLOR, 5, 236}, + {"center", (void *) LXB_CSS_VALUE_CENTER, 6, 240}, + {"force-end", (void *) LXB_CSS_VALUE_FORCE_END, 9, 0}, + {"solid", (void *) LXB_CSS_VALUE_SOLID, 5, 243}, + {"gold", (void *) LXB_CSS_VALUE_GOLD, 4, 248}, + {"peachpuff", (void *) LXB_CSS_VALUE_PEACHPUFF, 9, 0}, + {"saddlebrown", (void *) LXB_CSS_VALUE_SADDLEBROWN, 11, 86}, + {"inline", (void *) LXB_CSS_VALUE_INLINE, 6, 254}, + {"isolate", (void *) LXB_CSS_VALUE_ISOLATE, 7, 0}, + {"goldenrod", (void *) LXB_CSS_VALUE_GOLDENROD, 9, 0}, + {"cyan", (void *) LXB_CSS_VALUE_CYAN, 4, 256}, + {"linen", (void *) LXB_CSS_VALUE_LINEN, 5, 257}, + {"column", (void *) LXB_CSS_VALUE_COLUMN, 6, 258}, + {"crimson", (void *) LXB_CSS_VALUE_CRIMSON, 7, 259}, + {"springgreen", (void *) LXB_CSS_VALUE_SPRINGGREEN, 11, 0}, + {"lawngreen", (void *) LXB_CSS_VALUE_LAWNGREEN, 9, 260}, + {"lightgreen", (void *) LXB_CSS_VALUE_LIGHTGREEN, 10, 0}, + {"plum", (void *) LXB_CSS_VALUE_PLUM, 4, 262}, + {"initial", (void *) LXB_CSS_VALUE_INITIAL, 7, 264}, + {"lightseagreen", (void *) LXB_CSS_VALUE_LIGHTSEAGREEN, 13, 0}, + {"mediumblue", (void *) LXB_CSS_VALUE_MEDIUMBLUE, 10, 93}, + {"activetext", (void *) LXB_CSS_VALUE_ACTIVETEXT, 10, 94}, + {"buttonface", (void *) LXB_CSS_VALUE_BUTTONFACE, 10, 96}, + {"each-line", (void *) LXB_CSS_VALUE_EACH_LINE, 9, 0}, + {"greenyellow", (void *) LXB_CSS_VALUE_GREENYELLOW, 11, 0}, + {"hanging", (void *) LXB_CSS_VALUE_HANGING, 7, 0}, + {"hotpink", (void *) LXB_CSS_VALUE_HOTPINK, 7, 0}, + {"midnightblue", (void *) LXB_CSS_VALUE_MIDNIGHTBLUE, 12, 0}, + {"stretch", (void *) LXB_CSS_VALUE_STRETCH, 7, 0}, + {"lime", (void *) LXB_CSS_VALUE_LIME, 4, 266}, + {"unset", (void *) LXB_CSS_VALUE_UNSET, 5, 267}, + {"x-small", (void *) LXB_CSS_VALUE_X_SMALL, 7, 0}, + {"upright", (void *) LXB_CSS_VALUE_UPRIGHT, 7, 0}, + {"xx-small", (void *) LXB_CSS_VALUE_XX_SMALL, 8, 108}, + {"lightblue", (void *) LXB_CSS_VALUE_LIGHTBLUE, 9, 270}, + {"aqua", (void *) LXB_CSS_VALUE_AQUA, 4, 271}, + {"mediumslateblue", (void *) LXB_CSS_VALUE_MEDIUMSLATEBLUE, 15, 110}, + {"lightskyblue", (void *) LXB_CSS_VALUE_LIGHTSKYBLUE, 12, 0}, + {"mediumturquoise", (void *) LXB_CSS_VALUE_MEDIUMTURQUOISE, 15, 113}, + {"plaintext", (void *) LXB_CSS_VALUE_PLAINTEXT, 9, 272}, + {"justify-all", (void *) LXB_CSS_VALUE_JUSTIFY_ALL, 11, 0}, + {"accentcolortext", (void *) LXB_CSS_VALUE_ACCENTCOLORTEXT, 15, 0}, + {"tan", (void *) LXB_CSS_VALUE_TAN, 3, 273}, + {"thin", (void *) LXB_CSS_VALUE_THIN, 4, 274}, + {"blueviolet", (void *) LXB_CSS_VALUE_BLUEVIOLET, 10, 275}, + {"run-in", (void *) LXB_CSS_VALUE_RUN_IN, 6, 276}, + {"match-parent", (void *) LXB_CSS_VALUE_MATCH_PARENT, 12, 0}, + {"mediumaquamarine", (void *) LXB_CSS_VALUE_MEDIUMAQUAMARINE, 16, 0}, + {"snow", (void *) LXB_CSS_VALUE_SNOW, 4, 280}, + {"small", (void *) LXB_CSS_VALUE_SMALL, 5, 0}, + {"sienna", (void *) LXB_CSS_VALUE_SIENNA, 6, 283}, + {"table-column", (void *) LXB_CSS_VALUE_TABLE_COLUMN, 12, 0}, + {"seashell", (void *) LXB_CSS_VALUE_SEASHELL, 8, 286}, + {"lightslategray", (void *) LXB_CSS_VALUE_LIGHTSLATEGRAY, 14, 287}, + {"ruby", (void *) LXB_CSS_VALUE_RUBY, 4, 0}, + {"sideways-rl", (void *) LXB_CSS_VALUE_SIDEWAYS_RL, 11, 0}, + {"all", (void *) LXB_CSS_VALUE_ALL, 3, 288}, + {"extra-condensed", (void *) LXB_CSS_VALUE_EXTRA_CONDENSED, 15, 0}, + {"indigo", (void *) LXB_CSS_VALUE_INDIGO, 6, 0}, + {"block-end", (void *) LXB_CSS_VALUE_BLOCK_END, 9, 134}, + {"bolder", (void *) LXB_CSS_VALUE_BOLDER, 6, 0}, + {"forestgreen", (void *) LXB_CSS_VALUE_FORESTGREEN, 11, 0}, + {"burlywood", (void *) LXB_CSS_VALUE_BURLYWOOD, 9, 0}, + {"blanchedalmond", (void *) LXB_CSS_VALUE_BLANCHEDALMOND, 14, 0}, + {"mediumvioletred", (void *) LXB_CSS_VALUE_MEDIUMVIOLETRED, 15, 0}, + {"papayawhip", (void *) LXB_CSS_VALUE_PAPAYAWHIP, 10, 0}, + {"buttonborder", (void *) LXB_CSS_VALUE_BUTTONBORDER, 12, 0}, + {"nowrap", (void *) LXB_CSS_VALUE_NOWRAP, 6, 0}, + {"double", (void *) LXB_CSS_VALUE_DOUBLE, 6, 141}, + {"smaller", (void *) LXB_CSS_VALUE_SMALLER, 7, 142}, + {"cornsilk", (void *) LXB_CSS_VALUE_CORNSILK, 8, 0}, + {"dodgerblue", (void *) LXB_CSS_VALUE_DODGERBLUE, 10, 144}, + {"sideways-lr", (void *) LXB_CSS_VALUE_SIDEWAYS_LR, 11, 0}, + {"deepskyblue", (void *) LXB_CSS_VALUE_DEEPSKYBLUE, 11, 0}, + {"skyblue", (void *) LXB_CSS_VALUE_SKYBLUE, 7, 0}, + {"gainsboro", (void *) LXB_CSS_VALUE_GAINSBORO, 9, 0}, + {"khaki", (void *) LXB_CSS_VALUE_KHAKI, 5, 290}, + {"firebrick", (void *) LXB_CSS_VALUE_FIREBRICK, 9, 153}, + {"snap-inline", (void *) LXB_CSS_VALUE_SNAP_INLINE, 11, 0}, + {"dotted", (void *) LXB_CSS_VALUE_DOTTED, 6, 293}, + {"flow", (void *) LXB_CSS_VALUE_FLOW, 4, 295}, + {"darkslateblue", (void *) LXB_CSS_VALUE_DARKSLATEBLUE, 13, 154}, + {"darkturquoise", (void *) LXB_CSS_VALUE_DARKTURQUOISE, 13, 0}, + {"hwb", (void *) LXB_CSS_VALUE_HWB, 3, 297}, + {"highlight", (void *) LXB_CSS_VALUE_HIGHLIGHT, 9, 0}, + {"palegoldenrod", (void *) LXB_CSS_VALUE_PALEGOLDENROD, 13, 159}, + {"visible", (void *) LXB_CSS_VALUE_VISIBLE, 7, 298}, + {"palevioletred", (void *) LXB_CSS_VALUE_PALEVIOLETRED, 13, 0}, + {"green", (void *) LXB_CSS_VALUE_GREEN, 5, 299}, + {"hidden", (void *) LXB_CSS_VALUE_HIDDEN, 6, 300}, + {"emoji", (void *) LXB_CSS_VALUE_EMOJI, 5, 301}, + {"darkgray", (void *) LXB_CSS_VALUE_DARKGRAY, 8, 303}, + {"tomato", (void *) LXB_CSS_VALUE_TOMATO, 6, 304}, + {"xx-large", (void *) LXB_CSS_VALUE_XX_LARGE, 8, 305}, + {"fangsong", (void *) LXB_CSS_VALUE_FANGSONG, 8, 306}, + {"start", (void *) LXB_CSS_VALUE_START, 5, 0}, + {"right", (void *) LXB_CSS_VALUE_RIGHT, 5, 307}, + {"revert", (void *) LXB_CSS_VALUE_REVERT, 6, 0}, + {"wavy", (void *) LXB_CSS_VALUE_WAVY, 4, 0}, + {"rgba", (void *) LXB_CSS_VALUE_RGBA, 4, 310}, + {"maroon", (void *) LXB_CSS_VALUE_MAROON, 6, 313}, + {"olive", (void *) LXB_CSS_VALUE_OLIVE, 5, 314}, + {"orange", (void *) LXB_CSS_VALUE_ORANGE, 6, 315}, + {"oldlace", (void *) LXB_CSS_VALUE_OLDLACE, 7, 317}, + {"overline", (void *) LXB_CSS_VALUE_OVERLINE, 8, 320}, + {"pre", (void *) LXB_CSS_VALUE_PRE, 3, 322}, + {"lch", (void *) LXB_CSS_VALUE_LCH, 3, 323}, + {"ruby-base", (void *) LXB_CSS_VALUE_RUBY_BASE, 9, 0}, + {"purple", (void *) LXB_CSS_VALUE_PURPLE, 6, 325}, + {"rtl", (void *) LXB_CSS_VALUE_RTL, 3, 328}, + {"bottom", (void *) LXB_CSS_VALUE_BOTTOM, 6, 329}, + {"flex", (void *) LXB_CSS_VALUE_FLEX, 4, 331}, + {"powderblue", (void *) LXB_CSS_VALUE_POWDERBLUE, 10, 0}, + {"ltr", (void *) LXB_CSS_VALUE_LTR, 3, 334}, + {"ultra-condensed", (void *) LXB_CSS_VALUE_ULTRA_CONDENSED, 15, 0}, + {"line-through", (void *) LXB_CSS_VALUE_LINE_THROUGH, 12, 336}, + {"sub", (void *) LXB_CSS_VALUE_SUB, 3, 337}, + {"lighter", (void *) LXB_CSS_VALUE_LIGHTER, 7, 340}, + {"lavender", (void *) LXB_CSS_VALUE_LAVENDER, 8, 341}, + {"inline-grid", (void *) LXB_CSS_VALUE_INLINE_GRID, 11, 0}, + {"row", (void *) LXB_CSS_VALUE_ROW, 3, 343}, + {"row-reverse", (void *) LXB_CSS_VALUE_ROW_REVERSE, 11, 0}, + {"rebeccapurple", (void *) LXB_CSS_VALUE_REBECCAPURPLE, 13, 0}, + {"content", (void *) LXB_CSS_VALUE_CONTENT, 7, 344}, + {"red", (void *) LXB_CSS_VALUE_RED, 3, 0}, + {"selecteditem", (void *) LXB_CSS_VALUE_SELECTEDITEM, 12, 0}, + {"oklch", (void *) LXB_CSS_VALUE_OKLCH, 5, 346}, + {"table", (void *) LXB_CSS_VALUE_TABLE, 5, 348}, + {"mark", (void *) LXB_CSS_VALUE_MARK, 4, 0}, + {"black", (void *) LXB_CSS_VALUE_BLACK, 5, 349}, + {"inline-block", (void *) LXB_CSS_VALUE_INLINE_BLOCK, 12, 0}, + {"clip", (void *) LXB_CSS_VALUE_CLIP, 4, 352}, + {"anywhere", (void *) LXB_CSS_VALUE_ANYWHERE, 8, 205}, + {"absolute", (void *) LXB_CSS_VALUE_ABSOLUTE, 8, 0}, + {"wheat", (void *) LXB_CSS_VALUE_WHEAT, 5, 0}, + {"underline", (void *) LXB_CSS_VALUE_UNDERLINE, 9, 353}, + {"top", (void *) LXB_CSS_VALUE_TOP, 3, 0}, + {"alphabetic", (void *) LXB_CSS_VALUE_ALPHABETIC, 10, 0}, + {"ui-monospace", (void *) LXB_CSS_VALUE_UI_MONOSPACE, 12, 0}, + {"darkkhaki", (void *) LXB_CSS_VALUE_DARKKHAKI, 9, 0}, + {"graytext", (void *) LXB_CSS_VALUE_GRAYTEXT, 8, 214}, + {"serif", (void *) LXB_CSS_VALUE_SERIF, 5, 354}, + {"list-item", (void *) LXB_CSS_VALUE_LIST_ITEM, 9, 0}, + {"coral", (void *) LXB_CSS_VALUE_CORAL, 5, 355}, + {"ellipsis", (void *) LXB_CSS_VALUE_ELLIPSIS, 8, 0}, + {"central", (void *) LXB_CSS_VALUE_CENTRAL, 7, 357}, + {"darkcyan", (void *) LXB_CSS_VALUE_DARKCYAN, 8, 358}, + {"hsla", (void *) LXB_CSS_VALUE_HSLA, 4, 359}, + {"darksalmon", (void *) LXB_CSS_VALUE_DARKSALMON, 10, 360}, + {"flow-root", (void *) LXB_CSS_VALUE_FLOW_ROOT, 9, 0}, + {"darkseagreen", (void *) LXB_CSS_VALUE_DARKSEAGREEN, 12, 0}, + {"table-header-group", (void *) LXB_CSS_VALUE_TABLE_HEADER_GROUP, 18, 361}, + {"darkolivegreen", (void *) LXB_CSS_VALUE_DARKOLIVEGREEN, 14, 0}, + {"gray", (void *) LXB_CSS_VALUE_GRAY, 4, 363}, + {"_angle", (void *) LXB_CSS_VALUE__ANGLE, 6, 0}, + {"ghostwhite", (void *) LXB_CSS_VALUE_GHOSTWHITE, 10, 229}, + {"thick", (void *) LXB_CSS_VALUE_THICK, 5, 0}, + {"wrap-reverse", (void *) LXB_CSS_VALUE_WRAP_REVERSE, 12, 0}, + {"math", (void *) LXB_CSS_VALUE_MATH, 4, 365}, + {"_length", (void *) LXB_CSS_VALUE__LENGTH, 7, 366}, + {"fuchsia", (void *) LXB_CSS_VALUE_FUCHSIA, 7, 0}, + {"wrap", (void *) LXB_CSS_VALUE_WRAP, 4, 367}, + {"fixed", (void *) LXB_CSS_VALUE_FIXED, 5, 235}, + {"lightyellow", (void *) LXB_CSS_VALUE_LIGHTYELLOW, 11, 0}, + {"clear", (void *) LXB_CSS_VALUE_CLEAR, 5, 237}, + {"deeppink", (void *) LXB_CSS_VALUE_DEEPPINK, 8, 0}, + {"last", (void *) LXB_CSS_VALUE_LAST, 4, 368}, + {"full-size-kana", (void *) LXB_CSS_VALUE_FULL_SIZE_KANA, 14, 0}, + {"flex-end", (void *) LXB_CSS_VALUE_FLEX_END, 8, 0}, + {"palegreen", (void *) LXB_CSS_VALUE_PALEGREEN, 9, 370}, + {"linktext", (void *) LXB_CSS_VALUE_LINKTEXT, 8, 0}, + {"text-bottom", (void *) LXB_CSS_VALUE_TEXT_BOTTOM, 11, 245}, + {"inset", (void *) LXB_CSS_VALUE_INSET, 5, 0}, + {"inline-flex", (void *) LXB_CSS_VALUE_INLINE_FLEX, 11, 0}, + {"inherit", (void *) LXB_CSS_VALUE_INHERIT, 7, 0}, + {"navy", (void *) LXB_CSS_VALUE_NAVY, 4, 0}, + {"grid", (void *) LXB_CSS_VALUE_GRID, 4, 252}, + {"ruby-base-container", (void *) LXB_CSS_VALUE_RUBY_BASE_CONTAINER, 19, 371}, + {"orchid", (void *) LXB_CSS_VALUE_ORCHID, 6, 0}, + {"inline-start", (void *) LXB_CSS_VALUE_INLINE_START, 12, 0}, + {"border-box", (void *) LXB_CSS_VALUE_BORDER_BOX, 10, 0}, + {"peru", (void *) LXB_CSS_VALUE_PERU, 4, 372}, + {"currentcolor", (void *) LXB_CSS_VALUE_CURRENTCOLOR, 12, 255}, + {"lightgoldenrodyellow", (void *) LXB_CSS_VALUE_LIGHTGOLDENRODYELLOW, 20, 0}, + {"space-around", (void *) LXB_CSS_VALUE_SPACE_AROUND, 12, 0}, + {"semi-expanded", (void *) LXB_CSS_VALUE_SEMI_EXPANDED, 13, 0}, + {"semi-condensed", (void *) LXB_CSS_VALUE_SEMI_CONDENSED, 14, 0}, + {"inline-table", (void *) LXB_CSS_VALUE_INLINE_TABLE, 12, 0}, + {"lightcyan", (void *) LXB_CSS_VALUE_LIGHTCYAN, 9, 261}, + {"limegreen", (void *) LXB_CSS_VALUE_LIMEGREEN, 9, 0}, + {"lightsalmon", (void *) LXB_CSS_VALUE_LIGHTSALMON, 11, 263}, + {"isolate-override", (void *) LXB_CSS_VALUE_ISOLATE_OVERRIDE, 16, 0}, + {"keep-all", (void *) LXB_CSS_VALUE_KEEP_ALL, 8, 265}, + {"lemonchiffon", (void *) LXB_CSS_VALUE_LEMONCHIFFON, 12, 0}, + {"sideways", (void *) LXB_CSS_VALUE_SIDEWAYS, 8, 0}, + {"large", (void *) LXB_CSS_VALUE_LARGE, 5, 268}, + {"loose", (void *) LXB_CSS_VALUE_LOOSE, 5, 269}, + {"honeydew", (void *) LXB_CSS_VALUE_HONEYDEW, 8, 0}, + {"lowercase", (void *) LXB_CSS_VALUE_LOWERCASE, 9, 0}, + {"floralwhite", (void *) LXB_CSS_VALUE_FLORALWHITE, 11, 0}, + {"lightsteelblue", (void *) LXB_CSS_VALUE_LIGHTSTEELBLUE, 14, 0}, + {"marktext", (void *) LXB_CSS_VALUE_MARKTEXT, 8, 0}, + {"none", (void *) LXB_CSS_VALUE_NONE, 4, 0}, + {"buttontext", (void *) LXB_CSS_VALUE_BUTTONTEXT, 10, 0}, + {"region", (void *) LXB_CSS_VALUE_REGION, 6, 277}, + {"block-start", (void *) LXB_CSS_VALUE_BLOCK_START, 11, 278}, + {"min-content", (void *) LXB_CSS_VALUE_MIN_CONTENT, 11, 279}, + {"max-content", (void *) LXB_CSS_VALUE_MAX_CONTENT, 11, 0}, + {"lightgray", (void *) LXB_CSS_VALUE_LIGHTGRAY, 9, 281}, + {"lightgrey", (void *) LXB_CSS_VALUE_LIGHTGREY, 9, 282}, + {"rosybrown", (void *) LXB_CSS_VALUE_ROSYBROWN, 9, 0}, + {"scroll", (void *) LXB_CSS_VALUE_SCROLL, 6, 284}, + {"digits", (void *) LXB_CSS_VALUE_DIGITS, 6, 285}, + {"navajowhite", (void *) LXB_CSS_VALUE_NAVAJOWHITE, 11, 0}, + {"table-caption", (void *) LXB_CSS_VALUE_TABLE_CAPTION, 13, 0}, + {"lightslategrey", (void *) LXB_CSS_VALUE_LIGHTSLATEGREY, 14, 0}, + {"yellow", (void *) LXB_CSS_VALUE_YELLOW, 6, 289}, + {"break-spaces", (void *) LXB_CSS_VALUE_BREAK_SPACES, 12, 0}, + {"oklab", (void *) LXB_CSS_VALUE_OKLAB, 5, 291}, + {"slateblue", (void *) LXB_CSS_VALUE_SLATEBLUE, 9, 292}, + {"steelblue", (void *) LXB_CSS_VALUE_STEELBLUE, 9, 0}, + {"dashed", (void *) LXB_CSS_VALUE_DASHED, 6, 294}, + {"transparent", (void *) LXB_CSS_VALUE_TRANSPARENT, 11, 0}, + {"darkred", (void *) LXB_CSS_VALUE_DARKRED, 7, 296}, + {"olivedrab", (void *) LXB_CSS_VALUE_OLIVEDRAB, 9, 0}, + {"darkorchid", (void *) LXB_CSS_VALUE_DARKORCHID, 10, 0}, + {"darkgoldenrod", (void *) LXB_CSS_VALUE_DARKGOLDENROD, 13, 0}, + {"_number", (void *) LXB_CSS_VALUE__NUMBER, 7, 0}, + {"_integer", (void *) LXB_CSS_VALUE__INTEGER, 8, 0}, + {"dimgray", (void *) LXB_CSS_VALUE_DIMGRAY, 7, 302}, + {"dimgrey", (void *) LXB_CSS_VALUE_DIMGREY, 7, 0}, + {"darkgrey", (void *) LXB_CSS_VALUE_DARKGREY, 8, 0}, + {"x-large", (void *) LXB_CSS_VALUE_X_LARGE, 7, 0}, + {"horizontal-tb", (void *) LXB_CSS_VALUE_HORIZONTAL_TB, 13, 0}, + {"xxx-large", (void *) LXB_CSS_VALUE_XXX_LARGE, 9, 0}, + {"strict", (void *) LXB_CSS_VALUE_STRICT, 6, 308}, + {"darkslategray", (void *) LXB_CSS_VALUE_DARKSLATEGRAY, 13, 309}, + {"darkslategrey", (void *) LXB_CSS_VALUE_DARKSLATEGREY, 13, 0}, + {"brown", (void *) LXB_CSS_VALUE_BROWN, 5, 311}, + {"system-ui", (void *) LXB_CSS_VALUE_SYSTEM_UI, 9, 312}, + {"accentcolor", (void *) LXB_CSS_VALUE_ACCENTCOLOR, 11, 0}, + {"ruby-text", (void *) LXB_CSS_VALUE_RUBY_TEXT, 9, 0}, + {"cursive", (void *) LXB_CSS_VALUE_CURSIVE, 7, 0}, + {"moccasin", (void *) LXB_CSS_VALUE_MOCCASIN, 8, 316}, + {"collapse", (void *) LXB_CSS_VALUE_COLLAPSE, 8, 0}, + {"oblique", (void *) LXB_CSS_VALUE_OBLIQUE, 7, 318}, + {"cadetblue", (void *) LXB_CSS_VALUE_CADETBLUE, 9, 319}, + {"chocolate", (void *) LXB_CSS_VALUE_CHOCOLATE, 9, 0}, + {"chartreuse", (void *) LXB_CSS_VALUE_CHARTREUSE, 10, 321}, + {"capitalize", (void *) LXB_CSS_VALUE_CAPITALIZE, 10, 0}, + {"yellowgreen", (void *) LXB_CSS_VALUE_YELLOWGREEN, 11, 0}, + {"page", (void *) LXB_CSS_VALUE_PAGE, 4, 324}, + {"selecteditemtext", (void *) LXB_CSS_VALUE_SELECTEDITEMTEXT, 16, 0}, + {"cornflowerblue", (void *) LXB_CSS_VALUE_CORNFLOWERBLUE, 14, 326}, + {"mediumseagreen", (void *) LXB_CSS_VALUE_MEDIUMSEAGREEN, 14, 327}, + {"column-reverse", (void *) LXB_CSS_VALUE_COLUMN_REVERSE, 14, 0}, + {"ui-rounded", (void *) LXB_CSS_VALUE_UI_ROUNDED, 10, 0}, + {"medium", (void *) LXB_CSS_VALUE_MEDIUM, 6, 330}, + {"pre-line", (void *) LXB_CSS_VALUE_PRE_LINE, 8, 0}, + {"minimum", (void *) LXB_CSS_VALUE_MINIMUM, 7, 332}, + {"maximum", (void *) LXB_CSS_VALUE_MAXIMUM, 7, 333}, + {"mediumspringgreen", (void *) LXB_CSS_VALUE_MEDIUMSPRINGGREEN, 17, 0}, + {"mintcream", (void *) LXB_CSS_VALUE_MINTCREAM, 9, 335}, + {"ultra-expanded", (void *) LXB_CSS_VALUE_ULTRA_EXPANDED, 14, 0}, + {"paleturquoise", (void *) LXB_CSS_VALUE_PALETURQUOISE, 13, 0}, + {"larger", (void *) LXB_CSS_VALUE_LARGER, 6, 338}, + {"content-box", (void *) LXB_CSS_VALUE_CONTENT_BOX, 11, 339}, + {"lavenderblush", (void *) LXB_CSS_VALUE_LAVENDERBLUSH, 13, 0}, + {"indianred", (void *) LXB_CSS_VALUE_INDIANRED, 9, 0}, + {"inline-end", (void *) LXB_CSS_VALUE_INLINE_END, 10, 342}, + {"inter-word", (void *) LXB_CSS_VALUE_INTER_WORD, 10, 0}, + {"manual", (void *) LXB_CSS_VALUE_MANUAL, 6, 0}, + {"justify", (void *) LXB_CSS_VALUE_JUSTIFY, 7, 345}, + {"break-all", (void *) LXB_CSS_VALUE_BREAK_ALL, 9, 0}, + {"canvastext", (void *) LXB_CSS_VALUE_CANVASTEXT, 10, 347}, + {"mathematical", (void *) LXB_CSS_VALUE_MATHEMATICAL, 12, 0}, + {"full-width", (void *) LXB_CSS_VALUE_FULL_WIDTH, 10, 0}, + {"block", (void *) LXB_CSS_VALUE_BLOCK, 5, 350}, + {"blink", (void *) LXB_CSS_VALUE_BLINK, 5, 351}, + {"thistle", (void *) LXB_CSS_VALUE_THISTLE, 7, 0}, + {"turquoise", (void *) LXB_CSS_VALUE_TURQUOISE, 9, 0}, + {"uppercase", (void *) LXB_CSS_VALUE_UPPERCASE, 9, 0}, + {"text-top", (void *) LXB_CSS_VALUE_TEXT_TOP, 8, 0}, + {"ivory", (void *) LXB_CSS_VALUE_IVORY, 5, 356}, + {"inter-character", (void *) LXB_CSS_VALUE_INTER_CHARACTER, 15, 0}, + {"fantasy", (void *) LXB_CSS_VALUE_FANTASY, 7, 0}, + {"sans-serif", (void *) LXB_CSS_VALUE_SANS_SERIF, 10, 0}, + {"darkgreen", (void *) LXB_CSS_VALUE_DARKGREEN, 9, 0}, + {"table-row-group", (void *) LXB_CSS_VALUE_TABLE_ROW_GROUP, 15, 0}, + {"table-footer-group", (void *) LXB_CSS_VALUE_TABLE_FOOTER_GROUP, 18, 362}, + {"table-column-group", (void *) LXB_CSS_VALUE_TABLE_COLUMN_GROUP, 18, 0}, + {"grey", (void *) LXB_CSS_VALUE_GREY, 4, 364}, + {"vertical-rl", (void *) LXB_CSS_VALUE_VERTICAL_RL, 11, 0}, + {"both", (void *) LXB_CSS_VALUE_BOTH, 4, 0}, + {"_percentage", (void *) LXB_CSS_VALUE__PERCENTAGE, 11, 0}, + {"ui-serif", (void *) LXB_CSS_VALUE_UI_SERIF, 8, 0}, + {"left", (void *) LXB_CSS_VALUE_LEFT, 4, 369}, + {"ui-sans-serif", (void *) LXB_CSS_VALUE_UI_SANS_SERIF, 13, 0}, + {"condensed", (void *) LXB_CSS_VALUE_CONDENSED, 9, 0}, + {"ruby-text-container", (void *) LXB_CSS_VALUE_RUBY_TEXT_CONTAINER, 19, 0}, + {"orangered", (void *) LXB_CSS_VALUE_ORANGERED, 9, 0} +}; + + +#endif /* LXB_CSS_VALUE_RES_H */ diff --git a/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/ports/posix/lexbor/core/memory.c b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/ports/posix/lexbor/core/memory.c new file mode 100644 index 0000000..038e040 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/lexbor/lexbor/ports/posix/lexbor/core/memory.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 Alexander Borisov + * + * Author: Alexander Borisov + */ + +#include "lexbor/core/base.h" + +static lexbor_memory_malloc_f lexbor_memory_malloc = malloc; +static lexbor_memory_realloc_f lexbor_memory_realloc = realloc; +static lexbor_memory_calloc_f lexbor_memory_calloc = calloc; +static lexbor_memory_free_f lexbor_memory_free = free; + +void * +lexbor_malloc(size_t size) +{ + return lexbor_memory_malloc(size); +} + +void * +lexbor_realloc(void *dst, size_t size) +{ + return lexbor_memory_realloc(dst, size); +} + +void * +lexbor_calloc(size_t num, size_t size) +{ + return lexbor_memory_calloc(num, size); +} + +void * +lexbor_free(void *dst) +{ + lexbor_memory_free(dst); + return NULL; +} + +lxb_status_t +lexbor_memory_setup(lexbor_memory_malloc_f new_malloc, lexbor_memory_realloc_f new_realloc, + lexbor_memory_calloc_f new_calloc, lexbor_memory_free_f new_free) +{ + if (new_malloc == NULL || new_realloc == NULL || new_calloc == NULL || new_free == NULL) { + return LXB_STATUS_ERROR_OBJECT_IS_NULL; + } + + lexbor_memory_malloc = new_malloc; + lexbor_memory_realloc = new_realloc; + lexbor_memory_calloc = new_calloc; + lexbor_memory_free = new_free; + + return LXB_STATUS_OK; +} diff --git a/experiments/css/crates/css-compiler/vendor/stubs/inttypes.h b/experiments/css/crates/css-compiler/vendor/stubs/inttypes.h new file mode 100644 index 0000000..4c31f17 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/inttypes.h @@ -0,0 +1,4 @@ +#ifndef INTTYPES_H +#define INTTYPES_H +#include +#endif diff --git a/experiments/css/crates/css-compiler/vendor/stubs/math.h b/experiments/css/crates/css-compiler/vendor/stubs/math.h new file mode 100644 index 0000000..a7a99fc --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/math.h @@ -0,0 +1,12 @@ +#ifndef MATH_H +#define MATH_H +#define INFINITY (__builtin_inff()) +#define NAN (__builtin_nanf("")) +#define signbit(x) (__builtin_signbit(x)) +double pow(double, double); +double fmod(double, double); +double floor(double); +double ceil(double); +double round(double); +double log10(double); +#endif diff --git a/experiments/css/crates/css-compiler/vendor/stubs/memory.h b/experiments/css/crates/css-compiler/vendor/stubs/memory.h new file mode 100644 index 0000000..79418b8 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/memory.h @@ -0,0 +1,4 @@ +#ifndef MEMORY_H +#define MEMORY_H +#include +#endif diff --git a/experiments/css/crates/css-compiler/vendor/stubs/stdbool.h b/experiments/css/crates/css-compiler/vendor/stubs/stdbool.h new file mode 100644 index 0000000..81afced --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/stdbool.h @@ -0,0 +1,6 @@ +#ifndef STDBOOL_H +#define STDBOOL_H +#define bool _Bool +#define true 1 +#define false 0 +#endif diff --git a/experiments/css/crates/css-compiler/vendor/stubs/stdio.h b/experiments/css/crates/css-compiler/vendor/stubs/stdio.h new file mode 100644 index 0000000..acee9e0 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/stdio.h @@ -0,0 +1,5 @@ +#ifndef STDIO_H +#define STDIO_H +int printf(const char *, ...); +int snprintf(char *, unsigned long, const char *, ...); +#endif diff --git a/experiments/css/crates/css-compiler/vendor/stubs/stdlib.h b/experiments/css/crates/css-compiler/vendor/stubs/stdlib.h new file mode 100644 index 0000000..0f70d4b --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/stdlib.h @@ -0,0 +1,9 @@ +#ifndef STDLIB_H +#define STDLIB_H +void *malloc(unsigned long); +void *calloc(unsigned long, unsigned long); +void *realloc(void *, unsigned long); +void free(void *); +void abort(void); +void exit(int); +#endif diff --git a/experiments/css/crates/css-compiler/vendor/stubs/string.h b/experiments/css/crates/css-compiler/vendor/stubs/string.h new file mode 100644 index 0000000..3389ea0 --- /dev/null +++ b/experiments/css/crates/css-compiler/vendor/stubs/string.h @@ -0,0 +1,14 @@ +#ifndef STRING_H +#define STRING_H +void *memcpy(void *, const void *, unsigned long); +void *memmove(void *, const void *, unsigned long); +void *memset(void *, int, unsigned long); +int memcmp(const void *, const void *, unsigned long); +unsigned long strlen(const char *); +int strcmp(const char *, const char *); +int strncmp(const char *, const char *, unsigned long); +char *strchr(const char *, int); +void *memchr(const void *, int, unsigned long); +char *strcpy(char *, const char *); +char *strncpy(char *, const char *, unsigned long); +#endif diff --git a/experiments/css/crates/css-conformance/Cargo.toml b/experiments/css/crates/css-conformance/Cargo.toml new file mode 100644 index 0000000..3d34db1 --- /dev/null +++ b/experiments/css/crates/css-conformance/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "bombshell-css-conformance" +version = "0.1.0" +description = "Conformance corpus for the Bombshell CSS pipeline" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true +publish = false + +[dev-dependencies] +bombshell-css-core = { workspace = true } +bombshell-css-compiler = { workspace = true } +bombshell-css-runtime = { workspace = true } diff --git a/experiments/css/crates/css-conformance/cases/cascade/01-layers.css b/experiments/css/crates/css-conformance/cases/cascade/01-layers.css new file mode 100644 index 0000000..c852884 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/cascade/01-layers.css @@ -0,0 +1,15 @@ +/* Cascade 5: layer declaration order, nested layers, unlayered beats layered. */ +@layer a, b.c; +@layer a { + .x { + color: red; + } +} +@layer b.c { + .x { + color: green; + } +} +.x { + color: blue; +} diff --git a/experiments/css/crates/css-conformance/cases/cascade/02-important.css b/experiments/css/crates/css-conformance/cases/cascade/02-important.css new file mode 100644 index 0000000..e62014b --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/cascade/02-important.css @@ -0,0 +1,7 @@ +/* Importance and origin interactions (evaluated across origins by the runtime). */ +.x { + color: red !important; +} +.x { + color: green; +} diff --git a/experiments/css/crates/css-conformance/cases/colors/01-modern.css b/experiments/css/crates/css-conformance/cases/colors/01-modern.css new file mode 100644 index 0000000..f952714 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/colors/01-modern.css @@ -0,0 +1,30 @@ +/* CSS Color 4/5: wide-gamut spaces, mixing, relative syntax, light-dark(). + Values are validated and canonicalized by lightningcss; colors are not + converted or gamut-mapped by the runtime yet. */ +.a { + color: oklch(70% 0.2 40); +} +.b { + color: oklab(0.5 -0.1 0.1 / 50%); +} +.c { + color: lab(50% 20 -30); +} +.d { + color: lch(50% 40 120deg); +} +.e { + color: color(display-p3 1 0.5 0); +} +.f { + color: color-mix(in oklab, red 40%, blue); +} +.g { + color: rgb(from orange r g b / 50%); +} +.h { + color: light-dark(white, black); +} +.i { + color: hsl(120deg 75% 50%); +} diff --git a/experiments/css/crates/css-conformance/cases/colors/02-hex.css b/experiments/css/crates/css-conformance/cases/colors/02-hex.css new file mode 100644 index 0000000..1ea4c6f --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/colors/02-hex.css @@ -0,0 +1,28 @@ +/* Plain hex colors in every digit-count form, across the properties the + report called out. Hex payloads that read as identifiers (#fff) tokenize + as IDHash; digit-leading payloads (#333) tokenize as Hash — both must + reach the IR and the computed style. */ +.a { + color: #fff; +} +.b { + color: #ff8800; +} +.c { + color: #ffffff; +} +.d { + color: #fffe; +} +.e { + color: #ff8800ff; +} +.f { + border-color: #333; +} +.g { + border-color: #333333; +} +.h { + background-color: #101010; +} diff --git a/experiments/css/crates/css-conformance/cases/conditions/01-media.css b/experiments/css/crates/css-conformance/cases/conditions/01-media.css new file mode 100644 index 0000000..b5549c9 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/conditions/01-media.css @@ -0,0 +1,26 @@ +/* Media Queries Level 4: range syntax, boolean and discrete features, OR lists. */ +@media (400px <= width <= 800px) { + .a { + color: red; + } +} +@media (prefers-color-scheme: dark) { + .a { + color: green; + } +} +@media (prefers-reduced-motion: reduce) { + .a { + color: blue; + } +} +@media screen and (not (hover)) { + .a { + color: orange; + } +} +@media (min-width: 400px), (max-height: 10em) { + .a { + color: purple; + } +} diff --git a/experiments/css/crates/css-conformance/cases/conditions/02-container.css b/experiments/css/crates/css-conformance/cases/conditions/02-container.css new file mode 100644 index 0000000..66fd4ee --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/conditions/02-container.css @@ -0,0 +1,30 @@ +/* CSS Containment 3: named/anonymous containers, range and boolean size queries. */ +.panel { + container-type: inline-size; + container-name: panel; +} +@container panel (inline-size > 45em) { + .a { + color: red; + } +} +@container (width < 200px) { + .a { + color: green; + } +} +@container card (height >= 10em) { + .a { + color: blue; + } +} +@container (aspect-ratio > 5) { + .a { + color: orange; + } +} +@container panel style(color: red) { + .a { + color: purple; + } +} diff --git a/experiments/css/crates/css-conformance/cases/conditions/03-supports.css b/experiments/css/crates/css-conformance/cases/conditions/03-supports.css new file mode 100644 index 0000000..007eb89 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/conditions/03-supports.css @@ -0,0 +1,21 @@ +/* Conditional rules: @supports declarations, selector(), and/or/not algebra. */ +@supports (color: oklch(70% 0.2 40)) { + .a { + color: red; + } +} +@supports selector(:has(> .b)) { + .a { + color: green; + } +} +@supports not (bogus-property: 1px) { + .a { + color: blue; + } +} +@supports (display: grid) and (color: red) { + .a { + color: orange; + } +} diff --git a/experiments/css/crates/css-conformance/cases/nesting/01-basic.css b/experiments/css/crates/css-conformance/cases/nesting/01-basic.css new file mode 100644 index 0000000..4b210fa --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/nesting/01-basic.css @@ -0,0 +1,13 @@ +/* CSS Nesting: implicit descendant nesting and explicit `&`. + Structure adapted from CSS Nesting Module (csswg-drafts/css-nesting-1) examples. */ +.card { + color: oklch(70% 0.2 40); + + & > .title { + font-weight: bold; + } + + .body { + color: color-mix(in oklab, red 40%, blue); + } +} diff --git a/experiments/css/crates/css-conformance/cases/nesting/02-deep-nesting.css b/experiments/css/crates/css-conformance/cases/nesting/02-deep-nesting.css new file mode 100644 index 0000000..e4ee902 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/nesting/02-deep-nesting.css @@ -0,0 +1,10 @@ +/* CSS Nesting: multi-level expansion with mid-compound `&` and sibling context. */ +.a { + .b { + &.c { + :not(&) { + outline: 1px; + } + } + } +} diff --git a/experiments/css/crates/css-conformance/cases/nesting/03-nested-conditions.css b/experiments/css/crates/css-conformance/cases/nesting/03-nested-conditions.css new file mode 100644 index 0000000..4df6c92 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/nesting/03-nested-conditions.css @@ -0,0 +1,16 @@ +/* CSS Nesting: group rules inside style rules keep the nesting context. */ +.panel { + padding: 4px; + + @media (min-width: 24em) { + .item { + color: red; + } + } + + @container (inline-size > 20em) { + .item { + color: blue; + } + } +} diff --git a/experiments/css/crates/css-conformance/cases/nesting/04-nest-at-rule.css b/experiments/css/crates/css-conformance/cases/nesting/04-nest-at-rule.css new file mode 100644 index 0000000..c7aae30 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/nesting/04-nest-at-rule.css @@ -0,0 +1,8 @@ +/* Legacy nesting via @nest (requires an explicit & prefix). */ +.a { + color: red; + + @nest & .b { + color: blue; + } +} diff --git a/experiments/css/crates/css-conformance/cases/selectors/01-level4.css b/experiments/css/crates/css-conformance/cases/selectors/01-level4.css new file mode 100644 index 0000000..928591b --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/selectors/01-level4.css @@ -0,0 +1,22 @@ +/* Selectors Level 4: :is, :where, :not (complex args), :has, :nth-child(An+B of S). */ +:is(.a, .b) > .c { + color: red; +} +:where(#x, .y) .z { + color: green; +} +.item:not(.skip):not(.list > *) { + color: blue; +} +.row:has(> .col) { + outline: 1px; +} +.item:nth-child(2n + 1 of .tagged) { + color: yellow; +} +.item:nth-child(-n + 3) { + text-indent: 4px; +} +p:has(+ h2) { + margin: 4px; +} diff --git a/experiments/css/crates/css-conformance/cases/selectors/02-attributes.css b/experiments/css/crates/css-conformance/cases/selectors/02-attributes.css new file mode 100644 index 0000000..a3deb73 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/selectors/02-attributes.css @@ -0,0 +1,19 @@ +/* Selectors Level 4 attribute matching, including case flags. */ +[data-x^='pre'] { + color: red; +} +[title*='word' i] { + color: green; +} +[href$='.pdf'] { + color: blue; +} +[lang|='en'] { + color: orange; +} +[data-y~='item' s] { + color: purple; +} +[hidden] { + visibility: hidden; +} diff --git a/experiments/css/crates/css-conformance/cases/selectors/03-combinators.css b/experiments/css/crates/css-conformance/cases/selectors/03-combinators.css new file mode 100644 index 0000000..df2c1c5 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/selectors/03-combinators.css @@ -0,0 +1,10 @@ +/* Descendant, child, next-sibling, later-sibling, and mixed chains. */ +.a .b .c { + color: red; +} +.a > .b + .c ~ .d { + color: green; +} +*.item { + color: blue; +} diff --git a/experiments/css/crates/css-conformance/cases/values/01-var.css b/experiments/css/crates/css-conformance/cases/values/01-var.css new file mode 100644 index 0000000..0732f47 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/values/01-var.css @@ -0,0 +1,16 @@ +/* Custom properties, var() with fallbacks, substitution through nesting. */ +:root { + --brand: oklch(70% 0.2 40); + --gap: 8px; +} +.a { + color: var(--brand); + margin: var(--gap, 4px); +} +.b { + --gap: 2px; + padding: var(--gap); +} +.c { + color: var(--missing, var(--brand)); +} diff --git a/experiments/css/crates/css-conformance/cases/values/02-single-line.css b/experiments/css/crates/css-conformance/cases/values/02-single-line.css new file mode 100644 index 0000000..21dcc07 --- /dev/null +++ b/experiments/css/crates/css-conformance/cases/values/02-single-line.css @@ -0,0 +1,21 @@ +/* Single-line (minified) stylesheets: a rule body that opens and closes on + the same line must survive the shim's event stream, including comma + selectors, nesting, and grouping at-rules. */ +.card { + color: #fff; + padding: 4px; +} +.a, +.b { + color: red; +} +.x { + & > .y { + color: blue; + } +} +@media (min-width: 24em) { + .z { + color: green; + } +} diff --git a/experiments/css/crates/css-conformance/tests/behavior.rs b/experiments/css/crates/css-conformance/tests/behavior.rs new file mode 100644 index 0000000..efd58af --- /dev/null +++ b/experiments/css/crates/css-conformance/tests/behavior.rs @@ -0,0 +1,360 @@ +//! Behavior conformance: compile corpus cases and resolve computed styles +//! against tree snapshots, asserting the cascade semantics the corpus pins. + +use std::fs; +use std::path::Path; + +use bombshell_css_compiler::{CompileOptions, compile}; +use bombshell_css_core::{ColorScheme, Environment, NO_PARENT, NodeSnapshot, Origin, TreeSnapshot}; +use bombshell_css_runtime::{Stylesheet, compute}; + +fn read_case(rel: &str) -> String { + fs::read_to_string( + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("cases") + .join(rel), + ) + .expect("case file") +} + +/// An owned compiled case; [`Case::sheet`] borrows the parsed stylesheet +/// from the IR it keeps alive. +struct Case { + ir: bombshell_css_core::CompiledStylesheet, +} + +impl Case { + fn sheet(&self) -> Stylesheet<'_> { + Stylesheet::from_ir(&self.ir, 0) + } +} + +fn load(css: &str) -> Case { + let output = compile(css, Origin::Author, CompileOptions::default()); + assert!( + !output + .diagnostics + .iter() + .any(|d| d.severity == bombshell_css_core::Severity::Error), + "{:?}", + output.diagnostics + ); + Case { + ir: output.sheet.expect("sheet"), + } +} + +fn tree(nodes: Vec, parents: Vec) -> TreeSnapshot { + TreeSnapshot { nodes, parents } +} + +fn classed(tag: &str, classes: &[&str]) -> NodeSnapshot { + NodeSnapshot { + tag: tag.to_string(), + classes: classes.iter().map(|c| c.to_string()).collect(), + ..Default::default() + } +} + +fn get<'a>(style: &'a bombshell_css_runtime::ComputedStyle, name: &str) -> &'a str { + style + .get(name) + .unwrap_or_else(|| panic!("missing {name}: {:?}", style.declarations)) +} + +#[test] +fn nesting_case_styles_the_tree() { + let sheet = load(&read_case("nesting/01-basic.css")); + let sheet = sheet.sheet(); + let t = tree( + vec![ + classed("card", &["card"]), + classed("title", &["title"]), + classed("body", &["body"]), + ], + vec![NO_PARENT, 0, 0], + ); + let env = Environment::default(); + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s, "font-weight"), "700"); + // `color` inherits from .card; `.card .body` does not apply to the title. + assert_eq!(get(&s, "color"), "oklch(70% .2 40)"); + let s = compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(); + // lightningcss canonicalizes the static color-mix() to a resolved oklab. + let color = get(&s, "color"); + assert!( + color.starts_with("oklab(") || color.starts_with("color-mix("), + "unexpected color {color}" + ); + assert_ne!(color, "oklch(70% .2 40)"); +} + +#[test] +fn level4_selectors_match() { + let sheet = load(&read_case("selectors/01-level4.css")); + let sheet = sheet.sheet(); + let t = tree( + vec![ + classed("row", &["row"]), + classed("col", &["col"]), + classed("item", &["item", "tagged"]), + classed("item", &["item"]), + ], + vec![NO_PARENT, 0, 0, 0], + ); + let env = Environment::default(); + // .row:has(> .col) matches the row. + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + assert_eq!(get(&s, "outline"), "1px"); + // nth-child(odd of .tagged): node 2 is the 1st tagged child → matches. + let s = compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(); + assert_eq!(get(&s, "color"), "#ff0"); + // node 3 is the 3rd child → nth-child(-n+3) applies (blue outranks it on + // `color` specificity, so the corpus rule uses a distinct property). + let s = compute(std::slice::from_ref(&&sheet), &t, 3, &env).unwrap(); + assert_eq!(get(&s, "text-indent"), "4px"); +} + +#[test] +fn media_ranges_and_or_lists() { + let sheet = load(&read_case("conditions/01-media.css")); + let sheet = sheet.sheet(); + let t = tree(vec![classed("a", &["a"])], vec![NO_PARENT]); + let env = Environment { + viewport_width: Some(600.0), + viewport_height: Some(300.0), + ..Default::default() + }; + // The corpus stack: interval red, not-hover orange, and min-width purple + // all match at 600px; later source order wins. + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(), + "color" + ), + "purple" + ); + + // Interval semantics in isolation. + let interval = load("@media (400px <= width <= 800px) { .a { color: red } }"); + let interval = interval.sheet(); + assert_eq!( + get( + &compute(std::slice::from_ref(&&interval), &t, 0, &env).unwrap(), + "color" + ), + "red" + ); + let small = Environment { + viewport_width: Some(300.0), + ..Default::default() + }; + assert!( + compute(std::slice::from_ref(&&interval), &t, 0, &small) + .unwrap() + .get("color") + .is_none() + ); + let edge = Environment { + viewport_width: Some(800.0), + ..Default::default() + }; + assert_eq!( + get(&compute(&[&interval], &t, 0, &edge).unwrap(), "color"), + "red" + ); + + // The OR list matches on max-height 10em (160px) alone. + let small_height = Environment { + viewport_width: Some(300.0), + viewport_height: Some(96.0), + ..Default::default() + }; + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &small_height).unwrap(), + "color" + ), + "purple" + ); +} + +#[test] +fn dark_scheme_reaches_the_runtime() { + let sheet = load(&read_case("conditions/01-media.css")); + let sheet = sheet.sheet(); + let t = tree(vec![classed("a", &["a"])], vec![NO_PARENT]); + let env = Environment { + color_scheme: ColorScheme::Dark, + ..Default::default() + }; + // Dark-scheme green matches, but `screen and (not (hover))` also matches + // and appears later in source order. + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(), + "color" + ), + "orange" + ); + + // Dark scheme in isolation. + let dark = load("@media (prefers-color-scheme: dark) { .a { color: green } }"); + let dark = dark.sheet(); + assert_eq!( + get( + &compute(std::slice::from_ref(&&dark), &t, 0, &env).unwrap(), + "color" + ), + "green" + ); +} + +#[test] +fn container_corpus_case() { + let sheet = load(&read_case("conditions/02-container.css")); + let sheet = sheet.sheet(); + let t = tree( + vec![ + { + let mut n = classed("panel", &["panel"]); + n.width = Some(800.0); + n.height = Some(200.0); + n + }, + classed("a", &["a"]), + ], + vec![NO_PARENT, 0], + ); + let env = Environment::default(); + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + // inline-size 800 > 45em (720px) → red; width 800 > 200 → the anonymous + // container query would win too but it targets `(width < 200px)` → no. + assert_eq!(get(&s, "color"), "red"); +} + +#[test] +fn var_case_resolves_through_the_tree() { + let sheet = load(&read_case("values/01-var.css")); + let sheet = sheet.sheet(); + let t = tree( + vec![ + classed("root", &["root"]), + classed("a", &["a"]), + classed("b", &["b"]), + classed("c", &["c"]), + ], + vec![NO_PARENT, 0, 0, 0], + ); + let env = Environment::default(); + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s, "color"), "oklch(70% .2 40)"); + assert_eq!(get(&s, "margin"), "8px"); + let s = compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(); + assert_eq!(get(&s, "padding"), "2px"); + let s = compute(std::slice::from_ref(&&sheet), &t, 3, &env).unwrap(); + assert_eq!(get(&s, "color"), "oklch(70% .2 40)"); +} + +#[test] +fn layer_order_matches_first_appearance() { + let sheet = load(&read_case("cascade/01-layers.css")); + let sheet = sheet.sheet(); + let t = tree(vec![classed("x", &["x"])], vec![NO_PARENT]); + let env = Environment::default(); + // Unlayered rule beats both layered rules. + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(), + "color" + ), + "#00f" + ); +} + +#[test] +fn important_beats_source_order() { + let sheet = load(&read_case("cascade/02-important.css")); + let sheet = sheet.sheet(); + let t = tree(vec![classed("x", &["x"])], vec![NO_PARENT]); + let env = Environment::default(); + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(), + "color" + ), + "red" + ); +} + +#[test] +fn hex_colors_reach_computed_styles() { + let sheet = load(&read_case("colors/02-hex.css")); + let sheet = sheet.sheet(); + let t = tree( + vec![classed("x", &["a"]), classed("y", &["f"])], + vec![NO_PARENT, NO_PARENT], + ); + let env = Environment::default(); + // 3-digit hex on `color`… + let a = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + assert_eq!(get(&a, "color"), "#fff"); + // …and on `border-color`. + let f = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&f, "border-color"), "#333"); +} + +#[test] +fn single_line_rules_reach_computed_styles() { + let sheet = load(&read_case("values/02-single-line.css")); + let sheet = sheet.sheet(); + let t = tree( + vec![classed("card", &["card", "x"]), classed("y", &["y"])], + vec![NO_PARENT, 0], + ); + let env = Environment::default(); + // Both declarations of the single-line rule survive. + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "#fff"); + assert_eq!(get(&s, "padding"), "4px"); + // The nested rule opened and closed on the same line as its parent. + // (`blue` canonicalizes to `#00f`: equal-length ties go to hex.) + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s, "color"), "#00f"); +} + +/// The wasm adapter drives compile → prepare → compute-tree → compile / +/// prepare-again inside one component instance; hosts must see live results +/// at every step. This pins the library-level property that makes that +/// sequence safe: the compiler and the stylesheet loader carry no state +/// across calls. (The component-level sequence is asserted in +/// `demo/smoke.mjs` — an apparent cross-call poison there was traced to a +/// host misreading the `option<>` discriminant over canonical-ABI padding, +/// not to engine state.) +#[test] +fn compile_and_prepare_survive_compute_tree() { + use bombshell_css_core::{decode_ir, encode_ir}; + + let env = Environment::default(); + let first = load(&read_case("colors/02-hex.css")); + let sheet = first.sheet(); + let t = tree( + vec![classed("x", &["a"]), classed("y", &["f"])], + vec![NO_PARENT, NO_PARENT], + ); + + bombshell_css_runtime::cascade::compute_tree(std::slice::from_ref(&&sheet), &t, &env, &[]); + + // A later compile walks the same pipeline: identical source, identical IR. + let second = load(&read_case("colors/02-hex.css")); + assert_eq!(encode_ir(&first.ir), encode_ir(&second.ir)); + + // A later prepare of already-prepared IR bytes still decodes, loads, + // and computes. + let decoded = decode_ir(&encode_ir(&first.ir)).expect("re-encoded IR decodes"); + let reloaded = Stylesheet::from_ir(&decoded, 0); + let s = compute(std::slice::from_ref(&&reloaded), &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "#fff"); + let f = compute(std::slice::from_ref(&&reloaded), &t, 1, &env).unwrap(); + assert_eq!(get(&f, "border-color"), "#333"); +} diff --git a/experiments/css/crates/css-conformance/tests/conformance.rs b/experiments/css/crates/css-conformance/tests/conformance.rs new file mode 100644 index 0000000..8b181ce --- /dev/null +++ b/experiments/css/crates/css-conformance/tests/conformance.rs @@ -0,0 +1,215 @@ +//! Conformance corpus runner. +//! +//! Every `cases/**/*.css` must either compile cleanly or be marked with a +//! sibling `.error` file naming the expected diagnostic code. The compiled +//! IR must round-trip through the wire codec. Semantic behavior (matching, +//! cascade, conditions) is covered by `tests/behavior.rs`. + +use std::fs; +use std::path::{Path, PathBuf}; + +use bombshell_css_compiler::{CompileOptions, compile}; +use bombshell_css_core::{Origin, decode_ir, encode_ir}; + +fn case_dirs() -> Vec { + let root = Path::new(env!("CARGO_MANIFEST_DIR")).join("cases"); + let mut dirs = vec![root.clone()]; + for entry in fs::read_dir(&root).expect("cases directory") { + let path = entry.expect("entry").path(); + if path.is_dir() { + dirs.push(path); + } + } + dirs +} + +fn case_files() -> Vec { + let mut files = Vec::new(); + for dir in case_dirs() { + for entry in fs::read_dir(&dir).expect("readable") { + let path = entry.expect("entry").path(); + if path.extension().and_then(|e| e.to_str()) == Some("css") { + files.push(path); + } + } + } + files.sort(); + files +} + +#[test] +fn corpus_compiles_and_round_trips() { + let files = case_files(); + assert!( + files.len() >= 12, + "expected a non-trivial corpus, found {files:?}" + ); + for path in &files { + let css = fs::read_to_string(path).expect("readable case"); + let error_marker = path.with_extension("error"); + let options = CompileOptions { + error_recovery: false, + ..CompileOptions::default() + }; + let output = compile(&css, Origin::Author, options); + + if error_marker.exists() { + let expected = fs::read_to_string(&error_marker) + .expect("readable marker") + .trim() + .to_string(); + assert!( + output.sheet.is_none(), + "case {} unexpectedly compiled; expected error {expected}", + path.display() + ); + assert!( + output.diagnostics.iter().any(|d| d.code == expected), + "case {} missing diagnostic code {expected}: {:?}", + path.display(), + output.diagnostics + ); + continue; + } + + assert!( + !output + .diagnostics + .iter() + .any(|d| d.severity == bombshell_css_core::Severity::Error), + "case {} produced errors: {:?}", + path.display(), + output.diagnostics + ); + let sheet = output.sheet.expect("sheet present"); + assert_eq!(sheet.version, bombshell_css_core::IR_VERSION); + let bytes = encode_ir(&sheet); + let decoded = decode_ir(&bytes).expect("round trip"); + assert_eq!(decoded, sheet, "case {} IR mismatch", path.display()); + assert!( + !sheet.rules.is_empty(), + "case {} produced no rules", + path.display() + ); + } +} + +#[test] +fn nesting_expands_against_the_spec() { + let css = read_case("nesting/01-basic.css"); + let sheet = compile_strict(&css); + let selectors: Vec<&str> = sheet.rules.iter().map(|r| r.selector.as_str()).collect(); + // Implicit nesting (`.body` without `&`) is a descendant relationship. + assert_eq!(selectors, vec![".card", ".card>.title", ".card .body"]); +} + +#[test] +fn deep_nesting_expands_every_ampersand() { + let css = read_case("nesting/02-deep-nesting.css"); + let sheet = compile_strict(&css); + let selectors: Vec<&str> = sheet.rules.iter().map(|r| r.selector.as_str()).collect(); + // Only the innermost rule carries declarations; ancestors without + // declarations collapse. `:not(&)` substitutes the fully expanded parent. + assert_eq!(selectors, vec![":not(.a .b.c)"]); +} + +#[test] +fn nested_conditions_keep_the_style_context() { + let css = read_case("nesting/03-nested-conditions.css"); + let sheet = compile_strict(&css); + assert_eq!(sheet.rules.len(), 3); + assert_eq!(sheet.rules[0].selector, ".panel"); + assert!(sheet.rules[0].media.is_empty()); + assert_eq!(sheet.rules[1].selector, ".panel .item"); + assert_eq!(sheet.rules[1].media.len(), 1); + assert_eq!(sheet.rules[2].selector, ".panel .item"); + assert_eq!(sheet.rules[2].containers.len(), 1); +} + +#[test] +fn level4_selectors_are_preserved() { + let css = read_case("selectors/01-level4.css"); + let sheet = compile_strict(&css); + let selectors: Vec<&str> = sheet.rules.iter().map(|r| r.selector.as_str()).collect(); + assert_eq!( + selectors, + vec![ + ":is(.a,.b)>.c", + ":where(#x,.y) .z", + ".item:not(.skip):not(.list>*)", + ".row:has(>.col)", + ".item:nth-child(odd of .tagged)", + ".item:nth-child(-n+3)", + "p:has(+h2)", + ] + ); +} + +#[test] +fn conditions_are_typed_in_the_ir() { + let css = read_case("conditions/01-media.css"); + let sheet = compile_strict(&css); + assert_eq!(sheet.rules.len(), 5); + // The interval form canonicalizes. + match &sheet.rules[0].media[0] { + bombshell_css_core::MediaCondition::Feature(feature) => { + assert_eq!(feature.name, "width"); + assert!(matches!( + feature.kind, + bombshell_css_core::FeatureKind::Interval { .. } + )); + } + other => panic!("unexpected media condition {other:?}"), + } + // The comma list becomes an OR branch. + match &sheet.rules[4].media[0] { + bombshell_css_core::MediaCondition::Or(branches) => assert_eq!(branches.len(), 2), + other => panic!("expected OR list, got {other:?}"), + } +} + +#[test] +fn layers_are_registered_in_first_appearance_order() { + let css = read_case("cascade/01-layers.css"); + let sheet = compile_strict(&css); + assert_eq!( + sheet.layer_order, + vec![ + vec!["a".to_string()], + vec!["b".to_string()], + vec!["b".to_string(), "c".to_string()], + ] + ); + assert_eq!( + sheet.rules[0].layer.as_deref(), + Some(["a".to_string()].as_slice()) + ); + assert_eq!( + sheet.rules[1].layer.as_deref(), + Some(["b".to_string(), "c".to_string()].as_slice()) + ); + assert_eq!(sheet.rules[2].layer, None); +} + +#[test] +fn important_is_tracked_per_declaration() { + let css = read_case("cascade/02-important.css"); + let sheet = compile_strict(&css); + assert!(sheet.rules[0].declarations[0].important); + assert!(!sheet.rules[1].declarations[0].important); +} + +fn read_case(rel: &str) -> String { + fs::read_to_string( + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("cases") + .join(rel), + ) + .expect("case file") +} + +fn compile_strict(css: &str) -> bombshell_css_core::CompiledStylesheet { + let output = compile(css, Origin::Author, CompileOptions::default()); + assert!(output.diagnostics.is_empty(), "{:?}", output.diagnostics); + output.sheet.expect("sheet") +} diff --git a/experiments/css/crates/css-core/Cargo.toml b/experiments/css/crates/css-core/Cargo.toml new file mode 100644 index 0000000..2eac1f4 --- /dev/null +++ b/experiments/css/crates/css-core/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "bombshell-css-core" +version = "0.1.0" +description = "Shared contracts, typed CSS IR, and codec for the Bombshell CSS pipeline" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[features] +default = ["selectors"] +selectors = ["dep:parcel_selectors", "dep:cssparser"] + +[dependencies] +serde = { workspace = true } +postcard = { workspace = true } +cssparser = { workspace = true, optional = true } +parcel_selectors = { workspace = true, optional = true } diff --git a/experiments/css/crates/css-core/src/lib.rs b/experiments/css/crates/css-core/src/lib.rs new file mode 100644 index 0000000..3980c9b --- /dev/null +++ b/experiments/css/crates/css-core/src/lib.rs @@ -0,0 +1,469 @@ +//! Shared contracts for the Bombshell CSS pipeline. +//! +//! The IR/DOM-snapshot half is intentionally dependency-light (`serde` + +//! `postcard`, both `no_std`-capable). The selector engine lives here too, +//! behind the default `selectors` feature (which pulls `cssparser` and +//! `parcel_selectors`): both the compiler and the runtime drive this one +//! parser so they can never disagree about what a valid selector is. + +#![cfg_attr(not(feature = "selectors"), no_std)] + +extern crate alloc; + +#[cfg(feature = "selectors")] +pub mod selectors; + +#[cfg(feature = "selectors")] +pub mod tokens; + +use alloc::{boxed::Box, string::String, vec::Vec}; +use serde::{Deserialize, Serialize}; + +/// Version of the compiled stylesheet IR. Bump when the wire format changes +/// incompatibly; runtimes must reject unknown versions. +pub const IR_VERSION: u16 = 2; + +/// The sentinel used in [`TreeSnapshot::parents`] for "no parent" (a root). +pub const NO_PARENT: u32 = u32::MAX; + +/// Cascade origin of a stylesheet, mirroring the CSS cascade order. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Origin { + /// Rules from the user agent stylesheet. + UserAgent, + /// Rules supplied by the user. + User, + /// Rules supplied by the document/author. + Author, +} + +/// Severity of a [`Diagnostic`]. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Severity { + /// A fatal or non-recoverable problem. + Error, + /// A recoverable problem worth reporting to authors. + Warning, +} + +/// A compile or runtime diagnostic. Messages are stable text; `code` is a +/// machine-readable identifier intended to grow over time. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Diagnostic { + pub severity: Severity, + pub code: String, + pub message: String, +} + +impl Diagnostic { + pub fn error(code: &str, message: impl Into) -> Self { + Diagnostic { + severity: Severity::Error, + code: code.into(), + message: message.into(), + } + } + + pub fn warning(code: &str, message: impl Into) -> Self { + Diagnostic { + severity: Severity::Warning, + code: code.into(), + message: message.into(), + } + } +} + +/// A flat node snapshot describing one element of the host tree. +/// +/// The host (tty/UI) ships the whole subtree it wants styled as a flat, +/// document-ordered node list plus a parent-index vector. This shape is +/// recursion-free (WIT-friendly) yet complete enough for structural +/// selectors, sibling combinators, `:has()` traversal, and container lookups. +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct NodeSnapshot { + /// Element tag name, e.g. `box`, `text`. Case-sensitive. + pub tag: String, + /// Element id, if any. + pub id: Option, + /// Class names. + pub classes: Vec, + /// Attributes, in source order. Lookup is case-sensitive on both name and value. + pub attributes: Vec<(String, String)>, + /// Element has keyboard focus. + pub focus: bool, + /// Pointer is over the element. + pub hover: bool, + /// Element is being activated. + pub active: bool, + /// Layout width in CSS px, if known. Satisfies container/media size queries. + pub width: Option, + /// Layout height in CSS px, if known. + pub height: Option, + /// Inline style declarations as authored (e.g. `color: red; --x: 1`). + /// Parsed by the runtime cascade; author origin, above every stylesheet + /// declaration of the same importance, below author-`!important` rules. + pub style: Option, +} + +/// A flat tree snapshot: nodes in document order plus each node's parent index. +/// +/// Nodes are in document order and siblings are contiguous runs that share a +/// parent. [`NO_PARENT`] marks roots. +#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)] +pub struct TreeSnapshot { + pub nodes: Vec, + /// `parents[i]` is the index of the parent of node `i`, or [`NO_PARENT`]. + pub parents: Vec, +} + +impl TreeSnapshot { + pub fn parent_of(&self, index: usize) -> Option { + self.parents + .get(index) + .and_then(|p| (*p != NO_PARENT).then_some(*p as usize)) + } + + pub fn children_of(&self, index: usize) -> impl Iterator + '_ { + self.parents + .iter() + .enumerate() + .filter(move |&(_i, p)| *p == index as u32) + .map(|(i, _)| i) + } +} + +/// Color scheme preference for `prefers-color-scheme`. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ColorScheme { + Light, + Dark, +} + +/// Rendering environment supplied with every `compute` call. Unknown +/// dimensions are `None`; queries involving unknown dimensions do not match. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Environment { + pub viewport_width: Option, + pub viewport_height: Option, + pub color_scheme: ColorScheme, + /// `true` when the user prefers reduced motion. + pub reduced_motion: bool, + /// Device pixel ratio. + pub resolution: f32, +} + +impl Default for Environment { + fn default() -> Self { + Environment { + viewport_width: None, + viewport_height: None, + color_scheme: ColorScheme::Light, + reduced_motion: false, + resolution: 1.0, + } + } +} + +// --------------------------------------------------------------------------- +// Compiled stylesheet IR +// --------------------------------------------------------------------------- + +/// A compiled stylesheet: flattened, nesting-expanded rules with typed +/// condition trees, ready for linear-memory transport. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CompiledStylesheet { + /// [`IR_VERSION`] of the emitting compiler. + pub version: u16, + /// Origin this stylesheet was compiled for. + pub origin: Origin, + /// Cascade rules in source order. + pub rules: Vec, + /// Declared `@layer` names in first-appearance order. Nesting is a path. + pub layer_order: Vec>, + /// Preserved `@keyframes` blocks (not yet evaluated at runtime). + pub keyframes: Vec, + /// Preserved opaque at-rules (`@font-face`, `@property`, `@scope`, ...). + pub opaque: Vec, + /// Warnings collected during compilation. + pub warnings: Vec, +} + +/// One flattened, nesting-expanded cascade rule. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct CompiledRule { + /// Canonical serialized selector list (comma-separated). + pub selector: String, + /// Max specificity across the selector list, parcel_selectors-packed + /// `(ids << 20) | (classes << 10) | elements`. + pub specificity: u32, + /// Layer path this rule lives in, if any. + pub layer: Option>, + /// Media conditions. All must match. + pub media: Vec, + /// Container conditions. All must match. + pub containers: Vec, + /// `@supports` conditions. All must match. + pub supports: Vec, + /// Declarations, canonicalized per rule (each property at most once). + pub declarations: Vec, + /// Source order, unique within the originating stylesheet. + pub order: u32, +} + +/// A single declaration with its canonical value text. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Declaration { + /// Canonical property name (kebab-case, or `--custom`). + pub name: String, + /// Canonical serialized value. + pub value: String, + /// Whether the declaration carried `!important`. + pub important: bool, +} + +/// Whether `name` takes `` values. Both the compiler's color +/// canonicalization and the runtime's `light-dark()` resolution key off this +/// predicate, so it lives here next to the declaration type. +pub fn is_color_property(name: &str) -> bool { + name == "color" || name.ends_with("-color") +} + +/// A preserved `@keyframes` block. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct KeyframesRule { + pub name: String, + /// Canonical serialized body (everything inside the block). + pub body: String, +} + +/// A preserved opaque at-rule. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct OpaqueRule { + /// Canonical serialized at-rule text. + pub text: String, +} + +/// Comparison operator for range features. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Compare { + Equal, + GreaterThan, + GreaterThanEqual, + LessThan, + LessThanEqual, +} + +/// A value appearing in a media/container feature. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum FeatureValue { + /// Length already resolved to CSS px (absolute units). + Px(f32), + /// Length in a relative unit that needs a reference at evaluation time. + RelativeLength { + value: f32, + unit: String, + }, + Number(f32), + Integer(i32), + Boolean(bool), + /// Resolution normalized to dppx. + Dppx(f32), + Ratio(f32, f32), + Ident(String), + /// Unrepresentable value; conditions using it never match. + Unknown, +} + +/// The evaluated shape of a media or container size feature. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum FeatureKind { + /// `(width: 400px)` / `(min-width: 400px)`. + Plain { value: FeatureValue }, + /// `(hover)` — presence test. + Boolean, + /// `(width > 400px)`. + Range { cmp: Compare, value: FeatureValue }, + /// `(400px < width < 800px)`. + Interval { + start: FeatureValue, + start_cmp: Compare, + end: FeatureValue, + end_cmp: Compare, + }, +} + +/// A media or container size feature: canonical name plus its shape. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct Feature { + /// Canonical feature name (`min-width`, `width`, `aspect-ratio`, ...). + pub name: String, + pub kind: FeatureKind, +} + +/// Boolean algebra over media features. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum MediaCondition { + Feature(Feature), + Not(Box), + And(Vec), + Or(Vec), + /// Unparsed/unknown condition; never matches. + Unknown, +} + +/// A `@container` query: optional container name plus its condition. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub struct ContainerQuery { + /// Required container name, if the query was named. + pub name: Option, + pub condition: ContainerCondition, +} + +/// Boolean algebra over container conditions. +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +pub enum ContainerCondition { + /// Size feature (`width`, `inline-size`, `aspect-ratio`, ...). + Size(Feature), + /// Style query (`style(color: red)`), preserved as canonical text. + Style { + /// Canonical declaration text, e.g. `color: red`, or a bare property + /// name to test for non-initial value. + text: String, + }, + Not(Box), + And(Vec), + Or(Vec), + /// Scroll-state or unknown conditions; never match (for now). + Unknown, +} + +/// `@supports` condition with leaves pre-evaluated at compile time. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum SupportsCondition { + /// Declaration support: `supported` was determined by the compiler. + Declaration { + name: String, + value: String, + supported: bool, + }, + /// `selector(...)` support, validated at compile time. + Selector { + text: String, + supported: bool, + }, + Not(Box), + And(Vec), + Or(Vec), + Unknown, +} + +// --------------------------------------------------------------------------- +// Codec +// --------------------------------------------------------------------------- + +/// IR decode failure. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum IrError { + /// Bytes are not valid postcard IR. + Malformed, + /// IR decoded but carries an unsupported [`IR_VERSION`]. + UnsupportedVersion(u16), +} + +impl core::fmt::Display for IrError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + IrError::Malformed => f.write_str("malformed stylesheet IR"), + IrError::UnsupportedVersion(v) => { + write!(f, "unsupported IR version {v} (expected {IR_VERSION})") + } + } + } +} + +/// Encode a compiled stylesheet for linear-memory transport. +pub fn encode_ir(sheet: &CompiledStylesheet) -> Vec { + postcard::to_allocvec(sheet).unwrap_or_default() +} + +/// Decode and validate a compiled stylesheet. +pub fn decode_ir(bytes: &[u8]) -> Result { + let sheet: CompiledStylesheet = postcard::from_bytes(bytes).map_err(|_| IrError::Malformed)?; + if sheet.version != IR_VERSION { + return Err(IrError::UnsupportedVersion(sheet.version)); + } + Ok(sheet) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + fn sample() -> CompiledStylesheet { + CompiledStylesheet { + version: IR_VERSION, + origin: Origin::Author, + rules: vec![CompiledRule { + selector: ".card > .title".into(), + specificity: 0x200020, + layer: Some(vec!["base".into(), "typography".into()]), + media: vec![MediaCondition::Feature(Feature { + name: "min-width".into(), + kind: FeatureKind::Plain { + value: FeatureValue::Px(384.0), + }, + })], + containers: vec![ContainerQuery { + name: Some("panel".into()), + condition: ContainerCondition::Size(Feature { + name: "inline-size".into(), + kind: FeatureKind::Range { + cmp: Compare::GreaterThan, + value: FeatureValue::Px(720.0), + }, + }), + }], + supports: vec![SupportsCondition::Declaration { + name: "color".into(), + value: "oklch(70% 0.2 40)".into(), + supported: true, + }], + declarations: vec![Declaration { + name: "color".into(), + value: "oklch(70% 0.2 40)".into(), + important: false, + }], + order: 3, + }], + layer_order: vec![ + vec!["base".into()], + vec!["base".into(), "typography".into()], + ], + keyframes: vec![KeyframesRule { + name: "pulse".into(), + body: "0% {opacity:1} 100% {opacity:0}".into(), + }], + opaque: vec![OpaqueRule { + text: "@font-face{font-family:x}".into(), + }], + warnings: vec![Diagnostic::warning("test", "sample warning")], + } + } + + #[test] + fn round_trips() { + let sheet = sample(); + let bytes = encode_ir(&sheet); + let decoded = decode_ir(&bytes).unwrap(); + assert_eq!(decoded, sheet); + } + + #[test] + fn rejects_wrong_version() { + let mut sheet = sample(); + sheet.version = 99; + let bytes = encode_ir(&sheet); + assert_eq!(decode_ir(&bytes), Err(IrError::UnsupportedVersion(99))); + } +} diff --git a/experiments/css/crates/css-core/src/selectors.rs b/experiments/css/crates/css-core/src/selectors.rs new file mode 100644 index 0000000..554e047 --- /dev/null +++ b/experiments/css/crates/css-core/src/selectors.rs @@ -0,0 +1,526 @@ +//! The selector engine: a `parcel_selectors` `SelectorImpl` for the Bombshell +//! DOM snapshot model, the parser that accepts canonical selector text, and +//! the desugaring pass that rewrites components the matcher cannot execute +//! (`Nesting`, `Has`, `NthOf`, shadow-DOM parts) into interception points +//! owned by the runtime. +//! +//! Both the compiler (validation + specificity) and the runtime (matching) +//! drive this one parser, so the two sides can never disagree about what a +//! valid selector is. + +#![cfg(feature = "selectors")] + +use alloc::boxed::Box; +use alloc::vec::Vec; + +use cssparser::{ + CowRcStr, ParseError, Parser as CssParser, ParserInput, ToCss, match_ignore_ascii_case, +}; +use parcel_selectors::context::{MatchingContext, MatchingMode, QuirksMode}; +use parcel_selectors::matching::matches_selector_list; +use parcel_selectors::parser::{ + Component, NestingRequirement, NthOfSelectorData, ParseErrorRecovery, + Parser as SelectorParserTrait, SelectorImpl, SelectorParseErrorKind, +}; +use parcel_selectors::{NthIndexCache, SelectorList as ParcelSelectorList}; + +use alloc::borrow::Cow; +use core::fmt; + +/// `SelectorImpl` for the pipeline: identifiers are ref-counted strings. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Selectors; + +pub type SelectorList<'i> = ParcelSelectorList<'i, Selectors>; +pub type Selector<'i> = parcel_selectors::parser::Selector<'i, Selectors>; + +/// An interned-ish identifier backed by `CowRcStr`. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct Ident<'i>(pub CowRcStr<'i>); + +impl<'i> From> for Ident<'i> { + fn from(value: CowRcStr<'i>) -> Self { + Ident(value) + } +} + +impl<'i> From> for Ident<'i> { + fn from(value: Cow<'i, str>) -> Self { + Ident(CowRcStr::from(value)) + } +} + +impl AsRef for Ident<'_> { + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl<'i> core::borrow::Borrow for Ident<'i> { + fn borrow(&self) -> &str { + &self.0 + } +} + +impl Default for Ident<'_> { + fn default() -> Self { + Ident(CowRcStr::from("")) + } +} + +impl ToCss for Ident<'_> { + fn to_css(&self, dest: &mut W) -> fmt::Result { + dest.write_str(&self.0) + } +} + +/// Non-tree-structural pseudo-classes understood by the runtime matcher. +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum PseudoClass<'i> { + Hover, + Active, + Focus, + FocusVisible, + FocusWithin, + Disabled, + Enabled, + Checked, + Required, + Optional, + ReadOnly, + ReadWrite, + PlaceholderShown, + Lang(Vec>), + Dir(CowRcStr<'i>), + /// Desugared `:has(...)`; evaluated by traversal in the runtime. + Has(Box<[Selector<'i>]>), + /// Desugared `:nth-child(.. of S)`; evaluated by counting. + NthOf(NthOfSelectorData<'i, Selectors>), + /// Desugared components that can never match in the terminal model + /// (`&` remnants, `:host`, `::slotted`, `::part`, unknowns). + NeverMatches, +} + +impl fmt::Debug for PseudoClass<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + PseudoClass::Hover => ":hover", + PseudoClass::Active => ":active", + PseudoClass::Focus => ":focus", + PseudoClass::FocusVisible => ":focus-visible", + PseudoClass::FocusWithin => ":focus-within", + PseudoClass::Disabled => ":disabled", + PseudoClass::Enabled => ":enabled", + PseudoClass::Checked => ":checked", + PseudoClass::Required => ":required", + PseudoClass::Optional => ":optional", + PseudoClass::ReadOnly => ":read-only", + PseudoClass::ReadWrite => ":read-write", + PseudoClass::PlaceholderShown => ":placeholder-shown", + PseudoClass::Lang(_) => ":lang()", + PseudoClass::Dir(_) => ":dir()", + PseudoClass::Has(_) => ":has()", + PseudoClass::NthOf(_) => ":nth-child(of)", + PseudoClass::NeverMatches => ":never", + }) + } +} + +impl<'i> parcel_selectors::parser::NonTSPseudoClass<'i> for PseudoClass<'i> { + type Impl = Selectors; + + fn is_active_or_hover(&self) -> bool { + matches!(self, PseudoClass::Hover | PseudoClass::Active) + } + + fn is_user_action_state(&self) -> bool { + matches!( + self, + PseudoClass::Hover + | PseudoClass::Active + | PseudoClass::Focus + | PseudoClass::FocusVisible + | PseudoClass::FocusWithin + ) + } +} + +impl ToCss for PseudoClass<'_> { + fn to_css(&self, dest: &mut W) -> fmt::Result { + let name = match self { + PseudoClass::Hover => "hover", + PseudoClass::Active => "active", + PseudoClass::Focus => "focus", + PseudoClass::FocusVisible => "focus-visible", + PseudoClass::FocusWithin => "focus-within", + PseudoClass::Disabled => "disabled", + PseudoClass::Enabled => "enabled", + PseudoClass::Checked => "checked", + PseudoClass::Required => "required", + PseudoClass::Optional => "optional", + PseudoClass::ReadOnly => "read-only", + PseudoClass::ReadWrite => "read-write", + PseudoClass::PlaceholderShown => "placeholder-shown", + PseudoClass::Lang(_) => "lang", + PseudoClass::Dir(_) => "dir", + PseudoClass::Has(_) => "has", + PseudoClass::NthOf(_) => "nth-child", + PseudoClass::NeverMatches => return Ok(()), + }; + dest.write_str(name) + } +} + +/// Pseudo-elements are parsed for syntax compatibility but never match: the +/// terminal engine has no generated content yet. +#[derive(Clone, PartialEq, Eq, Hash)] +pub enum PseudoElement { + Before, + After, + Marker, + Selection, + FirstLine, + FirstLetter, + Placeholder, + Backdrop, + Unknown, +} + +impl fmt::Debug for PseudoElement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(match self { + PseudoElement::Before => "::before", + PseudoElement::After => "::after", + PseudoElement::Marker => "::marker", + PseudoElement::Selection => "::selection", + PseudoElement::FirstLine => "::first-line", + PseudoElement::FirstLetter => "::first-letter", + PseudoElement::Placeholder => "::placeholder", + PseudoElement::Backdrop => "::backdrop", + PseudoElement::Unknown => "::unknown", + }) + } +} + +impl parcel_selectors::parser::PseudoElement<'_> for PseudoElement { + type Impl = Selectors; +} + +impl ToCss for PseudoElement { + fn to_css(&self, dest: &mut W) -> fmt::Result { + let name = match self { + PseudoElement::Before => "before", + PseudoElement::After => "after", + PseudoElement::Marker => "marker", + PseudoElement::Selection => "selection", + PseudoElement::FirstLine => "first-line", + PseudoElement::FirstLetter => "first-letter", + PseudoElement::Placeholder => "placeholder", + PseudoElement::Backdrop => "backdrop", + PseudoElement::Unknown => return Ok(()), + }; + dest.write_str(name) + } +} + +/// Vendor prefixes never reach the runtime (compiler-canonical selectors, +/// `parse_any_prefix` returns `None`), so an uninhabited type satisfies the +/// `SelectorImpl` bounds. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum VendorPrefix {} + +impl ToCss for VendorPrefix { + fn to_css(&self, _dest: &mut W) -> fmt::Result { + match *self {} + } +} + +impl<'i> SelectorImpl<'i> for Selectors { + type ExtraMatchingData = (); + type AttrValue = Ident<'i>; + type Identifier = Ident<'i>; + type LocalName = Ident<'i>; + type NamespaceUrl = Ident<'i>; + type NamespacePrefix = Ident<'i>; + type BorrowedNamespaceUrl = str; + type BorrowedLocalName = str; + + type NonTSPseudoClass = PseudoClass<'i>; + type PseudoElement = PseudoElement; + type VendorPrefix = VendorPrefix; +} + +/// The selector parser for canonical compiler output. +pub struct SelectorParser; + +impl<'i> SelectorParserTrait<'i> for SelectorParser { + type Impl = Selectors; + type Error = SelectorParseErrorKind<'i>; + + fn parse_is_and_where(&self) -> bool { + true + } + + fn parse_non_ts_pseudo_class( + &self, + _location: cssparser::SourceLocation, + name: CowRcStr<'i>, + ) -> Result, ParseError<'i, Self::Error>> { + match_ignore_ascii_case! { &name, + "hover" => Ok(PseudoClass::Hover), + "active" => Ok(PseudoClass::Active), + "focus" => Ok(PseudoClass::Focus), + "focus-visible" => Ok(PseudoClass::FocusVisible), + "focus-within" => Ok(PseudoClass::FocusWithin), + "disabled" => Ok(PseudoClass::Disabled), + "enabled" => Ok(PseudoClass::Enabled), + "checked" => Ok(PseudoClass::Checked), + "required" => Ok(PseudoClass::Required), + "optional" => Ok(PseudoClass::Optional), + "read-only" => Ok(PseudoClass::ReadOnly), + "read-write" => Ok(PseudoClass::ReadWrite), + "placeholder-shown" => Ok(PseudoClass::PlaceholderShown), + _ => Err(_location.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClass(name))), + } + } + + fn parse_non_ts_functional_pseudo_class<'t>( + &self, + name: CowRcStr<'i>, + arguments: &mut CssParser<'i, 't>, + ) -> Result, ParseError<'i, Self::Error>> { + match_ignore_ascii_case! { &name, + "lang" => { + let mut languages = Vec::new(); + loop { + if arguments + .try_parse(|i| i.expect_delim('*')) + .is_ok() + { + languages.push(CowRcStr::from("*")); + } else { + languages.push(arguments.expect_ident()?.clone()); + } + if arguments.try_parse(|i| i.expect_comma()).is_err() { + break; + } + } + Ok(PseudoClass::Lang(languages)) + }, + "dir" => { + let ident = arguments.expect_ident()?.clone(); + Ok(PseudoClass::Dir(ident)) + }, + _ => Err(arguments.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClass(name))), + } + } + + fn parse_pseudo_element( + &self, + _location: cssparser::SourceLocation, + name: CowRcStr<'i>, + ) -> Result> { + match_ignore_ascii_case! { &name, + "before" => Ok(PseudoElement::Before), + "after" => Ok(PseudoElement::After), + "marker" => Ok(PseudoElement::Marker), + "selection" => Ok(PseudoElement::Selection), + "first-line" => Ok(PseudoElement::FirstLine), + "first-letter" => Ok(PseudoElement::FirstLetter), + "placeholder" => Ok(PseudoElement::Placeholder), + "backdrop" => Ok(PseudoElement::Backdrop), + _ => Ok(PseudoElement::Unknown), + } + } +} + +/// Per-element matching state: the `NthIndexCache` is element-scoped, so it +/// is built once per cascade step and shared across every rule matched +/// against that element. +pub struct MatchContext { + cache: NthIndexCache, +} + +impl Default for MatchContext { + fn default() -> Self { + Self::new() + } +} + +impl MatchContext { + pub fn new() -> Self { + MatchContext { + cache: NthIndexCache::default(), + } + } + + /// Match a parsed selector list against one element. + pub fn matches<'i, E>( + &mut self, + element: &E, + list: &SelectorList<'i>, + ) -> bool + where + E: parcel_selectors::Element<'i, Impl = Selectors>, + { + let mut context = MatchingContext::new( + MatchingMode::Normal, + None, + Some(&mut self.cache), + QuirksMode::NoQuirks, + ); + matches_selector_list(list, element, &mut context) + } +} + +/// Whether the selector can never match in the terminal model: it carries a +/// pseudo-element (no generated content yet) or a desugared `NeverMatches` +/// component (`&` remnants, `:host`, `::slotted`, `::part`) at the top +/// level. Components nested inside functional pseudo-classes only disable +/// that inner branch, so they do not disqualify the selector. +pub fn selector_never_matches(selector: &Selector) -> bool { + selector.has_pseudo_element() + || selector + .iter_raw_match_order() + .any(|c| matches!(c, Component::NonTSPseudoClass(PseudoClass::NeverMatches))) +} + +/// The "index keys" of a selector: tag/class/id names such that an element +/// missing all of them cannot match. Keys come from the rightmost compound +/// (positive requirements only — `:not()` contributes nothing, `:has()` +/// constrains descendants, not the element). An empty result means the +/// selector must always be tried. +/// +/// `:is()`/`:where()` and `:nth-child(.. of S)` contribute the union of +/// their inner selectors' rightmost keys: the element has to satisfy at +/// least one inner selector, so it must carry one of their keys. +pub fn selector_keys<'i>(selector: &Selector<'i>) -> Vec { + let mut keys = Vec::new(); + collect_keys(selector, &mut keys); + keys +} + +fn collect_keys<'i>(selector: &Selector<'i>, keys: &mut Vec) { + // Raw match order runs right-to-left (matching starts at the rightmost + // compound), so the keys come from the head of the iteration. + for component in selector.iter_raw_match_order() { + match component { + Component::Combinator(..) => break, + Component::Class(name) | Component::ID(name) => { + keys.push(String::from(name.as_ref())) + } + Component::LocalName(name) => { + // Both spellings: the matcher may consult either. + keys.push(String::from(name.name.as_ref())); + keys.push(String::from(name.lower_name.as_ref())); + } + Component::Is(list) | Component::Where(list) | Component::Any(_, list) => { + for inner in &**list { + collect_keys(inner, keys); + } + } + Component::NthOf(data) => { + for inner in data.selectors() { + collect_keys(inner, keys); + } + } + // `:not()` and `:has()` add no positive requirements on the + // element itself; attributes and pseudo-classes add none either. + _ => {} + } + } +} + +/// Validate a (nesting-expanded) selector list and return its specificity: +/// the max across entries, parcel-packed `(ids << 20) | (classes << 10) | +/// elements`. Specificity comes from the same engine that matches at runtime +/// (`:is()`/`:not()` take the max of their arguments; `:where()`/`:has()` +/// contribute nothing). +pub fn validate_and_specificity(text: &str) -> Result { + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + let list = SelectorList::parse( + &SelectorParser, + &mut parser, + ParseErrorRecovery::DiscardList, + NestingRequirement::None, + ) + .map_err(|_| ())?; + Ok(list.0.iter().map(|s| s.specificity()).max().unwrap_or(0)) +} + +/// Parse canonical selector text produced by the compiler. +/// +/// The returned selectors borrow from `text`; keep the text alive for as +/// long as the list (the IR owns it, so loaded stylesheets hold it anyway). +pub fn parse_selector_list<'i>( + text: &'i str, +) -> Result, ParseError<'i, SelectorParseErrorKind<'i>>> { + let mut input = ParserInput::new(text); + let mut parser = CssParser::new(&mut input); + let mut list = SelectorList::parse( + &SelectorParser, + &mut parser, + ParseErrorRecovery::IgnoreInvalidSelector, + NestingRequirement::None, + )?; + desugar_list(&mut list); + Ok(list) +} + +/// Rewrite components the upstream matcher cannot execute: +/// +/// - `Has(...)` → `PseudoClass::Has(...)`, evaluated by traversal +/// - `NthOf(...)` → `PseudoClass::NthOf(...)`, evaluated by counting +/// - `Nesting` (`&`), `Host`, `Slotted`, `Part` → `NeverMatches` +/// +/// Desugaring preserves the specificity parcel computed at parse time +/// (`:has()` weighs 0 here where the spec takes the max of its arguments). +pub fn desugar_list(list: &mut SelectorList) { + for selector in &mut list.0 { + desugar_selector(selector); + } +} + +fn desugar_selector(selector: &mut Selector) { + for component in selector.iter_mut_raw_match_order() { + desugar_component(component); + } +} + +fn desugar_component(component: &mut Component<'_, Selectors>) { + match component { + Component::Has(_) => { + let dummy = Component::ExplicitUniversalType; + let old = core::mem::replace(component, dummy); + if let Component::Has(selectors) = old { + let mut selectors = selectors.into_vec(); + for selector in &mut selectors { + desugar_selector(selector); + } + *component = + Component::NonTSPseudoClass(PseudoClass::Has(selectors.into_boxed_slice())); + } + } + Component::NthOf(_) => { + let dummy = Component::ExplicitUniversalType; + let old = core::mem::replace(component, dummy); + if let Component::NthOf(data) = old { + *component = Component::NonTSPseudoClass(PseudoClass::NthOf(data)); + } + } + Component::Nesting | Component::Host(_) | Component::Slotted(_) | Component::Part(_) => { + *component = Component::NonTSPseudoClass(PseudoClass::NeverMatches); + } + Component::Is(selectors) + | Component::Where(selectors) + | Component::Negation(selectors) + | Component::Any(_, selectors) => { + for selector in selectors.iter_mut() { + desugar_selector(selector); + } + } + _ => {} + } +} + diff --git a/experiments/css/crates/css-core/src/tokens.rs b/experiments/css/crates/css-core/src/tokens.rs new file mode 100644 index 0000000..c034d52 --- /dev/null +++ b/experiments/css/crates/css-core/src/tokens.rs @@ -0,0 +1,172 @@ +//! Canonical CSS token serialization — the one writer for re-emitting +//! tokenized value/selector text. +//! +//! Both the compiler (value canonicalization, nth canonicalization, +//! condition text) and the runtime (`var()` substitution) rebuild canonical +//! CSS from `cssparser` token streams. This module is that single writer: +//! block tokens serialize as their opening delimiter and callers descend +//! into the nested block themselves; numbers take the pipeline's canonical +//! number form (shortest round-trip f32, no redundant zeros or signs). + +#![cfg(feature = "selectors")] + +use core::fmt::Write as _; + +use cssparser::{CssStringWriter, Token, serialize_identifier, serialize_name, serialize_string}; + +/// CSS url() body escaping: control characters and spaces hex-escape, the +/// delimiter set backslash-escapes, everything else is literal. +fn serialize_unquoted_url(value: &str, out: &mut String) { + let mut chunk_start = 0; + for (i, byte) in value.bytes().enumerate() { + let hex = matches!(byte, b'\0'..=b' ' | b'\x7F'); + let special = matches!(byte, b'(' | b')' | b'"' | b'\'' | b'\\'); + if !hex && !special { + continue; + } + out.push_str(&value[chunk_start..i]); + if hex { + hex_escape(byte, out); + } else { + out.push('\\'); + out.push(byte as char); + } + chunk_start = i + 1; + } + out.push_str(&value[chunk_start..]); +} + +fn hex_escape(byte: u8, out: &mut String) { + const HEX_DIGITS: &[u8; 16] = b"0123456789abcdef"; + if byte > 0x0F { + out.push('\\'); + out.push(HEX_DIGITS[(byte >> 4) as usize] as char); + out.push(HEX_DIGITS[(byte & 0x0F) as usize] as char); + } else { + out.push('\\'); + out.push(HEX_DIGITS[byte as usize] as char); + } + out.push(' '); +} + +/// Canonical CSS text of one token. Block tokens (`Function`, bracket +/// blocks) write only their opening delimiter; the caller consumes the +/// nested block and writes the closer. +pub fn write_token(out: &mut String, token: &Token<'_>) { + match *token { + Token::Ident(ref value) => { + let _ = serialize_identifier(value, out); + } + Token::AtKeyword(ref value) => { + out.push('@'); + let _ = serialize_identifier(value, out); + } + Token::Hash(ref value) => { + out.push('#'); + let _ = serialize_name(value, out); + } + Token::IDHash(ref value) => { + out.push('#'); + let _ = serialize_identifier(value, out); + } + Token::QuotedString(ref value) => { + let _ = serialize_string(value, out); + } + Token::UnquotedUrl(ref value) => { + out.push_str("url("); + serialize_unquoted_url(value, out); + out.push(')'); + } + Token::Delim(value) => out.push(value), + + Token::Number { value, has_sign, .. } => write_number(out, value, has_sign), + Token::Percentage { unit_value, .. } => { + write_number(out, unit_value * 100.0, false); + out.push('%'); + } + Token::Dimension { value, ref unit, has_sign, .. } => { + write_number(out, value, has_sign); + // Disambiguate with scientific notation: a unit starting with + // `e`/`E` would read as an exponent. + let unit = &**unit; + if unit == "e" || unit == "E" || unit.starts_with("e-") || unit.starts_with("E-") { + out.push_str("\\65 "); + let _ = serialize_name(&unit[1..], out); + } else { + let _ = serialize_identifier(unit, out); + } + } + + Token::WhiteSpace(content) => out.push_str(content), + Token::Comment(content) => { + out.push_str("/*"); + out.push_str(content); + out.push_str("*/"); + } + Token::Colon => out.push(':'), + Token::Semicolon => out.push(';'), + Token::Comma => out.push(','), + Token::IncludeMatch => out.push_str("~="), + Token::DashMatch => out.push_str("|="), + Token::PrefixMatch => out.push_str("^="), + Token::SuffixMatch => out.push_str("$="), + Token::SubstringMatch => out.push_str("*="), + Token::CDO => out.push_str(""), + + Token::Function(ref name) => { + let _ = serialize_identifier(name, out); + out.push('('); + } + Token::ParenthesisBlock => out.push('('), + Token::SquareBracketBlock => out.push('['), + Token::CurlyBracketBlock => out.push('{'), + + Token::BadUrl(ref contents) => { + out.push_str("url("); + out.push_str(contents); + out.push(')'); + } + Token::BadString(ref value) => { + // The token ends just before its newline, with no closing quote; + // the content is still escaped like a string body. + out.push('"'); + let mut escaped = String::new(); + let _ = CssStringWriter::new(&mut escaped).write_str(value); + out.push_str(&escaped); + } + Token::CloseParenthesis => out.push(')'), + Token::CloseSquareBracket => out.push(']'), + Token::CloseCurlyBracket => out.push('}'), + } +} + +/// Canonical number text: shortest round-trip f32, `-0` normalized, leading +/// zeros dropped (`.2`), trailing zeros dropped (`2.50` → `2.5`), integers +/// left integer. +pub fn write_number(out: &mut String, value: f32, _has_sign: bool) { + // Shortest round-trip f32 text (core's float Display). dtoa's f32 + // output diverges from this in the 7th+ significant digit, and the + // canonical form is pinned by conformance — keep the core formatter. + let text = format!("{value}"); + if !text.contains('.') { + out.push_str(&text); + return; + } + + let text = text.trim_end_matches('0'); + let text = if text.ends_with('.') { &text[..text.len() - 1] } else { text }; + match text.strip_prefix("-0.") { + Some(stripped) => { + out.push_str("-."); + out.push_str(stripped); + } + None => match text.strip_prefix("0.") { + Some(stripped) => { + out.push('.'); + out.push_str(stripped); + } + None => out.push_str(text), + }, + } +} diff --git a/experiments/css/crates/css-runtime/Cargo.toml b/experiments/css/crates/css-runtime/Cargo.toml new file mode 100644 index 0000000..193cf92 --- /dev/null +++ b/experiments/css/crates/css-runtime/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "bombshell-css-runtime" +version = "0.1.0" +description = "Selector matching and cascade runtime for the Bombshell CSS pipeline" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[dependencies] +bombshell-css-core = { workspace = true } +parcel_selectors = { workspace = true } +rustc-hash = { workspace = true } +cssparser = { workspace = true } + +[dev-dependencies] +bombshell-css-compiler = { workspace = true } diff --git a/experiments/css/crates/css-runtime/src/cascade.rs b/experiments/css/crates/css-runtime/src/cascade.rs new file mode 100644 index 0000000..9eaece6 --- /dev/null +++ b/experiments/css/crates/css-runtime/src/cascade.rs @@ -0,0 +1,707 @@ +//! Cascade resolution: origins and importance, `@layer` ordering, +//! specificity, source order, then inheritance and custom-property +//! resolution. + +use std::borrow::Cow; + +use crate::conditions::{ + ContainerAncestor, ContainerType, eval_container_list, eval_media_list, eval_supports_list, +}; +use crate::selectors::parse_selector_list; +use crate::values::{resolve_light_dark, resolve_vars}; +use bombshell_css_core::{CompiledStylesheet, ContainerQuery, Declaration, Origin, TreeSnapshot}; +use rustc_hash::FxHashMap as HashMap; + +/// Property map for one element: keys are canonical IR property names +/// (borrowed) or inline-style names (owned); values borrow the IR until a +/// `var()` substitution, inheritance, or an inline declaration materializes +/// something new. +pub type StyleMap<'ir> = HashMap, Cow<'ir, str>>; + +/// Properties that inherit by default (CSS-wide custom properties also +/// inherit unconditionally). +pub const INHERITED_PROPERTIES: &[&str] = &[ + "color", + "opacity", + "font", + "font-family", + "font-size", + "font-weight", + "font-style", + "font-stretch", + "font-variation-settings", + "font-feature-settings", + "line-height", + "letter-spacing", + "word-spacing", + "white-space", + "text-align", + "text-align-last", + "text-transform", + "text-indent", + "text-underline-offset", + "text-decoration-thickness", + "text-emphasis-color", + "text-emphasis-style", + "visibility", + "cursor", + "direction", + "writing-mode", + "tab-size", + "user-select", + "list-style-type", + "list-style-position", + "border-collapse", + "border-spacing", + "caption-side", + "empty-cells", + "quotes", + "orphans", + "widows", + "caret-color", +]; + +/// A stylesheet loaded for cascade: parsed selectors over the typed IR. +/// +/// Borrows from the [`CompiledStylesheet`] it was loaded from; the IR owns +/// all selector and declaration text, so loading is allocation-free apart +/// from parsing. +#[derive(Clone)] +pub struct Stylesheet<'ir> { + pub origin: Origin, + pub sheet_index: usize, + /// Rules in IR order; rules whose selectors failed to parse are skipped + /// (their selector text shows up in [`Self::unmatched_selectors`]). + pub rules: Vec>, + pub layer_order: &'ir [Vec], + /// Candidate pre-filter: rule indices keyed by the tag/class/id names + /// their selectors' rightmost compounds require. Matching only consults + /// the element's own keys plus the always-checked bucket, which keeps + /// per-frame work proportional to relevant rules instead of all rules. + index: RuleIndex, + parse_warnings: Vec, +} + +#[derive(Clone, Default)] +struct RuleIndex { + /// Rule indices per index key; a key may name a class, a tag, or an id — + /// collisions only add false-positive candidates, never miss one. + /// Owned keys: the index is built once per stylesheet load. + keys: HashMap>, + /// Rules whose selectors carry no index key and are always checked. + universal: Vec, +} + +impl RuleIndex { + fn build<'ir>(rules: &[CascadeRule<'ir>]) -> RuleIndex { + let mut index = RuleIndex::default(); + for (rule_index, rule) in rules.iter().enumerate() { + let rule_index = rule_index as u32; + let mut keys: Vec = Vec::new(); + let mut always = false; + let mut indexable = false; + for selector in &rule.parsed.0 { + // Selectors that can never match are not indexed at all: + // checking them per element would be pure waste. + if bombshell_css_core::selectors::selector_never_matches(selector) { + continue; + } + indexable = true; + let selector_keys = bombshell_css_core::selectors::selector_keys(selector); + if selector_keys.is_empty() { + // One un-keyed selector in the list means any element + // could match through it. + always = true; + break; + } + keys.extend(selector_keys); + } + if !indexable { + // Every selector is impossible; the rule can never match. + continue; + } + if always || keys.is_empty() { + index.universal.push(rule_index); + } else { + for key in keys { + index.keys.entry(key).or_default().push(rule_index); + } + } + } + index + } +} + +#[derive(Clone)] +pub struct CascadeRule<'ir> { + /// Canonical selector text, for diagnostics and serialization. + pub selector: &'ir str, + pub parsed: crate::selectors::SelectorList<'ir>, + pub specificity: u32, + pub layer: Option<&'ir [String]>, + pub media: &'ir [bombshell_css_core::MediaCondition], + pub containers: &'ir [ContainerQuery], + pub supports: &'ir [bombshell_css_core::SupportsCondition], + pub declarations: &'ir [Declaration], + pub order: u32, +} + +impl<'ir> Stylesheet<'ir> { + /// Load a stylesheet from decoded IR. Selectors that fail to parse are + /// skipped (they are reported through [`Self::unmatched_selectors`]). + pub fn from_ir(ir: &'ir CompiledStylesheet, sheet_index: usize) -> Stylesheet<'ir> { + let mut rules = Vec::with_capacity(ir.rules.len()); + let mut parse_warnings = Vec::new(); + for rule in &ir.rules { + match parse_selector_list(rule.selector.as_str()) { + Ok(parsed) => rules.push(CascadeRule { + selector: rule.selector.as_str(), + parsed, + specificity: rule.specificity, + layer: rule.layer.as_deref(), + media: &rule.media, + containers: &rule.containers, + supports: &rule.supports, + declarations: &rule.declarations, + order: rule.order, + }), + Err(_) => parse_warnings.push(bombshell_css_core::Diagnostic::warning( + "selector-parse", + { + let mut message = + String::from("selector could not be matched at runtime: "); + message.push_str(&rule.selector); + message + }, + )), + } + } + let index = RuleIndex::build(&rules); + Stylesheet { + origin: ir.origin, + sheet_index, + rules, + layer_order: &ir.layer_order, + index, + parse_warnings, + } + } + + /// Rule indices that could possibly match `element`: the union of the + /// element's own index keys plus the always-checked bucket, deduped, + /// with impossible selectors filtered by an actual match attempt. + pub(crate) fn matched_rules( + &self, + element: &crate::element::MatchElement, + context: &mut crate::selectors::MatchContext, + ) -> Vec { + let node = element.node(); + let mut candidates: Vec = Vec::new(); + candidates.extend_from_slice(&self.index.universal); + let push_key = |key: &str, candidates: &mut Vec| { + if let Some(list) = self.index.keys.get(key) { + candidates.extend_from_slice(list); + } + }; + push_key(node.tag.as_str(), &mut candidates); + if let Some(id) = node.id.as_deref() { + push_key(id, &mut candidates); + } + for class in &node.classes { + push_key(class.as_str(), &mut candidates); + } + sort_by(&mut candidates, |a, b| a < b); + candidates.dedup(); + candidates.retain(|&i| context.matches(element, &self.rules[i as usize].parsed)); + candidates + } + + /// Selector text that failed to parse at load time. + pub fn unmatched_selectors(&self) -> impl Iterator { + self.parse_warnings + .iter() + .map(|d| &d.message["selector could not be matched at runtime: ".len()..]) + } +} + + +/// Minimal stable sort. std's adaptive sort machinery is several KB of code; +/// cascade sorts are almost always a few dozen elements, where plain binary +/// insertion sort costs nothing and behaves identically. +fn sort_by(v: &mut [T], mut less: impl FnMut(&T, &T) -> bool) { + for i in 1..v.len() { + // The element being inserted is `v[i]`; compare it against the + // sorted prefix. Comparing `v[j]` instead would test the wrong pair + // as soon as the key moves more than one slot. + let mut j = i; + while j > 0 && less(&v[i], &v[j - 1]) { + j -= 1; + } + if j != i { + v[j..=i].rotate_right(1); + } + } +} +/// The computed style of one element: winning declarations with inheritance +/// applied and `var()` references resolved. Names always borrow the IR; +/// values borrow until substitution produces something new. +#[derive(Debug, Clone, Default, PartialEq)] +pub struct ComputedStyle<'ir> { + /// (property name, computed value), sorted by name. Names borrow the IR + /// unless they came from an inline style. + pub declarations: Vec<(Cow<'ir, str>, Cow<'ir, str>)>, +} + +impl<'ir> ComputedStyle<'ir> { + pub fn get(&self, name: &str) -> Option<&str> { + self.declarations + .iter() + .find(|(n, _)| n.as_ref() == name) + .map(|(_, v)| v.as_ref()) + } + + pub(crate) fn from_map(map: StyleMap<'ir>) -> ComputedStyle<'ir> { + let mut declarations: Vec<(Cow<'ir, str>, Cow<'ir, str>)> = map.into_iter().collect(); + sort_by(&mut declarations, |a, b| a < b); + ComputedStyle { declarations } + } +} + +/// Compute the style of `target` within `tree`. +/// +/// The full ancestor chain is cascaded so container lookups, inheritance, +/// and style queries see computed values. +pub fn compute<'ir>( + sheets: &[&Stylesheet<'ir>], + tree: &TreeSnapshot, + target: usize, + env: &bombshell_css_core::Environment, +) -> Option> { + if target >= tree.nodes.len() { + return None; + } + compute_tree(sheets, tree, env, std::slice::from_ref(&target)) + .into_iter() + .nth(target) + .flatten() +} + +/// Compute styles for a whole tree in one pass: nodes are processed in +/// document order (parents before children), so each node's cascade runs +/// exactly once and every computed style is available to its descendants. +/// +/// Returns one entry per node, index-aligned with `tree.nodes`; `targets` +/// restricts which entries are resolved (an empty list resolves every +/// node). Unresolved entries are empty styles. +pub fn compute_tree<'ir>( + sheets: &[&Stylesheet<'ir>], + tree: &TreeSnapshot, + env: &bombshell_css_core::Environment, + targets: &[usize], +) -> Vec>> { + let count = tree.nodes.len(); + // Everything when `targets` is empty; otherwise each target plus its + // ancestor chain (targets may not be leaves, so walk to the root). + let mut wanted = vec![targets.is_empty(); count]; + for target in targets { + let mut index = Some(*target); + while let Some(current) = index { + wanted[current] = true; + index = tree.parent_of(current); + } + } + + // Resolved maps per node, kept so descendants can inherit computed + // values; the sorted `ComputedStyle` form is built only for output. + let mut maps: Vec>> = Vec::with_capacity(count); + + // `@layer` order is a document-wide property: layers rank by first + // appearance across all sheets in cascade order. With a single sheet + // this is exactly that sheet's own order — no allocation, and the + // zero-allocation frame-loop claim holds for the common case. + let merged: Vec> = if sheets.len() == 1 { + Vec::new() + } else { + let mut merged: Vec> = Vec::new(); + for sheet in sheets { + for path in sheet.layer_order { + if !merged.iter().any(|existing| *existing == *path) { + merged.push(path.clone()); + } + } + } + merged + }; + let layers: &[Vec] = if sheets.len() == 1 { + sheets[0].layer_order + } else { + &merged + }; + for index in 0..count { + if !wanted[index] { + maps.push(None); + continue; + } + let parent = tree.parent_of(index); + // Hosts list nodes in document order, so the parent is already + // processed; a malformed ordering degrades to no inheritance rather + // than panicking. + let inherited: StyleMap<'ir> = match parent.and_then(|p| maps.get(p).and_then(|m| m.as_ref())) { + Some(map) => map.clone(), + None => HashMap::default(), + }; + // Container ancestors: walk up through the already-computed maps. + // The node itself is never its own container. + let mut containers: Vec = Vec::new(); + let mut current = parent; + while let Some(ancestor) = current { + if let Some(map) = maps.get(ancestor).and_then(|m| m.as_ref()) { + if let Some(container_type) = computed_container_type(map) { + let node = &tree.nodes[ancestor]; + containers.push(ContainerAncestor { + name: map.get("container-name").map(|v| v.clone().into_owned()), + container_type, + width: node.width, + height: node.height, + }); + } + } + current = tree.parent_of(ancestor); + } + + let mut map: StyleMap<'ir> = cascade(sheets, tree, index, env, &containers, layers); + apply_css_wide_keywords(&mut map, &inherited); + for (name, value) in &inherited { + let inherits = + name.starts_with("--") || INHERITED_PROPERTIES.iter().any(|p| *p == name.as_ref()); + if inherits && !map.contains_key(name) { + map.insert(name.clone(), value.clone()); + } + } + // var() substitution is part of computing the value: descendants + // inherit computed values, not raw `var()` text. + resolve_vars_in_map(&mut map); + // `light-dark()` resolves at computed-value time, after var() + // substitution (a custom property may carry it into the using + // declaration) and before descendants inherit the value. + resolve_light_dark_in_map(&mut map, env.color_scheme); + maps.push(Some(map)); + } + + maps.into_iter() + .map(|slot| slot.map(ComputedStyle::from_map)) + .collect() +} + +fn computed_container_type(map: &StyleMap<'_>) -> Option { + // `map.get` accepts `&str` via `Borrow` on the `Cow` key. + match map.get("container-type").map(|v| v.as_ref()) { + Some("size") => Some(ContainerType::Size), + Some("inline-size") => Some(ContainerType::InlineSize), + Some("normal") | Some("") | None => None, + Some(_) => None, + } +} + +/// Resolve var() references in every non-custom declaration (custom +/// properties keep their raw values until referenced). +fn resolve_vars_in_map(map: &mut StyleMap<'_>) { + let names: Vec> = map.keys().cloned().collect(); + for name in names { + if name.starts_with("--") { + continue; + } + if let Some(value) = map.get(name.as_ref()) { + if value.contains("var(") { + match resolve_vars(value, map) { + Some(resolved) => { + map.insert(name, Cow::Owned(resolved)); + } + None => { + // Invalid at computed-value time. + map.remove(name.as_ref()); + } + } + } + } + } +} + +/// Resolve `light-dark()` in every non-custom color declaration against the +/// environment's color scheme. Resolution is scoped to the color properties +/// the compiler canonicalizes; custom properties substitute verbatim and +/// resolve at the using declaration. A malformed call drops the +/// declaration, like a failed `var()` resolution. +fn resolve_light_dark_in_map(map: &mut StyleMap<'_>, scheme: bombshell_css_core::ColorScheme) { + let names: Vec> = map.keys().cloned().collect(); + for name in names { + if name.starts_with("--") { + continue; + } + if !bombshell_css_core::is_color_property(name.as_ref()) { + continue; + } + if let Some(value) = map.get(name.as_ref()) { + if value.contains("light-dark(") { + match resolve_light_dark(value, scheme) { + Some(resolved) => { + if resolved != value.as_ref() { + map.insert(name, Cow::Owned(resolved)); + } + } + None => { + // Invalid at computed-value time. + map.remove(name.as_ref()); + } + } + } + } + } +} + +/// Handle `inherit`, `initial`, `unset`, and `revert` keywords. +fn apply_css_wide_keywords<'ir>(map: &mut StyleMap<'ir>, inherited: &StyleMap<'ir>) { + let names: Vec> = map.keys().cloned().collect(); + for name in names { + let keyword = map.get(name.as_ref()).map(|v| v.trim()).unwrap_or_default(); + let inherits = + name.starts_with("--") || INHERITED_PROPERTIES.iter().any(|p| *p == name.as_ref()); + match keyword { + "inherit" => match inherited.get(name.as_ref()) { + Some(value) => { + map.insert(name, value.clone()); + } + None => { + map.remove(name.as_ref()); + } + }, + "unset" => { + if inherits { + match inherited.get(name.as_ref()) { + Some(value) => { + map.insert(name, value.clone()); + } + None => { + map.remove(name.as_ref()); + } + } + } else { + map.remove(name.as_ref()); + } + } + // No initial-value table yet: `initial` and `revert` drop the + // declaration. + "initial" | "revert" => { + map.remove(name.as_ref()); + } + _ => {} + } + } +} + +/// Cascade one node: condition-filtered, selector-matched rules, sorted by +/// origin/importance, layer, specificity, then source order; last write per +/// property wins. Inline style declarations slot in at their cascade +/// boundaries (see [`parse_inline_style`]). +fn cascade<'ir>( + sheets: &[&Stylesheet<'ir>], + tree: &TreeSnapshot, + node_index: usize, + env: &bombshell_css_core::Environment, + containers: &[ContainerAncestor], + layers: &[Vec], +) -> StyleMap<'ir> { + let Some(element) = crate::element::MatchElement::new(tree, node_index) else { + return HashMap::default(); + }; + + struct Candidate<'a> { + declaration: &'a Declaration, + origin_rank: u32, + layer_rank: u32, + specificity: u32, + order: (usize, u32), + } + + // One match context per element: the nth-index cache is per-element + // state, not per-rule state. + let mut context = crate::selectors::MatchContext::new(); + let mut candidates: Vec = Vec::new(); + for sheet in sheets { + let mut matched = sheet.matched_rules(&element, &mut context); + + for rule_index in matched.drain(..) { + let rule = &sheet.rules[rule_index as usize]; + if !eval_supports_list(rule.supports) { + continue; + } + if !eval_media_list(rule.media, env) { + continue; + } + if !eval_container_list(rule.containers, containers) { + continue; + } + for declaration in rule.declarations { + candidates.push(Candidate { + declaration, + origin_rank: origin_importance_rank(sheet.origin, declaration.important), + layer_rank: layer_rank(layers, rule.layer), + specificity: rule.specificity, + order: (sheet.sheet_index, rule.order), + }); + } + } + } + + sort_by(&mut candidates, |a, b| { + (a.origin_rank, a.layer_rank, a.specificity, a.order) + < (b.origin_rank, b.layer_rank, b.specificity, b.order) + }); + + // Inline styles are author-origin declarations with precedence above + // every stylesheet declaration of the same importance: inline-normal + // slots in after all normal author rules, inline-`!important` after all + // author-`!important` rules. Both still lose to higher tiers (user / + // user-agent `!important`). Writing in ascending order means the last + // write per property wins. + let (inline_normal, inline_important) = tree.nodes[node_index] + .style + .as_deref() + .map(parse_inline_style) + .unwrap_or_default(); + + // Ascending order: later candidates overwrite earlier ones, so the map + // ends up holding the winning value per property. + let mut winners: StyleMap<'ir> = HashMap::default(); + let mut inline_normal_pending = !inline_normal.is_empty(); + let mut inline_important_pending = !inline_important.is_empty(); + for candidate in &candidates { + if inline_normal_pending && candidate.origin_rank >= 3 { + for (name, value) in &inline_normal { + winners.insert(Cow::Owned(name.clone()), Cow::Owned(value.clone())); + } + inline_normal_pending = false; + } + if inline_important_pending && candidate.origin_rank >= 4 { + for (name, value) in &inline_important { + winners.insert(Cow::Owned(name.clone()), Cow::Owned(value.clone())); + } + inline_important_pending = false; + } + let declaration = candidate.declaration; + winners.insert( + Cow::Borrowed(declaration.name.as_str()), + Cow::Borrowed(declaration.value.as_str()), + ); + } + if inline_normal_pending { + for (name, value) in &inline_normal { + winners.insert(Cow::Owned(name.clone()), Cow::Owned(value.clone())); + } + } + if inline_important_pending { + for (name, value) in &inline_important { + winners.insert(Cow::Owned(name.clone()), Cow::Owned(value.clone())); + } + } + winners +} + +/// `@layer` order across sheets: layers rank by first appearance across all +/// sheets in the order the host supplies them (later layers win). Unlayered +/// ranks above every layer. +fn layer_rank(layers: &[Vec], layer: Option<&[String]>) -> u32 { + match layer { + None => u32::MAX, + Some(path) => layers + .iter() + .position(|p| p.as_slice() == path) + .map(|p| p as u32) + .unwrap_or(u32::MAX - 1), + } +} + +/// Parse an inline `style` attribute into (normal, important) declaration +/// lists, in authorship order. Splits on `;` and the first `:` outside +/// parens, brackets, and quotes, so values like `url(data:image/png;base64,…)` +/// survive. Names are lowercased; values pass through un-canonicalized (the +/// compiler never sees them). +fn parse_inline_style(style: &str) -> (Vec<(String, String)>, Vec<(String, String)>) { + let mut normal: Vec<(String, String)> = Vec::new(); + let mut important: Vec<(String, String)> = Vec::new(); + for part in top_level_split(style, ';') { + let Some(sep) = top_level_index(part, ':') else { + continue; + }; + let name = part[..sep].trim().to_ascii_lowercase(); + let value = part[sep + 1..].trim(); + let Some((value, is_important)) = strip_important(value) else { + continue; + }; + if name.is_empty() || value.is_empty() { + continue; + } + if is_important { + important.push((name, value.to_string())); + } else { + normal.push((name, value.to_string())); + } + } + (normal, important) +} + +/// Strip a trailing case-insensitive `!important`; returns `None` when the +/// declaration is empty after trimming. +fn strip_important(value: &str) -> Option<(&str, bool)> { + let lower = value.to_ascii_lowercase(); + if let Some(pos) = lower.rfind("!important") { + if lower[pos + "!important".len()..].trim().is_empty() { + let trimmed = value[..pos].trim_end(); + return Some((trimmed, true)); + } + } + (!value.is_empty()).then_some((value, false)) +} + +/// Split on every `sep` that sits outside parens, brackets, and quotes. +fn top_level_split(style: &str, sep: char) -> Vec<&str> { + let mut out: Vec<&str> = Vec::new(); + let mut depth = 0usize; + let mut quote: Option = None; + let mut start = 0usize; + for (index, ch) in style.char_indices() { + match ch { + '(' | '[' if quote.is_none() => depth += 1, + ')' | ']' if quote.is_none() => depth = depth.saturating_sub(1), + '\'' | '"' if quote.is_none() => quote = Some(ch), + c if Some(c) == quote => quote = None, + _ => {} + } + if ch == sep && quote.is_none() && depth == 0 { + out.push(&style[start..index]); + start = index + ch.len_utf8(); + } + } + out.push(&style[start..]); + out +} + +/// Index of the first `sep` outside parens, brackets, and quotes. +fn top_level_index(style: &str, sep: char) -> Option { + top_level_split(style, sep) + .first() + .map(|head| head.len()) + .filter(|&len| len < style.len()) +} + +/// Cascade priority within (origin, importance), ascending. +fn origin_importance_rank(origin: Origin, important: bool) -> u32 { + match (origin, important) { + (Origin::UserAgent, false) => 0, + (Origin::User, false) => 1, + (Origin::Author, false) => 2, + (Origin::Author, true) => 3, + (Origin::User, true) => 4, + (Origin::UserAgent, true) => 5, + } +} diff --git a/experiments/css/crates/css-runtime/src/conditions.rs b/experiments/css/crates/css-runtime/src/conditions.rs new file mode 100644 index 0000000..c3fa2f4 --- /dev/null +++ b/experiments/css/crates/css-runtime/src/conditions.rs @@ -0,0 +1,415 @@ +//! Runtime evaluation of the typed IR condition trees against the +//! [`Environment`] and container snapshots. + +use bombshell_css_core::{ + ColorScheme, Compare, ContainerCondition, ContainerQuery, Environment, Feature, FeatureKind, + FeatureValue, MediaCondition, +}; + +/// A container discovered while walking the ancestor chain. Sizes come from +/// the node snapshot; container-ness comes from the ancestor's own computed +/// `container-type` / `container-name`. +#[derive(Debug, Clone)] +pub struct ContainerAncestor { + /// The container's `container-name`, if set. + pub name: Option, + /// Whether the container tracks inline size, block size, or both. + pub container_type: ContainerType, + pub width: Option, + pub height: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum ContainerType { + Normal, + Size, + InlineSize, +} + +/// Evaluate a whole `@media` condition list (ANDed). +pub fn eval_media_list(conditions: &[MediaCondition], env: &Environment) -> bool { + conditions.iter().all(|c| eval_media(c, env)) +} + +pub fn eval_media(condition: &MediaCondition, env: &Environment) -> bool { + match condition { + MediaCondition::And(conditions) => conditions.iter().all(|c| eval_media(c, env)), + MediaCondition::Or(conditions) => conditions.iter().any(|c| eval_media(c, env)), + MediaCondition::Not(inner) => !eval_media(inner, env), + MediaCondition::Feature(feature) => eval_feature(feature, &FeatureSource::Viewport(env)), + MediaCondition::Unknown => false, + } +} + +/// Evaluate a whole `@container` condition list (ANDed). +pub fn eval_container_list(queries: &[ContainerQuery], containers: &[ContainerAncestor]) -> bool { + queries + .iter() + .all(|query| eval_container(query, containers)) +} + +pub fn eval_container(query: &ContainerQuery, containers: &[ContainerAncestor]) -> bool { + let container = match &query.name { + Some(name) => containers.iter().rev().find(|c| { + c.container_type != ContainerType::Normal + && c.name.as_deref().is_some_and(|n| n == name) + }), + None => containers + .iter() + .rev() + .find(|c| c.container_type != ContainerType::Normal), + }; + let Some(container) = container else { + return false; + }; + eval_container_condition(&query.condition, container) +} + +fn eval_container_condition(condition: &ContainerCondition, container: &ContainerAncestor) -> bool { + match condition { + ContainerCondition::And(conditions) => conditions + .iter() + .all(|c| eval_container_condition(c, container)), + ContainerCondition::Or(conditions) => conditions + .iter() + .any(|c| eval_container_condition(c, container)), + ContainerCondition::Not(inner) => !eval_container_condition(inner, container), + ContainerCondition::Size(feature) => { + eval_feature(feature, &FeatureSource::Container(container)) + } + ContainerCondition::Style { text } => { + // Style queries are resolved against the container's computed + // declarations by the cascade layer; without that context they + // do not match. + let _ = text; + false + } + ContainerCondition::Unknown => false, + } +} + +pub enum FeatureSource<'a> { + Viewport(&'a Environment), + Container(&'a ContainerAncestor), +} + +impl FeatureSource<'_> { + fn dimension(&self, name: &str) -> Option { + match self { + FeatureSource::Viewport(env) => match name { + "width" | "inline-size" => env.viewport_width, + "height" | "block-size" => env.viewport_height, + _ => None, + }, + FeatureSource::Container(container) => { + let (width, height) = (container.width, container.height); + match name { + "width" => width, + "height" => height, + "inline-size" => match container.container_type { + // A `size` container has both axes; an `inline-size` + // container only guarantees the inline axis. + ContainerType::Normal => None, + ContainerType::InlineSize | ContainerType::Size => width, + }, + "block-size" => match container.container_type { + ContainerType::Size => height, + _ => None, + }, + _ => None, + } + } + } + } +} + +/// Evaluate one media/container size feature. +pub fn eval_feature(feature: &Feature, source: &FeatureSource) -> bool { + let name = feature.name.as_str(); + + // Orientation and aspect-ratio need special handling. + if let Some(result) = eval_special_feature(name, feature, source) { + return result; + } + + // Environment-driven features (prefers-*, color, hover, ...). + if let FeatureSource::Viewport(env) = source { + if let Some(result) = eval_env_feature(name, feature, env) { + return result; + } + } + + // Dimensional features. + match &feature.kind { + FeatureKind::Boolean => { + // `(width)` is true when the dimension is known and non-zero. + source.dimension(name).is_some_and(|v| v != 0.0) + } + FeatureKind::Plain { value } => { + let Some(dimension) = source.dimension(name) else { + return false; + }; + let Some(actual) = feature_value(value, source) else { + return false; + }; + compare(Compare::Equal, dimension, actual) + } + FeatureKind::Range { cmp, value } => { + let Some(dimension) = source.dimension(name) else { + return false; + }; + let Some(actual) = feature_value(value, source) else { + return false; + }; + compare(*cmp, dimension, actual) + } + FeatureKind::Interval { + start, + start_cmp, + end, + end_cmp, + } => { + let Some(dimension) = source.dimension(name) else { + return false; + }; + let (Some(start), Some(end)) = + (feature_value(start, source), feature_value(end, source)) + else { + return false; + }; + // `(a < feature < b)`: the start operator is written between the + // start value and the feature (feature on the right), the end + // operator between the feature and the end value. + compare(*start_cmp, start, dimension) && compare(*end_cmp, dimension, end) + } + } +} + +/// Orientation and aspect-ratio need special handling. +fn eval_special_feature(name: &str, feature: &Feature, source: &FeatureSource) -> Option { + if name == "orientation" { + let (width, height) = match source { + FeatureSource::Viewport(env) => (env.viewport_width, env.viewport_height), + FeatureSource::Container(c) => (c.width, c.height), + }; + let (Some(width), Some(height)) = (width, height) else { + return Some(false); + }; + let landscape = width > height; + return Some(match &feature.kind { + FeatureKind::Boolean => true, + FeatureKind::Plain { + value: FeatureValue::Ident(ident), + } => match ident.as_str() { + "landscape" => landscape, + "portrait" => !landscape, + _ => false, + }, + _ => false, + }); + } + if name == "aspect-ratio" { + let (width, height) = match source { + FeatureSource::Viewport(env) => (env.viewport_width, env.viewport_height), + FeatureSource::Container(c) => (c.width, c.height), + }; + let (Some(width), Some(height)) = (width, height) else { + return Some(false); + }; + let actual = width / height.max(f32::EPSILON); + return Some(match &feature.kind { + FeatureKind::Boolean => true, + FeatureKind::Plain { value } => match feature_value(value, source) { + Some(ratio) => (actual - ratio).abs() < f32::EPSILON, + None => false, + }, + FeatureKind::Range { cmp, value } => match feature_value(value, source) { + Some(ratio) => compare(*cmp, actual, ratio), + None => false, + }, + FeatureKind::Interval { + start, + start_cmp, + end, + end_cmp, + } => { + let (Some(start), Some(end)) = + (feature_value(start, source), feature_value(end, source)) + else { + return Some(false); + }; + compare(*start_cmp, actual, start) && compare(*end_cmp, actual, end) + } + }); + } + None +} + +/// Environment-driven features that are not plain dimension comparisons. +fn eval_env_feature(name: &str, feature: &Feature, env: &Environment) -> Option { + match name { + "prefers-color-scheme" => Some(match &feature.kind { + FeatureKind::Boolean => true, + FeatureKind::Plain { + value: FeatureValue::Ident(ident), + } => match ident.as_str() { + "light" => env.color_scheme == ColorScheme::Light, + "dark" => env.color_scheme == ColorScheme::Dark, + _ => false, + }, + _ => false, + }), + "prefers-reduced-motion" => Some(match &feature.kind { + FeatureKind::Boolean => true, + FeatureKind::Plain { + value: FeatureValue::Ident(ident), + } => match ident.as_str() { + "reduce" => env.reduced_motion, + "no-preference" => !env.reduced_motion, + _ => false, + }, + _ => false, + }), + "resolution" + | "device-pixel-ratio" + | "min-device-pixel-ratio" + | "max-device-pixel-ratio" => { + let dppx = match &feature.kind { + FeatureKind::Plain { value } => feature_value(value, &FeatureSource::Viewport(env)), + FeatureKind::Range { cmp, value } => { + return Some(match feature_value(value, &FeatureSource::Viewport(env)) { + Some(actual) => compare(*cmp, env.resolution, actual), + None => false, + }); + } + FeatureKind::Boolean => return Some(true), + FeatureKind::Interval { .. } => return Some(false), + }; + Some(match dppx { + Some(actual) => (env.resolution - actual).abs() < f32::EPSILON, + None => false, + }) + } + "color" => Some(true), + "color-index" | "monochrome" | "grid" => Some(match &feature.kind { + FeatureKind::Boolean => false, + FeatureKind::Plain { value } => { + match feature_value(value, &FeatureSource::Viewport(env)) { + Some(actual) => actual == 0.0, + None => false, + } + } + _ => false, + }), + "hover" | "any-hover" | "pointer" | "any-pointer" => Some(match &feature.kind { + FeatureKind::Boolean => false, + FeatureKind::Plain { + value: FeatureValue::Ident(ident), + } => matches!(ident.as_str(), "none"), + _ => false, + }), + "color-gamut" => Some(match &feature.kind { + FeatureKind::Plain { + value: FeatureValue::Ident(ident), + } => matches!(ident.as_str(), "srgb"), + _ => false, + }), + "scripting" => Some(match &feature.kind { + FeatureKind::Boolean => true, + FeatureKind::Plain { + value: FeatureValue::Ident(ident), + } => matches!(ident.as_str(), "enabled" | "initial-only"), + _ => false, + }), + "update" + | "overflow-block" + | "overflow-inline" + | "dynamic-range" + | "video-dynamic-range" + | "prefers-contrast" + | "forced-colors" + | "prefers-transparency" + | "inverted-colors" => Some(match &feature.kind { + FeatureKind::Boolean => false, + _ => false, + }), + _ => None, + } +} + +fn feature_value(value: &FeatureValue, source: &FeatureSource) -> Option { + match value { + FeatureValue::Px(px) => Some(*px), + FeatureValue::RelativeLength { value, unit } => { + let base = match source { + // Media queries resolve em/rem against the root font size. + FeatureSource::Viewport(_) => 16.0, + // Container queries resolve against the container's font + // size, which the terminal model does not carry yet. + FeatureSource::Container(_) => 16.0, + }; + match unit.as_str() { + "em" | "rem" => Some(value * base), + "ch" | "ex" => Some(value * 8.0), + "vw" => match source { + FeatureSource::Viewport(env) => env.viewport_width.map(|w| value * w / 100.0), + FeatureSource::Container(_) => None, + }, + "vh" => match source { + FeatureSource::Viewport(env) => env.viewport_height.map(|h| value * h / 100.0), + FeatureSource::Container(_) => None, + }, + "cqw" | "cqi" => match source { + FeatureSource::Container(c) => c.width.map(|w| value * w / 100.0), + FeatureSource::Viewport(_) => None, + }, + "cqh" | "cqb" => match source { + FeatureSource::Container(c) => c.height.map(|h| value * h / 100.0), + FeatureSource::Viewport(_) => None, + }, + _ => None, + } + } + FeatureValue::Number(n) => Some(*n), + FeatureValue::Integer(i) => Some(*i as f32), + FeatureValue::Boolean(b) => Some((*b as i32) as f32), + FeatureValue::Dppx(d) => Some(*d), + FeatureValue::Ratio(numerator, denominator) => { + if *denominator == 0.0 { + None + } else { + Some(numerator / denominator) + } + } + FeatureValue::Ident(_) => None, + FeatureValue::Unknown => None, + } +} + +fn compare(cmp: Compare, actual: f32, expected: f32) -> bool { + match cmp { + Compare::Equal => (actual - expected).abs() < f32::EPSILON, + Compare::GreaterThan => actual > expected, + Compare::GreaterThanEqual => actual >= expected, + Compare::LessThan => actual < expected, + Compare::LessThanEqual => actual <= expected, + } +} + +/// Evaluate a `@supports` condition (leaves were pre-evaluated by the +/// compiler). +pub fn eval_supports_list(conditions: &[bombshell_css_core::SupportsCondition]) -> bool { + conditions.iter().all(eval_supports) +} + +pub fn eval_supports(condition: &bombshell_css_core::SupportsCondition) -> bool { + use bombshell_css_core::SupportsCondition as C; + match condition { + C::And(conditions) => conditions.iter().all(eval_supports), + C::Or(conditions) => conditions.iter().any(eval_supports), + C::Not(inner) => !eval_supports(inner), + C::Declaration { supported, .. } => *supported, + C::Selector { supported, .. } => *supported, + C::Unknown => false, + } +} diff --git a/experiments/css/crates/css-runtime/src/element.rs b/experiments/css/crates/css-runtime/src/element.rs new file mode 100644 index 0000000..5255db7 --- /dev/null +++ b/experiments/css/crates/css-runtime/src/element.rs @@ -0,0 +1,414 @@ +//! The `parcel_selectors::Element` implementation over the flat +//! [`TreeSnapshot`], plus the runtime semantics for pseudo-classes, +//! `:has()` traversal, and `:nth-child(.. of S)` counting. + +use crate::selectors::{PseudoClass, Selectors, matches_relative, nth_matches}; +use bombshell_css_core::{NO_PARENT, NodeSnapshot, TreeSnapshot}; +use parcel_selectors::attr::CaseSensitivity; +use parcel_selectors::attr::{AttrSelectorOperation, NamespaceConstraint}; +use parcel_selectors::context::MatchingContext; +use parcel_selectors::matching::ElementSelectorFlags; +use parcel_selectors::parser::{NthOfSelectorData, NthType}; +use parcel_selectors::{Element as ParcelElement, OpaqueElement}; + +/// A view of one node in a [`TreeSnapshot`], cheap to clone. +#[derive(Clone, Copy, Debug)] +pub struct MatchElement<'a> { + pub tree: &'a TreeSnapshot, + pub index: usize, +} + +impl<'a> MatchElement<'a> { + pub fn new(tree: &'a TreeSnapshot, index: usize) -> Option { + (index < tree.nodes.len()).then_some(MatchElement { tree, index }) + } + + pub fn node(&self) -> &'a NodeSnapshot { + &self.tree.nodes[self.index] + } + + pub(crate) fn attr(&self, name: &str) -> Option<&'a str> { + self.node() + .attributes + .iter() + .find(|(n, _)| n == name) + .map(|(_, v)| v.as_str()) + } + + /// Resolve an inheritable-ish attribute by walking up the chain + /// (used for `lang` and `dir`). + fn inherited_attr(&self, name: &str) -> Option<&'a str> { + let mut current = *self; + loop { + if let Some(value) = current.attr(name) { + return Some(value); + } + match current.parent_element() { + Some(parent) => current = parent, + None => return None, + } + } + } + + /// Sibling indices sharing this node's parent (contiguous run). + fn siblings(&self) -> impl Iterator + '_ { + let parent = self.tree.parents.get(self.index).copied(); + let tree = self.tree; + let mut start = self.index; + while start > 0 && tree.parents.get(start - 1).copied() == parent { + start -= 1; + } + let mut end = self.index; + while end + 1 < tree.nodes.len() && tree.parents.get(end + 1).copied() == parent { + end += 1; + } + start..=end + } + + /// All descendants (depth first, document order). + fn descendants(&self) -> impl Iterator + '_ { + let tree = self.tree; + let mut stack: Vec = Vec::new(); + // Collect children eagerly (reverse for DFS order). + let children: Vec = tree + .parents + .iter() + .enumerate() + .filter(|&(_, p)| *p == self.index as u32) + .map(|(i, _)| i) + .collect(); + for child in children.iter().rev() { + stack.push(*child); + } + std::iter::from_fn(move || { + let index = stack.pop()?; + for child in tree + .parents + .iter() + .enumerate() + .filter(|&(_, p)| *p == index as u32) + .map(|(i, _)| i) + .collect::>() + .into_iter() + .rev() + { + stack.push(child); + } + Some(index) + }) + } + + /// Following siblings of this element and all of their descendants. + fn following_siblings_and_descendants(&self) -> impl Iterator + '_ { + let tree = self.tree; + let parent = self.tree.parents.get(self.index).copied(); + let following: Vec = (self.index + 1..tree.nodes.len()) + .filter(|&i| tree.parents.get(i).copied() == parent) + .collect(); + following.into_iter().flat_map(move |sibling| { + std::iter::once(sibling).chain( + MatchElement::new(tree, sibling) + .map(|el| el.descendants().collect::>()) + .unwrap_or_default(), + ) + }) + } + + fn has_focus_within(&self) -> bool { + if self.node().focus { + return true; + } + self.descendants().any(|i| self.tree.nodes[i].focus) + } + + /// Candidates addressable by `:has()` relative selectors: everything + /// anchored at this element — its descendants, its following siblings, + /// and the descendants of those siblings. + fn has_candidates(&self) -> impl Iterator> + '_ { + self.descendants() + .chain(self.following_siblings_and_descendants()) + .filter_map(move |index| MatchElement::new(self.tree, index)) + } + + fn matches_any_of( + &self, + selectors: &[crate::selectors::Selector], + scope: &MatchElement, + ) -> bool { + selectors + .iter() + .any(|selector| matches_relative(selector, self, scope)) + } + + fn nth_of_matches(&self, data: &NthOfSelectorData<'_, Selectors>) -> bool { + let nth = data.nth_data(); + if matches!(nth.ty, NthType::Col | NthType::LastCol) { + return false; + } + let mut nth_cache = parcel_selectors::NthIndexCache::default(); + let mut context = MatchingContext::new( + parcel_selectors::context::MatchingMode::Normal, + None, + Some(&mut nth_cache), + parcel_selectors::context::QuirksMode::NoQuirks, + ); + let mut flags = |_: &MatchElement, _: ElementSelectorFlags| {}; + + let of_selectors = data.selectors(); + let mut matches_of = |index: usize| -> bool { + MatchElement::new(self.tree, index).is_some_and(|el| { + of_selectors.iter().any(|selector| { + parcel_selectors::matching::matches_selector( + selector, + 0, + None, + &el, + &mut context, + &mut flags, + ) + }) + }) + }; + + let from_end = matches!(nth.ty, NthType::LastChild | NthType::LastOfType); + let of_type = matches!(nth.ty, NthType::OfType | NthType::LastOfType); + + let mut matching: Vec = Vec::new(); + for sibling in self.siblings() { + if of_type && self.tree.nodes[sibling].tag != self.node().tag { + continue; + } + if !of_selectors.is_empty() && !matches_of(sibling) { + continue; + } + matching.push(sibling); + } + + let count = if from_end { + matching + .iter() + .rposition(|&i| i == self.index) + .map(|p| p + 1) + } else { + matching + .iter() + .position(|&i| i == self.index) + .map(|p| p + 1) + }; + let Some(count) = count else { return false }; + nth_matches(data.nth_data(), count as i32) + } +} + +impl<'i, 'a> ParcelElement<'i> for MatchElement<'a> { + type Impl = Selectors; + + fn opaque(&self) -> OpaqueElement { + OpaqueElement::new(&self.tree.nodes[self.index]) + } + + fn parent_element(&self) -> Option { + self.tree + .parent_of(self.index) + .and_then(|index| MatchElement::new(self.tree, index)) + } + + fn parent_node_is_shadow_root(&self) -> bool { + false + } + + fn containing_shadow_host(&self) -> Option { + None + } + + fn is_pseudo_element(&self) -> bool { + false + } + + fn prev_sibling_element(&self) -> Option { + let parent = self.tree.parents.get(self.index).copied(); + (self.index > 0 && self.tree.parents.get(self.index - 1).copied() == parent).then(|| { + MatchElement { + tree: self.tree, + index: self.index - 1, + } + }) + } + + fn next_sibling_element(&self) -> Option { + let parent = self.tree.parents.get(self.index).copied(); + (self.index + 1 < self.tree.nodes.len() + && self.tree.parents.get(self.index + 1).copied() == parent) + .then(|| MatchElement { + tree: self.tree, + index: self.index + 1, + }) + } + + fn is_html_element_in_html_document(&self) -> bool { + false + } + + fn has_local_name(&self, local_name: &str) -> bool { + self.node().tag == local_name + } + + fn has_namespace(&self, ns: &str) -> bool { + ns.is_empty() + } + + fn is_same_type(&self, other: &Self) -> bool { + self.node().tag == other.node().tag + } + + fn attr_matches( + &self, + ns: &NamespaceConstraint< + &>::NamespaceUrl, + >, + local_name: &>::LocalName, + operation: &AttrSelectorOperation< + &>::AttrValue, + >, + ) -> bool { + let namespace_ok = match ns { + NamespaceConstraint::Any => true, + // Elements live in no namespace; only the empty URL can match. + NamespaceConstraint::Specific(url) => url.as_ref().is_empty(), + }; + if !namespace_ok { + return false; + } + let name = local_name.as_ref(); + let Some(value) = self.attr(name) else { + return false; + }; + // `eval_str` implements the full operator semantics (including the + // `i`/`s` flags resolved by the parser). + operation.eval_str(value) + } + + fn match_non_ts_pseudo_class( + &self, + pc: &PseudoClass<'i>, + _context: &mut MatchingContext<'_, 'i, Selectors>, + _flags_setter: &mut F, + ) -> bool + where + F: FnMut(&Self, ElementSelectorFlags), + { + let node = self.node(); + match pc { + PseudoClass::Hover => node.hover, + PseudoClass::Active => node.active, + PseudoClass::Focus => node.focus, + PseudoClass::FocusVisible => node.focus, + PseudoClass::FocusWithin => self.has_focus_within(), + PseudoClass::Disabled => self.attr("disabled").is_some(), + PseudoClass::Enabled => self.attr("disabled").is_none(), + PseudoClass::Checked => self.attr("checked").is_some(), + PseudoClass::Required => self.attr("required").is_some(), + PseudoClass::Optional => self.attr("required").is_none(), + PseudoClass::ReadOnly => { + self.attr("readonly").is_some() || self.attr("disabled").is_some() + } + PseudoClass::ReadWrite => { + self.attr("readonly").is_none() && self.attr("disabled").is_none() + } + PseudoClass::PlaceholderShown => self.attr("placeholder").is_some(), + PseudoClass::Lang(languages) => self + .inherited_attr("lang") + .is_some_and(|lang| languages.iter().any(|want| lang_matches(lang, want))), + PseudoClass::Dir(dir) => self + .inherited_attr("dir") + .is_some_and(|value| value.eq_ignore_ascii_case(&*dir)), + PseudoClass::NthOf(data) => self.nth_of_matches(data), + PseudoClass::Has(selectors) => self + .has_candidates() + .any(|candidate| candidate.matches_any_of(selectors, self)), + PseudoClass::NeverMatches => false, + } + } + + fn match_pseudo_element( + &self, + _pe: &crate::selectors::PseudoElement, + _context: &mut MatchingContext<'_, 'i, Selectors>, + ) -> bool { + false + } + + fn is_link(&self) -> bool { + false + } + + fn is_html_slot_element(&self) -> bool { + false + } + + fn has_id( + &self, + id: &>::Identifier, + case_sensitivity: CaseSensitivity, + ) -> bool { + self.node() + .id + .as_deref() + .is_some_and(|value| case_eq(case_sensitivity, value, id.as_ref())) + } + + fn has_class( + &self, + name: &>::Identifier, + case_sensitivity: CaseSensitivity, + ) -> bool { + self.node() + .classes + .iter() + .any(|class| case_eq(case_sensitivity, class, name.as_ref())) + } + + fn imported_part( + &self, + _name: &>::Identifier, + ) -> Option<>::Identifier> { + None + } + + fn is_part( + &self, + _name: &>::Identifier, + ) -> bool { + false + } + + fn is_empty(&self) -> bool { + !self.tree.parents.contains(&(self.index as u32)) + } + + fn is_root(&self) -> bool { + matches!(self.tree.parents.get(self.index), None | Some(&NO_PARENT)) + } + + fn ignores_nth_child_selectors(&self) -> bool { + false + } +} + +fn case_eq(case_sensitivity: CaseSensitivity, a: &str, b: &str) -> bool { + match case_sensitivity { + CaseSensitivity::CaseSensitive => a == b, + CaseSensitivity::AsciiCaseInsensitive => a.eq_ignore_ascii_case(b), + } +} + +/// CSS `lang()` matching: exact (case-insensitive) or wildcard prefix on `-`. +fn lang_matches(actual: &str, wanted: &str) -> bool { + let actual = actual.trim(); + let wanted = wanted.trim(); + actual.eq_ignore_ascii_case(wanted) + || (actual + .get(..wanted.len()) + .is_some_and(|prefix| prefix.eq_ignore_ascii_case(wanted)) + && actual.as_bytes().get(wanted.len()) == Some(&b'-')) +} diff --git a/experiments/css/crates/css-runtime/src/lib.rs b/experiments/css/crates/css-runtime/src/lib.rs new file mode 100644 index 0000000..cc1f9b5 --- /dev/null +++ b/experiments/css/crates/css-runtime/src/lib.rs @@ -0,0 +1,38 @@ +//! Selector matching and cascade for the Bombshell CSS pipeline. +//! +//! The runtime consumes the versioned stylesheet IR emitted by +//! `bombshell-css-compiler` (or any host that produces the same contract) +//! and resolves computed styles against a flat DOM [`TreeSnapshot`]: +//! +//! - selector matching via `parcel_selectors`, the engine lightningcss +//! itself uses, adapted to the snapshot model (see [`selectors`] and +//! [`element`]); +//! - cascade by origin/importance, `@layer`, specificity, and source order +//! (see [`cascade`]); +//! - inheritance, custom properties, `var()` substitution, and CSS-wide +//! keywords; +//! - `@media`, `@container`, and `@supports` condition evaluation against +//! the [`Environment`] (see [`conditions`]). + +pub mod cascade; +pub mod conditions; +pub mod element; +pub mod selectors; +pub mod values; + +pub use bombshell_css_core::{Environment, NodeSnapshot, TreeSnapshot}; + +pub use cascade::{ComputedStyle, Stylesheet}; +pub use conditions::{ContainerAncestor, ContainerType}; +pub use element::MatchElement; +pub use selectors::{SelectorList, parse_selector_list}; + +/// Resolve the computed style for `target`. +pub fn compute<'ir>( + sheets: &[&Stylesheet<'ir>], + tree: &TreeSnapshot, + target: usize, + env: &Environment, +) -> Option> { + cascade::compute(sheets, tree, target, env) +} diff --git a/experiments/css/crates/css-runtime/src/selectors.rs b/experiments/css/crates/css-runtime/src/selectors.rs new file mode 100644 index 0000000..3908e71 --- /dev/null +++ b/experiments/css/crates/css-runtime/src/selectors.rs @@ -0,0 +1,40 @@ +//! Matching glue over the selector engine (which lives in `bombshell-css-core` +//! so the compiler and runtime share one parser). + +pub use bombshell_css_core::selectors::*; + +use crate::element::MatchElement; +use parcel_selectors::matching::matches_selector; +use parcel_selectors::parser::{NthSelectorData, NthType}; +use parcel_selectors::{Element as ParcelElement, NthIndexCache}; + +/// Match one relative selector (from `:has()`) with `scope` pinned to the +/// anchoring element. +pub(crate) fn matches_relative( + selector: &Selector, + candidate: &MatchElement, + scope: &MatchElement, +) -> bool { + let mut nth_cache = NthIndexCache::default(); + let mut context = parcel_selectors::context::MatchingContext::new( + parcel_selectors::context::MatchingMode::Normal, + None, + Some(&mut nth_cache), + parcel_selectors::context::QuirksMode::NoQuirks, + ); + context.scope_element = Some(scope.opaque()); + let mut flags = |_: &MatchElement, _: parcel_selectors::matching::ElementSelectorFlags| {}; + matches_selector(selector, 0, None, candidate, &mut context, &mut flags) +} + +/// Nth arithmetic shared by the `NthOf` evaluator. +pub(crate) fn nth_matches(nth: &NthSelectorData, count: i32) -> bool { + if matches!(nth.ty, NthType::Col | NthType::LastCol) { + return false; + } + if nth.a == 0 { + return count == nth.b; + } + let delta = count - nth.b; + delta % nth.a == 0 && delta / nth.a >= 0 +} diff --git a/experiments/css/crates/css-runtime/src/values.rs b/experiments/css/crates/css-runtime/src/values.rs new file mode 100644 index 0000000..32f3188 --- /dev/null +++ b/experiments/css/crates/css-runtime/src/values.rs @@ -0,0 +1,410 @@ +//! `var()` substitution against resolved custom properties, and +//! `light-dark()` resolution against the environment's color scheme. +//! +//! Values are canonical CSS text; substitution walks the token stream so +//! strings and nested functions are handled correctly. Cycles resolve to +//! `None` (the declaration becomes invalid at computed-value time and the +//! caller falls back to inheritance). + +use bombshell_css_core::tokens::write_token; +use bombshell_css_core::ColorScheme; +use cssparser::{Parser as CssParser, ParserInput, Token}; + +use crate::cascade::StyleMap; + +/// Resolve every `var(--x[, fallback])` in `value` against `custom`. +/// +/// Returns `None` when a referenced variable is missing (no fallback) or a +/// cycle is detected, mirroring "invalid at computed-value time". +pub fn resolve_vars(value: &str, custom: &StyleMap<'_>) -> Option { + if !value.contains("var(") { + return Some(value.to_string()); + } + let mut resolving = Vec::new(); + resolve_value(value, custom, &mut resolving, 0) +} + +fn resolve_value( + value: &str, + custom: &StyleMap<'_>, + resolving: &mut Vec, + depth: u32, +) -> Option { + if depth > 32 { + return None; + } + + // Every value this function returns is canonical: the token walk + // re-serializes numbers and whitespace even when no `var(` remains + // (custom-property values arrive verbatim and must still come out + // canonical — the conformance corpus pins that). + let mut input = ParserInput::new(value); + let mut parser = CssParser::new(&mut input); + let mut out = String::new(); + + loop { + match parser.next_including_whitespace() { + Ok(token) => match token { + Token::Function(name) if name.eq_ignore_ascii_case("var") => { + let substitution = parse_var_arguments(&mut parser, custom, resolving, depth)?; + out.push_str(&substitution); + } + Token::Function(name) => { + out.push_str(name); + out.push('('); + let inner = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_tokens(parser, &mut out, custom, resolving, depth); + Ok(()) + }, + ); + let _ = inner; + out.push(')'); + } + Token::ParenthesisBlock => { + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_tokens(parser, &mut out, custom, resolving, depth); + Ok(()) + }, + ); + out.push(')'); + } + other => write_token(&mut out, &other), + }, + Err(_) => break, + } + } + Some(out) +} + +/// Read the arguments of `var(name, fallback?)` and produce the substituted +/// text. +fn parse_var_arguments( + parser: &mut CssParser, + custom: &StyleMap<'_>, + resolving: &mut Vec, + depth: u32, +) -> Option { + let mut name: Option = None; + let mut fallback = String::new(); + let mut in_fallback = false; + + let _ = parser.parse_nested_block(|parser| -> Result<(), cssparser::ParseError<'_, ()>> { + loop { + match parser.next_including_whitespace() { + Ok(token) => match token { + Token::Ident(ident) if name.is_none() && !in_fallback => { + name = Some(ident.to_string()); + } + Token::Comma if !in_fallback => { + in_fallback = true; + } + other => { + if !in_fallback && name.is_some() { + // Junk between the name and the comma makes + // the var() invalid. + return Err(cssparser::ParseError { + kind: cssparser::ParseErrorKind::Basic( + cssparser::BasicParseErrorKind::UnexpectedToken(other.clone()), + ), + location: parser.current_source_location(), + }); + } + // The fallback may itself contain var() refs and + // nested functions; descend like the main path. + match other { + Token::Function(fn_name) if fn_name.eq_ignore_ascii_case("var") => { + let substitution = + match parse_var_arguments(parser, custom, resolving, depth) { + Some(text) => text, + None => return Ok(()), + }; + fallback.push_str(&substitution); + } + Token::Function(fn_name) => { + fallback.push_str(fn_name); + fallback.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_tokens( + parser, + &mut fallback, + custom, + resolving, + depth, + ); + Ok(()) + }, + ); + fallback.push(')'); + } + Token::ParenthesisBlock => { + fallback.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_tokens( + parser, + &mut fallback, + custom, + resolving, + depth, + ); + Ok(()) + }, + ); + fallback.push(')'); + } + inner => write_token(&mut fallback, &inner), + } + } + }, + Err(_) => break, + } + } + Ok(()) + }); + + let name = name?; + if !name.starts_with("--") { + return None; + } + if resolving.contains(&name) { + return None; + } + + if let Some(value) = custom.get(name.as_str()) { + resolving.push(name); + let resolved = resolve_value(value, custom, resolving, depth + 1); + resolving.pop(); + return resolved; + } + + if in_fallback { + resolve_value(fallback.trim(), custom, resolving, depth + 1) + } else { + None + } +} + +/// Serialize the remaining tokens of a nested block into `out`, resolving +/// any `var()` references along the way. +fn write_tokens( + parser: &mut CssParser, + out: &mut String, + custom: &StyleMap<'_>, + resolving: &mut Vec, + depth: u32, +) { + loop { + match parser.next_including_whitespace() { + Ok(token) => match token { + Token::Function(name) if name.eq_ignore_ascii_case("var") => { + let substitution = match parse_var_arguments(parser, custom, resolving, depth) { + Some(text) => text, + None => return, + }; + out.push_str(&substitution); + } + Token::Function(name) => { + out.push_str(name); + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_tokens(parser, out, custom, resolving, depth); + Ok(()) + }, + ); + out.push(')'); + } + Token::ParenthesisBlock => { + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_tokens(parser, out, custom, resolving, depth); + Ok(()) + }, + ); + out.push(')'); + } + other => write_token(out, &other), + }, + Err(_) => break, + } + } +} + +/// Resolve every `light-dark(light, dark)` in a color value against the +/// environment's color scheme, returning the computed value. `None` marks +/// the value invalid at computed-value time (a malformed call — anything +/// other than exactly two arguments). +/// +/// Runs after `var()` substitution: a custom property may carry +/// `light-dark()` verbatim into the using declaration. Branches are emitted +/// verbatim — the compiler canonicalized stylesheet branches, and inline +/// styles pass through like every other inline value. +pub fn resolve_light_dark(value: &str, scheme: ColorScheme) -> Option { + if !value.contains("light-dark(") { + return Some(value.to_string()); + } + let mut input = ParserInput::new(value); + let mut parser = CssParser::new(&mut input); + let mut out = String::with_capacity(value.len()); + write_light_dark_tokens(&mut parser, &mut out, scheme)?; + Some(out) +} + +/// Token walk that rewrites `light-dark()` functions in place; other +/// functions and parens recurse without interpretation. `None` marks a +/// malformed `light-dark()` anywhere in the value. +fn write_light_dark_tokens( + parser: &mut CssParser<'_, '_>, + out: &mut String, + scheme: ColorScheme, +) -> Option<()> { + let mut malformed = false; + loop { + match parser.next_including_whitespace() { + Ok(token) => match token { + Token::Function(name) if name.eq_ignore_ascii_case("light-dark") => { + match parse_light_dark_args(parser) { + Some((light, dark)) => { + out.push_str(match scheme { + ColorScheme::Light => light.trim(), + ColorScheme::Dark => dark.trim(), + }); + } + None => malformed = true, + } + } + Token::Function(name) => { + out.push_str(name); + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + if write_light_dark_tokens(parser, out, scheme).is_none() { + malformed = true; + } + Ok(()) + }, + ); + out.push(')'); + } + Token::ParenthesisBlock => { + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + if write_light_dark_tokens(parser, out, scheme).is_none() { + malformed = true; + } + Ok(()) + }, + ); + out.push(')'); + } + other => write_token(out, &other), + }, + Err(_) => break, + } + } + if malformed { + return None; + } + Some(()) +} + +/// Read the two color arguments of `light-dark(...)`. The contents are +/// serialized verbatim; a second top-level comma, an empty branch, or a +/// non-paren block makes the call malformed. +fn parse_light_dark_args(parser: &mut CssParser<'_, '_>) -> Option<(String, String)> { + let mut light = String::new(); + let mut dark = String::new(); + let mut seen_comma = false; + let mut malformed = false; + let _ = parser.parse_nested_block(|parser| -> Result<(), cssparser::ParseError<'_, ()>> { + loop { + match parser.next_including_whitespace() { + Ok(token) => match token { + Token::Comma => { + if seen_comma { + malformed = true; + } + seen_comma = true; + } + Token::Function(name) => { + let branch = if seen_comma { &mut dark } else { &mut light }; + branch.push_str(name); + branch.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_branch_tokens(parser, branch); + Ok(()) + }, + ); + branch.push(')'); + } + Token::ParenthesisBlock => { + let branch = if seen_comma { &mut dark } else { &mut light }; + branch.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_branch_tokens(parser, branch); + Ok(()) + }, + ); + branch.push(')'); + } + // Square/curly blocks cannot appear inside a color. + Token::SquareBracketBlock | Token::CurlyBracketBlock => { + malformed = true; + } + other => { + let branch = if seen_comma { &mut dark } else { &mut light }; + write_token(branch, &other); + } + }, + Err(_) => break, + } + } + Ok(()) + }); + if malformed || !seen_comma || light.trim().is_empty() || dark.trim().is_empty() { + return None; + } + Some((light, dark)) +} + +/// Verbatim token serialization for `light-dark()` branches: no `var()` +/// resolution (substitution already ran) and no rewriting. +fn write_branch_tokens(parser: &mut CssParser<'_, '_>, out: &mut String) { + loop { + match parser.next_including_whitespace() { + Ok(token) => match token { + Token::Function(name) => { + out.push_str(name); + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_branch_tokens(parser, out); + Ok(()) + }, + ); + out.push(')'); + } + Token::ParenthesisBlock => { + out.push('('); + let _ = parser.parse_nested_block( + |parser| -> Result<(), cssparser::ParseError<'_, ()>> { + write_branch_tokens(parser, out); + Ok(()) + }, + ); + out.push(')'); + } + other => write_token(out, &other), + }, + Err(_) => break, + } + } +} diff --git a/experiments/css/crates/css-runtime/tests/runtime.rs b/experiments/css/crates/css-runtime/tests/runtime.rs new file mode 100644 index 0000000..c9de400 --- /dev/null +++ b/experiments/css/crates/css-runtime/tests/runtime.rs @@ -0,0 +1,741 @@ +//! End-to-end runtime tests: compile CSS, load the IR, and resolve computed +//! styles against tree snapshots. + +use bombshell_css_compiler::compile; +use bombshell_css_core::{Environment, NO_PARENT, NodeSnapshot, Origin, TreeSnapshot}; +use bombshell_css_runtime::{Stylesheet, compute}; + +fn node(tag: &str) -> NodeSnapshot { + NodeSnapshot { + tag: tag.to_string(), + ..Default::default() + } +} + +fn tree(nodes: Vec, parents: Vec) -> TreeSnapshot { + TreeSnapshot { nodes, parents } +} + +/// An owned compiled case; [`Case::sheet`] borrows the parsed stylesheet +/// from the IR it keeps alive. +struct Case { + ir: bombshell_css_core::CompiledStylesheet, + index: usize, +} + +impl Case { + fn sheet(&self) -> Stylesheet<'_> { + Stylesheet::from_ir(&self.ir, self.index) + } +} + +fn stylesheet(css: &str) -> Case { + let out = compile(css, Origin::Author, Default::default()); + assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics); + Case { + ir: out.sheet.expect("sheet"), + index: 0, + } +} + +fn get<'a>(style: &'a bombshell_css_runtime::ComputedStyle, name: &str) -> &'a str { + style + .get(name) + .unwrap_or_else(|| panic!("missing {name}: {:?}", style.declarations)) +} + +#[test] +fn inline_styles_cascade_above_selectors() { + // All cases bind first: the invariant `SelectorList` borrow unifies IR + // lifetimes across the sheets of a single `compute` call, so every + // `Case` must outlive every `Stylesheet`. + let case = stylesheet(".card { color: #fff; background: black }"); + let important_case = stylesheet(".card { color: red !important }"); + let other_case = stylesheet(".other { color: red !important }"); + let sheet = case.sheet(); + let important = important_case.sheet(); + let other = other_case.sheet(); + let env = Environment::default(); + + // Inline-normal beats every author stylesheet declaration. + let mut n = node("card"); + n.classes = vec!["card".into()]; + n.style = Some("color: blue; border: none".into()); + let t = tree(vec![n], vec![NO_PARENT]); + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "blue"); + assert_eq!(get(&s, "background"), "black"); + assert_eq!(get(&s, "border"), "none"); + + // Author `!important` beats inline-normal… + let s = compute(&[&sheet, &important], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "red"); + // …even when the important rule is in an earlier sheet. + let s = compute(&[&important, &sheet], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "red"); + + // …and an `!important` in a rule that does NOT match the node must not + // shield the property: the inline style wins. + let s = compute(&[&other, &sheet], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "blue"); + + // Inline `!important` beats author stylesheet `!important`. + let mut n_imp = node("card"); + n_imp.classes = vec!["card".into()]; + n_imp.style = Some("color: blue !important".into()); + let t_imp = tree(vec![n_imp], vec![NO_PARENT]); + let s = compute(&[&sheet, &important], &t_imp, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "blue"); +} + +#[test] +fn inline_styles_participate_in_inheritance() { + // Inline declarations are part of the node's declared values BEFORE + // var() substitution and inheritance, so descendants inherit the + // inline-overridden computed values. + let case = stylesheet(".child { color: var(--brand) }"); + let sheet = case.sheet(); + let env = Environment::default(); + let mut parent = node("root"); + parent.style = Some("--brand: red".into()); + let mut child = node("child"); + child.classes = vec!["child".into()]; + let t = tree(vec![parent, child], vec![NO_PARENT, 0]); + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s, "color"), "red"); +} + +#[test] +fn inline_styles_reject_malformed_declarations() { + // url() with a data URI keeps its colons and semicolons intact; junk + // parts are dropped instead of poisoning the cascade. + let case = stylesheet(".card { color: #fff }"); + let sheet = case.sheet(); + let env = Environment::default(); + let mut n = node("card"); + n.classes = vec!["card".into()]; + n.style = Some("background: url(data:image/png;base64,AAA); ::bad; color".into()); + let t = tree(vec![n], vec![NO_PARENT]); + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "#fff"); + assert_eq!( + get(&s, "background"), + "url(data:image/png;base64,AAA)" + ); +} + +#[test] +fn matches_selectors() { + let css = r" + box { color: red } + .panel { color: green } + #main { color: blue } + .a.b { color: yellow } + [disabled] { opacity: 0.5 } + [role=tab] { text-transform: uppercase } + [data-x^='pre'] { text-decoration: underline } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + node("box"), + { + let mut n = node("div"); + n.classes = vec!["panel".into(), "a".into(), "b".into()]; + n.attributes = vec![ + ("disabled".into(), "".into()), + ("role".into(), "tab".into()), + ("data-x".into(), "prefix-1".into()), + ]; + n + }, + { + let mut n = node("span"); + n.id = Some("main".into()); + n + }, + ], + vec![NO_PARENT, NO_PARENT, NO_PARENT], + ); + let env = Environment::default(); + + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(), + "color" + ), + "red" + ); + // .a.b wins over .panel (higher specificity). + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(), + "color" + ), + "#ff0" + ); + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(), + "opacity" + ), + ".5" + ); + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(), + "text-transform" + ), + "uppercase" + ); + // [data-x^='pre'] also matched. + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(), + "text-decoration" + ), + "underline" + ); + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(), + "color" + ), + "#00f" + ); +} + +#[test] +fn matches_combinators_and_structural_pseudos() { + let css = r" + .list > .item { color: red } + .root .item { color: green } + .item:first-child { color: blue } + .item:last-child { color: yellow } + .item + .item { font-weight: bold } + .item:nth-child(2n) { opacity: 0.5 } + .item:only-child { visibility: hidden } + .root:has(.special) .item { text-decoration: line-through } + .item:not(.skip) { cursor: pointer } + .wrap:is(.a, .b) .item { text-align: center } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + { + let mut n = node("root"); + n.classes = vec!["root".into()]; + n + }, // 0 + { + let mut n = node("wrap"); + n.classes = vec!["wrap".into(), "a".into()]; + n + }, // 1 + { + let mut n = node("list"); + n.classes = vec!["list".into()]; + n + }, // 2 + { + let mut n = node("item"); + n.classes = vec!["item".into()]; + n + }, // 3 + { + let mut n = node("item"); + n.classes = vec!["item".into()]; + n + }, // 4 + { + let mut n = node("item"); + n.classes = vec!["item".into(), "special".into()]; + n + }, // 5 + ], + vec![NO_PARENT, 0, 1, 2, 2, 2], + ); + let env = Environment::default(); + + // item 3: first-child; ancestor `.root:has(.special)` styles all items + let s3 = compute(std::slice::from_ref(&&sheet), &t, 3, &env).unwrap(); + assert_eq!(get(&s3, "color"), "#00f"); + assert_eq!(get(&s3, "cursor"), "pointer"); + assert_eq!(get(&s3, "text-align"), "center"); + assert_eq!(get(&s3, "text-decoration"), "line-through"); + // no `+` previous sibling → no bold + assert!(s3.get("font-weight").is_none()); + + // item 4: nth-child(2), has previous sibling → bold + let s4 = compute(std::slice::from_ref(&&sheet), &t, 4, &env).unwrap(); + assert_eq!(get(&s4, "color"), "green"); + assert_eq!(get(&s4, "font-weight"), "700"); + assert_eq!(get(&s4, "opacity"), ".5"); + assert_eq!(get(&s4, "text-decoration"), "line-through"); + + // item 5: last-child; :not(.skip) applies + let s5 = compute(std::slice::from_ref(&&sheet), &t, 5, &env).unwrap(); + assert_eq!(get(&s5, "color"), "#ff0"); + assert_eq!(get(&s5, "cursor"), "pointer"); +} + +#[test] +fn state_pseudos_match() { + let css = r" + .btn { color: gray } + .btn:hover { color: white } + .btn:active { color: black } + .btn:focus { outline: 1px } + .btn:focus-within { border-color: cyan } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + node("app"), + { + let mut n = node("btn"); + n.classes = vec!["btn".into()]; + n.hover = true; + n + }, + { + let mut n = node("btn"); + n.classes = vec!["btn".into()]; + n.active = true; + n.focus = true; + n + }, + ], + vec![NO_PARENT, 0, 0], + ); + let env = Environment::default(); + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(), + "color" + ), + "#fff" + ); + let s2 = compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(); + assert_eq!(get(&s2, "color"), "#000"); + assert_eq!(get(&s2, "outline"), "1px"); + // app has no focus; focus-within on ancestors of focused node — app is ancestor, but we only computed leaf nodes; focus-within on btn itself also true + assert_eq!(get(&s2, "border-color"), "#0ff"); +} + +#[test] +fn cascades_by_origin_layer_specificity_order() { + // One shared IR owner: every stylesheet borrows its parsed selectors + // from the same `CompiledStylesheet` list (the borrow of a + // `SelectorList` is invariant, so multi-sheet calls need one owner). + let mut irs = Vec::new(); + let mut push = |css: &str, origin: Origin, index: usize| { + let out = compile(css, origin, Default::default()); + assert!(out.diagnostics.is_empty(), "{:?}", out.diagnostics); + irs.push((out.sheet.expect("sheet"), index)); + }; + push(".x { color: red; padding: 1px }", Origin::Author, 0); + push(".x { color: green }", Origin::Author, 1); + push(".x { color: blue !important }", Origin::Author, 2); + push("@layer a { .x { color: cyan } }", Origin::Author, 3); + push(".x { color: white !important }", Origin::User, 4); + let sheets: Vec = irs + .iter() + .map(|(ir, index)| Stylesheet::from_ir(ir, *index)) + .collect(); + let [author, author_later, author_important, layered, important_user] = &sheets[..] else { + panic!("five sheets"); + }; + + let t = tree( + vec![{ + let mut n = node("div"); + n.classes = vec!["x".into()]; + n + }], + vec![NO_PARENT], + ); + let env = Environment::default(); + + // Later author rule wins over earlier. + let s = compute(&[&author, &author_later], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "green"); + assert_eq!(get(&s, "padding"), "1px"); + + // !important beats normal even from an earlier sheet. + let s = compute(&[&author, &author_important], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "#00f"); + + // Unlayered beats layered. + let s = compute(&[&author, &layered], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "red"); + + // User !important beats author !important. + let s = compute(&[&author_important, &important_user], &t, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "#fff"); + + // Specificity: #id beats .class. + let specific_case = stylesheet("#y { color: purple } .x { color: orange }"); + let specific = specific_case.sheet(); + let t2 = tree( + vec![{ + let mut n = node("div"); + n.id = Some("y".into()); + n.classes = vec!["x".into()]; + n + }], + vec![NO_PARENT], + ); + let s = compute(&[&specific], &t2, 0, &env).unwrap(); + assert_eq!(get(&s, "color"), "purple"); +} + +#[test] +fn inherits_and_resolves_custom_properties() { + let css = r" + :root { + --brand: oklch(70% .2 40); + --gap: 8px; + color: var(--brand); + } + .box { border-color: var(--brand); margin: var(--gap) } + .box { --gap: 4px } + .leaf { border-color: inherit } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + node("root"), // 0 + { + let mut n = node("box"); + n.classes = vec!["box".into()]; + n + }, // 1 + { + let mut n = node("leaf"); + n.classes = vec!["leaf".into()]; + n + }, // 2 + ], + vec![NO_PARENT, 0, 1], + ); + let env = Environment::default(); + + let s0 = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + assert_eq!(get(&s0, "color"), "oklch(70% .2 40)"); + assert_eq!(get(&s0, "--brand"), "oklch(70% .2 40)"); + + // color inherits from root; --gap overridden locally; border-color via var + let s1 = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s1, "color"), "oklch(70% .2 40)"); + assert_eq!(get(&s1, "border-color"), "oklch(70% .2 40)"); + assert_eq!(get(&s1, "margin"), "4px"); + assert_eq!(get(&s1, "--gap"), "4px"); + + // explicit inherit keyword pulls parent's border-color + let s2 = compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(); + assert_eq!(get(&s2, "border-color"), "oklch(70% .2 40)"); + assert_eq!(get(&s2, "--gap"), "4px"); +} + +#[test] +fn var_fallbacks_and_cycles() { + let css = r" + .a { color: var(--missing, red) } + .b { --x: var(--y); --y: var(--x); color: var(--x) } + .c { color: var(--missing) } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + { + let mut n = node("d"); + n.classes = vec!["a".into()]; + n + }, + { + let mut n = node("d"); + n.classes = vec!["b".into()]; + n + }, + { + let mut n = node("d"); + n.classes = vec!["c".into()]; + n + }, + ], + vec![NO_PARENT, NO_PARENT, NO_PARENT], + ); + let env = Environment::default(); + assert_eq!( + get( + &compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(), + "color" + ), + "red" + ); + // Cycle → declaration dropped. + assert!( + compute(std::slice::from_ref(&&sheet), &t, 1, &env) + .unwrap() + .get("color") + .is_none() + ); + // Missing without fallback → dropped. + assert!( + compute(std::slice::from_ref(&&sheet), &t, 2, &env) + .unwrap() + .get("color") + .is_none() + ); +} + +#[test] +fn evaluates_media_container_supports() { + let css = r" + @media (min-width: 400px) { .m { color: red } } + @media (min-width: 1000px) { .m { color: green } } + @media (prefers-color-scheme: dark) { .m { color: white } } + @container panel (inline-size > 300px) { .c { color: blue } } + @supports (color: oklch(70% .2 40)) { .s { color: oklch(70% .2 40) } } + @supports (bogus-property: 1px) { .s { color: black } } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + { + let mut n = node("app"); + n.width = Some(500.0); + n.height = Some(100.0); + n + }, // container + { + let mut n = node("m"); + n.classes = vec!["m".into()]; + n + }, + { + let mut n = node("c"); + n.classes = vec!["c".into()]; + n + }, + { + let mut n = node("s"); + n.classes = vec!["s".into()]; + n + }, + ], + vec![NO_PARENT, 0, 0, 0], + ); + let env = Environment { + viewport_width: Some(600.0), + viewport_height: Some(800.0), + color_scheme: bombshell_css_core::ColorScheme::Dark, + ..Default::default() + }; + // Both the 400px rule and the dark-scheme rule match; the dark rule is + // later in source order, so it wins. + let s1 = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s1, "color"), "#fff"); + + // With a light scheme only the viewport rule matches. + let light = Environment { + viewport_width: Some(600.0), + viewport_height: Some(800.0), + ..Default::default() + }; + let s1 = compute(std::slice::from_ref(&&sheet), &t, 1, &light).unwrap(); + assert_eq!(get(&s1, "color"), "red"); + + let s2 = compute(std::slice::from_ref(&&sheet), &t, 2, &env).unwrap(); + assert!(s2.get("color").is_none(), "no container ancestor yet"); + + let s3 = compute(std::slice::from_ref(&&sheet), &t, 3, &env).unwrap(); + assert_eq!(get(&s3, "color"), "oklch(70% .2 40)"); +} + +#[test] +fn container_queries_evaluate_against_ancestors() { + let css = r" + .panel { + container-type: inline-size; + container-name: panel; + } + @container panel (inline-size > 300px) { .card { color: blue } } + @container (inline-size <= 300px) { .card { color: red } } + @container panel (width > 600px) { .card { font-weight: bold } } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![ + { + let mut n = node("panel"); + n.classes = vec!["panel".into()]; + n.width = Some(400.0); + n + }, + { + let mut n = node("card"); + n.classes = vec!["card".into()]; + n + }, + ], + vec![NO_PARENT, 0], + ); + let env = Environment::default(); + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &env).unwrap(); + assert_eq!(get(&s, "color"), "#00f"); + assert!(s.get("font-weight").is_none()); + + // Small container + let t2 = tree( + vec![ + { + let mut n = node("panel"); + n.classes = vec!["panel".into()]; + n.width = Some(200.0); + n + }, + { + let mut n = node("card"); + n.classes = vec!["card".into()]; + n + }, + ], + vec![NO_PARENT, 0], + ); + let s = compute(std::slice::from_ref(&&sheet), &t2, 1, &env).unwrap(); + assert_eq!(get(&s, "color"), "red"); +} + +#[test] +fn dark_scheme_and_state_via_nesting() { + let css = r" + .btn { + color: black; + &:hover { color: white } + @media (prefers-color-scheme: dark) { + & { color: light-dark(white, black) } + } + } + "; + let sheet = stylesheet(css); + let sheet = sheet.sheet(); + let t = tree( + vec![{ + let mut n = node("btn"); + n.classes = vec!["btn".into()]; + n.hover = true; + n + }], + vec![NO_PARENT], + ); + let env = Environment { + color_scheme: bombshell_css_core::ColorScheme::Dark, + ..Default::default() + }; + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &env).unwrap(); + // Both rules match, but `:hover` carries higher specificity (0,2,0 vs + // 0,1,0), so the hover rule's plain `white` wins regardless of what the + // dark rule's `light-dark()` would resolve to. + assert_eq!(get(&s, "color"), "#fff"); +} + +#[test] +fn light_dark_resolves_against_the_color_scheme() { + let case = stylesheet(".card { color: light-dark(white, black) }"); + let sheet = case.sheet(); + let mut n = node("card"); + n.classes = vec!["card".into()]; + let t = tree(vec![n], vec![NO_PARENT]); + + let light = Environment::default(); + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &light).unwrap(); + assert_eq!(get(&s, "color"), "#fff"); + + let dark = Environment { + color_scheme: bombshell_css_core::ColorScheme::Dark, + ..Default::default() + }; + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &dark).unwrap(); + assert_eq!(get(&s, "color"), "#000"); +} + +#[test] +fn light_dark_resolves_through_var_substitution() { + // A custom property carries `light-dark()` verbatim (custom property + // values are not canonicalized); the using declaration resolves it at + // computed-value time, picking the dark branch as authored. + let case = stylesheet(":root { --panel: light-dark(white, black) } .card { color: var(--panel) }"); + let sheet = case.sheet(); + let t = tree( + vec![node("root"), { + let mut n = node("card"); + n.classes = vec!["card".into()]; + n + }], + vec![NO_PARENT, 0], + ); + let dark = Environment { + color_scheme: bombshell_css_core::ColorScheme::Dark, + ..Default::default() + }; + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &dark).unwrap(); + assert_eq!(get(&s, "color"), "black"); +} + +#[test] +fn light_dark_inherits_as_a_computed_value() { + // Descendants inherit the resolved branch, not the raw function text. + let case = stylesheet(".card { color: light-dark(#123456, #654321) }"); + let sheet = case.sheet(); + let t = tree( + vec![{ + let mut n = node("card"); + n.classes = vec!["card".into()]; + n + }, node("title")], + vec![NO_PARENT, 0], + ); + let dark = Environment { + color_scheme: bombshell_css_core::ColorScheme::Dark, + ..Default::default() + }; + let s = compute(std::slice::from_ref(&&sheet), &t, 1, &dark).unwrap(); + assert_eq!(get(&s, "color"), "#654321"); +} + +#[test] +fn malformed_light_dark_drops_the_declaration() { + // Inline styles pass through un-canonicalized, so a malformed call only + // surfaces at computed-value time; it drops the declaration like a + // failed var() resolution. + let case = stylesheet(".card { color: blue }"); + let sheet = case.sheet(); + let mut n = node("card"); + n.classes = vec!["card".into()]; + n.style = Some("color: light-dark(#fff)".into()); + let t = tree(vec![n], vec![NO_PARENT]); + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &Environment::default()).unwrap(); + assert_eq!(s.get("color"), None, "malformed light-dark must drop"); +} + +#[test] +fn light_dark_stays_verbatim_outside_color_properties() { + // Resolution is scoped to the color properties the compiler + // canonicalizes; other properties keep the value as authored. + let case = stylesheet(".card { border: light-dark(#fff, #000) }"); + let sheet = case.sheet(); + let mut n = node("card"); + n.classes = vec!["card".into()]; + let t = tree(vec![n], vec![NO_PARENT]); + let s = compute(std::slice::from_ref(&&sheet), &t, 0, &Environment::default()).unwrap(); + assert_eq!(get(&s, "border"), "light-dark(#fff, #000)"); +} diff --git a/experiments/css/crates/css-wasm/Cargo.toml b/experiments/css/crates/css-wasm/Cargo.toml new file mode 100644 index 0000000..5b9766a --- /dev/null +++ b/experiments/css/crates/css-wasm/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "bombshell-css-wasm" +version = "0.1.0" +description = "WIT component adapter for the Bombshell CSS engine" +edition.workspace = true +license.workspace = true +repository.workspace = true +rust-version.workspace = true + +[lib] +crate-type = ["cdylib"] + +[dependencies] +bombshell-css-core = { workspace = true } +bombshell-css-compiler = { workspace = true } +bombshell-css-runtime = { workspace = true } +wit-bindgen = { workspace = true } diff --git a/experiments/css/crates/css-wasm/src/lib.rs b/experiments/css/crates/css-wasm/src/lib.rs new file mode 100644 index 0000000..23035df --- /dev/null +++ b/experiments/css/crates/css-wasm/src/lib.rs @@ -0,0 +1,235 @@ +//! WIT component adapter: the only public ABI of the CSS pipeline. +//! +//! Hosts receive compiled IR as opaque bytes and evaluate computed styles +//! against a flat tree snapshot, keeping the linear-memory contract free of +//! Rust or JavaScript object layouts. + +/// The component glue only makes sense for the wasm component target; the +/// crate is a `cdylib`, and an empty dylib on native hosts keeps +/// `cargo build --workspace` runnable everywhere. +#[cfg(target_arch = "wasm32")] +mod guest { + wit_bindgen::generate!({ + path: "../../wit/css.wit", + }); + + use std::cell::RefCell; + + use bombshell::css::types::{ + ColorScheme as WitColorScheme, Diagnostic as WitDiagnostic, Environment as WitEnvironment, + Node as WitNode, NodeState, Origin as WitOrigin, Severity as WitSeverity, + }; + use bombshell_css_compiler::{CompileOptions, compile}; + use bombshell_css_core::{ + ColorScheme, CompiledStylesheet, Diagnostic, Environment, NodeSnapshot, Origin, Severity, + TreeSnapshot, decode_ir, encode_ir, + }; + use bombshell_css_runtime::Stylesheet; + use exports::bombshell::css::stylesheet::CompiledSheet; + use exports::bombshell::css::stylesheet::Guest; + + struct Css; + + impl Guest for Css { + fn compile(css: String, origin: WitOrigin) -> CompiledSheet { + let origin = to_origin(origin); + let output = compile(&css, origin, CompileOptions::default()); + let ir = output.sheet.as_ref().map(encode_ir); + CompiledSheet { + ir, + diagnostics: to_diagnostics(output.diagnostics), + } + } + + fn prepare(ir: Vec) -> Option { + // Ownership of `ir` transfers to the module (zero-copy lift); + // decode, then leak the decoded IR so the parsed stylesheet can + // borrow from it for the lifetime of the handle. + let Ok(decoded) = decode_ir(&ir) else { + return None; + }; + let sheet_ir: &'static CompiledStylesheet = Box::leak(Box::new(decoded)); + let sheet = Stylesheet::from_ir(sheet_ir, 0); + + SHEETS.with(|cell| { + let mut slots = cell.borrow_mut(); + let index = match slots.iter().position(|slot| slot.is_none()) { + Some(index) => index, + None => { + slots.push(None); + slots.len() - 1 + } + }; + slots[index] = Some(SheetSlot { + ir: sheet_ir, + sheet, + }); + Some(index as u32) + }) + } + + fn compute( + sheets: Vec, + nodes: Vec, + parents: Vec, + target: u32, + env: WitEnvironment, + ) -> Vec<(String, String)> { + let Ok(tree) = to_tree(nodes, parents) else { + return Vec::new(); + }; + let Ok(target) = usize::try_from(target) else { + return Vec::new(); + }; + let environment = to_environment(env); + + SHEETS.with(|cell| -> Vec<(String, String)> { + let slots = cell.borrow(); + let loaded: Vec<&bombshell_css_runtime::Stylesheet> = sheets + .iter() + .filter_map(|&sheet| { + slots + .get(sheet as usize) + .and_then(|slot| slot.as_ref()) + .map(|entry| &entry.sheet) + }) + .collect(); + let style = bombshell_css_runtime::compute(&loaded, &tree, target, &environment); + // Names borrow the IR and values borrow until a var() + // substitution; the canonical-ABI lowering needs owned text. + style + .map(|style| { + style + .declarations + .into_iter() + .map(|(name, value)| (String::from(name), value.into_owned())) + .collect() + }) + .unwrap_or_default() + }) + } + + fn compute_tree( + sheets: Vec, + nodes: Vec, + parents: Vec, + env: WitEnvironment, + ) -> Vec> { + let Ok(tree) = to_tree(nodes, parents) else { + return Vec::new(); + }; + let environment = to_environment(env); + + SHEETS.with(|cell| -> Vec> { + let slots = cell.borrow(); + let loaded: Vec<&bombshell_css_runtime::Stylesheet> = sheets + .iter() + .filter_map(|&sheet| { + slots + .get(sheet as usize) + .and_then(|slot| slot.as_ref()) + .map(|entry| &entry.sheet) + }) + .collect(); + bombshell_css_runtime::cascade::compute_tree(&loaded, &tree, &environment, &[]) + .into_iter() + .map(|style| { + style + .map(|style| { + style + .declarations + .into_iter() + .map(|(name, value)| (String::from(name), value.into_owned())) + .collect() + }) + .unwrap_or_default() + }) + .collect() + }) + } + + fn release(sheet: u32) { + SHEETS.with(|cell| { + let mut slots = cell.borrow_mut(); + if let Some(entry) = slots.get_mut(sheet as usize).and_then(|slot| slot.take()) { + // The parsed stylesheet borrows from the leaked IR; drop + // it before freeing the IR so the borrow is gone first. + let SheetSlot { ir, sheet } = entry; + drop(sheet); + // SAFETY: `ir` came from `Box::leak` in `prepare`, and + // the borrowing stylesheet was dropped above. + drop(unsafe { Box::from_raw(ir as *const CompiledStylesheet as *mut CompiledStylesheet) }); + } + }); + } + } + + struct SheetSlot { + /// The leaked decoded IR, kept so `release` can free it. + ir: &'static CompiledStylesheet, + sheet: Stylesheet<'static>, + } + + thread_local! { + static SHEETS: RefCell>> = const { RefCell::new(Vec::new()) }; + } + + fn to_origin(origin: WitOrigin) -> Origin { + match origin { + WitOrigin::UserAgent => Origin::UserAgent, + WitOrigin::User => Origin::User, + WitOrigin::Author => Origin::Author, + } + } + + fn to_diagnostics(diagnostics: Vec) -> Vec { + diagnostics + .into_iter() + .map(|d| WitDiagnostic { + severity: match d.severity { + Severity::Error => WitSeverity::Error, + Severity::Warning => WitSeverity::Warning, + }, + code: d.code, + message: d.message, + }) + .collect() + } + + fn to_tree(nodes: Vec, parents: Vec) -> Result { + if nodes.len() != parents.len() { + return Err(()); + } + let nodes = nodes + .into_iter() + .map(|n| NodeSnapshot { + tag: n.tag, + id: n.id, + classes: n.classes, + attributes: n.attributes, + focus: n.state.contains(NodeState::FOCUS), + hover: n.state.contains(NodeState::HOVER), + active: n.state.contains(NodeState::ACTIVE), + width: n.width, + height: n.height, + style: n.style, + }) + .collect(); + Ok(TreeSnapshot { nodes, parents }) + } + + fn to_environment(env: WitEnvironment) -> Environment { + Environment { + viewport_width: env.viewport_width, + viewport_height: env.viewport_height, + color_scheme: match env.color_scheme { + WitColorScheme::Light => ColorScheme::Light, + WitColorScheme::Dark => ColorScheme::Dark, + }, + reduced_motion: env.reduced_motion, + resolution: env.resolution, + } + } + + export!(Css); +} diff --git a/experiments/css/package.json b/experiments/css/package.json new file mode 100644 index 0000000..e5aea7d --- /dev/null +++ b/experiments/css/package.json @@ -0,0 +1,41 @@ +{ + "name": "@bomb.sh/css", + "version": "0.0.0", + "description": "The Bombshell CSS engine: compiler front-end and cascade runtime as a freestanding wasm component, with canonical-ABI bindings and the embedded artifact", + "license": "MIT", + "author": { + "name": "Bombshell", + "email": "oss@bomb.sh", + "url": "https://bomb.sh" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/bombshell-dev/playground.git", + "directory": "experiments/css" + }, + "files": [ + "src" + ], + "type": "module", + "exports": { + ".": "./src/index.js", + "./package.json": "./package.json" + }, + "scripts": { + "test": "node smoke.mjs", + "test:using": "node smoke.using.mjs", + "bundle": "node scripts/bundle-wasm.mjs" + }, + "devEngines": { + "packageManager": { + "name": "pnpm", + "version": "10.7.0", + "onFail": "error" + }, + "runtime": { + "name": "node", + "version": "22.14.0", + "onFail": "error" + } + } +} diff --git a/experiments/css/scripts/bundle-wasm.mjs b/experiments/css/scripts/bundle-wasm.mjs new file mode 100644 index 0000000..8a70ca9 --- /dev/null +++ b/experiments/css/scripts/bundle-wasm.mjs @@ -0,0 +1,78 @@ +// Encode a built wasm module into `src/wasm.js`: brotli at maximum quality, +// Z85-encoded into a self-contained module that embeds its own decoder and +// exports `compiled`, a ready `WebAssembly.Module`. Same bundle-friendly +// scheme the tty repo uses for its embedded artifacts. +// +// The optimized freestanding artifact needs nightly (`-Z build-std`, +// immediate-abort panics) plus Binaryen; see the css-compiler workspace +// README in the css repository history for the full recipe: +// +// cargo +nightly build -Z build-std=std,panic_abort \ +// -p bombshell-css-wasm --target wasm32-unknown-unknown --release +// wasm-opt -Oz --enable-bulk-memory --enable-reference-types \ +// --enable-nontrapping-float-to-int --enable-sign-ext \ +// --enable-mutable-globals --enable-multivalue --enable-tail-call \ +// -o bombshell_css.wasm target/wasm32-unknown-unknown/release/bombshell_css_wasm.wasm +// +// Usage: node scripts/bundle-wasm.mjs + +import { brotliCompressSync, constants } from 'node:zlib'; +import { readFileSync, writeFileSync } from 'node:fs'; + +const Z85 = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#'; + +function encodeZ85(data) { + const padLen = (4 - (data.length % 4)) % 4; + let src = data; + if (padLen > 0) { + src = new Uint8Array(data.length + padLen); + src.set(data); + } + const out = []; + for (let i = 0; i < src.length; i += 4) { + const v = src[i] * 16777216 + src[i + 1] * 65536 + src[i + 2] * 256 + src[i + 3]; + out.push( + Z85[Math.floor(v / 52200625)], + Z85[Math.floor(v / 614125) % 85], + Z85[Math.floor(v / 7225) % 85], + Z85[Math.floor(v / 85) % 85], + Z85[v % 85], + ); + } + return out.join(''); +} + +const wasm = readFileSync(process.argv[2]); + +const compressed = new Uint8Array( + brotliCompressSync(wasm, { + params: { + [constants.BROTLI_PARAM_QUALITY]: 11, + [constants.BROTLI_PARAM_SIZE_HINT]: wasm.length, + [constants.BROTLI_PARAM_LGWIN]: 24, + }, + }), +); + +const z85 = encodeZ85(compressed); + +// The decoder receives the pre-padding module length, so the zero bytes the +// Z85 alignment pad contributes never reach WebAssembly.compile. +// Decoding uses division instead of >>> to avoid 32-bit truncation on +// values near 0xFFFFFFFF. +const source = `import{brotliDecompressSync}from"node:zlib"; +const Z="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#"; +const T=new Uint8Array(128);for(let i=0;i<85;i++)T[Z.charCodeAt(i)]=i; +// the table lookups are non-null for well-formed z85 input; the bounds +// checks below handle a short tail, so the assertions carry no risk +function d(s,n){const b=new Uint8Array(n);let o=0;for(let i=0;i .title { font-weight: bold } } + @media (min-width: 24em) { + @container panel (inline-size > 20em) { + .card { border-color: var(--brand) } + } + } +`; + +// compile both compiles and prepares: the Sheet carries diagnostics, the IR +// bytes, and the decoded rules. +const sheet = compile(css, 2); +console.log('diagnostics:', sheet.diagnostics.length ? sheet.diagnostics : 'none'); +console.log('ir bytes:', sheet.ir.byteLength); + +const parsed = decodeIr(sheet); +console.log('ir version:', parsed.version); +for (const rule of parsed.rules) { + console.log(` ${rule.selector} spec=0x${rule.specificity.toString(16)} ->`, rule.declarations); +} + +const tree = [ + { tag: 'root', classes: ['root', 'panel'], width: 400, height: 100, state: 0 }, // container + { tag: 'card', classes: ['card'] }, + { tag: 'title', classes: ['title'] }, +]; +const parents = [NO_PARENT, 0, 1]; + +// Node 0 as a named container via container-type comes from computed styles; +// this fixture relies on the width. Compute each node with a dark viewport. +const env = { + viewportWidth: 400, + viewportHeight: 300, + colorScheme: 'dark', + reducedMotion: false, + resolution: 1, +}; +for (const target of [0, 1, 2]) { + const computed = sheet.compute(tree, { parents, target, env }); + console.log(`node ${target}:`, JSON.stringify(computed)); +} + +// Frame loop: `compute` runs per animation frame in real hosts, so its +// memory must not grow over time. The component caches the parsed sheet for +// identical IR bytes; a growing trace means the cache is leaking. +function memoryPages() { + return component.raw.memory.buffer.byteLength; +} +// The tree API must agree with the per-node API — via both the Sheet methods +// and the module-level functions. +const perNode = []; +for (const target of tree.keys()) { + perNode.push(sheet.compute(tree, { parents, target, env })); +} +const wholeViaSheet = sheet.computeTree(tree, { parents, env }); +const whole = computeTree(sheet, { nodes: tree, parents, env }); +assert.deepEqual(perNode, wholeViaSheet, 'Sheet.computeTree disagrees with Sheet.compute'); +assert.deepEqual(perNode, whole, 'module-level computeTree disagrees with compute'); + +// Re-compile + release exercises the slot lifecycle before the loop. +const otherSheet = compile('.x { color: blue }', 2); +otherSheet.compute(tree, { parents, target: 2, env }); +otherSheet.release(); +for (let i = 0; i < 500; i++) { + sheet.compute(tree, { parents, target: 2, env }); +} +assert.strictEqual(memoryPages(), memoryPages(), 'unstable'); +const pagesAfterFrames = memoryPages(); +for (let i = 0; i < 500; i++) { + for (const target of tree.keys()) { + sheet.compute(tree, { parents, target, env }); + } + sheet.computeTree(tree, { parents, env }); +} +const growth = memoryPages() - pagesAfterFrames; +console.log(`frame loop: 5500 computes, memory grew ${growth} bytes`); +assert.ok(growth <= 0, `per-frame leak: ${growth} bytes over 500 frames`); + +// Option-returning calls after compute-tree: the shared return area holds a +// pointer from compute-tree's lowering, so the option discriminant's padding +// bytes are no longer zero. Reading the disc as anything wider than one byte +// misreads these results as absent. +const hotSheet = compile('.card { color: #fff }', 2); +hotSheet.compute(tree, { parents, target: 1, env }); +hotSheet.release(); + +// The rest of the poison matrix: re-compiling the ORIGINAL css… +const reSheet = compile(css, 2); +// …and computing on a sheet adopted after compute-tree. +const adoptedSheet = compile('.card { color: #0f0 }', 2); +const afterPoison = adoptedSheet.computeTree(tree, { parents, env }); +assert.ok( + afterPoison.length === tree.length && afterPoison[1].length > 0, + `compute-tree on a late-prepared sheet returned no styles: ${JSON.stringify(afterPoison)}`, +); +reSheet.release(); +adoptedSheet.release(); + +// Diagnostics surface through the API: an invalid color warns and the rest +// of the rule recovers — the compile still succeeds. +const warned = compile('.card { color: notacolor; padding: 4px }', 2); +assert.ok( + warned.diagnostics.some( + (d) => d.severity === 1 && d.code === 'declaration' && d.message.includes('notacolor'), + ), + `expected a warning diagnostic, got ${JSON.stringify(warned.diagnostics)}`, +); +warned.release(); + +// light-dark() survives compilation (branches canonicalized) and resolves +// against the environment's color scheme at computed-value time. +const schemeSheet = compile('.card { color: light-dark(white, black) }', 2); +const schemeTree = [{ tag: 'card', classes: ['card'] }]; +const schemeParents = [NO_PARENT]; +assertColor( + colorOf( + schemeSheet.compute(schemeTree, { + parents: schemeParents, + target: 0, + env: { ...env, colorScheme: 'light' }, + }), + ), + { + expected: '#fff', + label: 'light-dark under a light scheme', + }, +); +assertColor( + colorOf( + schemeSheet.compute(schemeTree, { + parents: schemeParents, + target: 0, + env: { ...env, colorScheme: 'dark' }, + }), + ), + { + expected: '#000', + label: 'light-dark under a dark scheme', + }, +); +// A malformed call is invalid at computed-value time: the declaration drops. +const malformedScheme = compile('.card { color: blue }', 2); +const malformedNode = { tag: 'card', classes: ['card'], style: 'color: light-dark(#fff)' }; +assert.strictEqual( + colorOf(malformedScheme.compute([malformedNode], { parents: schemeParents, target: 0, env })), + null, + 'malformed light-dark must drop the declaration', +); +schemeSheet.release(); +malformedScheme.release(); + +// Disposable protocol: release is synchronous, so `using` works via +// Symbol.dispose and `await using` via Symbol.asyncDispose. (The `using` +// syntax itself is exercised in smoke.using.mjs on Node 24+/bun.) +{ + const scoped = compile('.card { color: red }', 2); + assert.ok( + scoped.compute(tree, { parents, target: 1, env }).length > 0, + 'scoped sheet returned no styles', + ); + scoped[Symbol.dispose](); + assert.strictEqual(scoped.handle, null, 'Symbol.dispose did not drop the handle'); + scoped.release(); // double release is a safe no-op + await scoped[Symbol.asyncDispose](); +} + +sheet.release(); + +// --------------------------------------------------------------------------- +// Engine: multi-sheet aggregation, lazy recompile, removal, @layer, inline. +// --------------------------------------------------------------------------- + +function colorOf(declarations) { + const hit = declarations.find(([name]) => name === 'color'); + return hit ? hit[1] : null; +} +function assertColor(actual, { expected, label }) { + assert.strictEqual(actual, expected, `${label}: expected color ${expected}, got ${actual}`); +} + +const cardOnly = [{ tag: 'card', classes: ['card'] }]; +const cardRoot = [NO_PARENT]; + +// Later sheets win at equal specificity (document order). Colors come back +// canonicalized (named → shortest hex), so assert canonical values. +const engine = createEngine(); +engine.addSheet('.card { color: #0f0 }'); +engine.addSheet('.card { color: #f00 }'); +assertColor(colorOf(engine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#f00', + label: 'sheet order', +}); + +// Each sheet compiles once; removal reverts to the prior cascade. +const whiteId = engine.addSheet('.card { color: #123456 }'); +assertColor(colorOf(engine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#123456', + label: 'added sheet', +}); +assert.strictEqual(engine.removeSheet(whiteId), true, 'removeSheet failed'); +assertColor(colorOf(engine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#f00', + label: 'after removeSheet', +}); + +// @layer across sheets: layers rank by first appearance (later wins), and +// re-referencing an earlier layer must NOT reorder it to the end — that's +// the discriminator the concatenation scheme has to preserve. +const layerEngine = createEngine(); +layerEngine.addSheet('@layer b { .card { color: #0f0 } }'); +layerEngine.addSheet('@layer a { .card { color: #ff0 } }'); +const plainId = layerEngine.addSheet('.card { color: #234567 }'); +assertColor(colorOf(layerEngine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#234567', + label: 'unlayered wins', +}); +layerEngine.removeSheet(plainId); +assertColor(colorOf(layerEngine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#ff0', + label: 'later layer wins', +}); +layerEngine.addSheet('@layer b { .card { color: #00f } }'); +assertColor(colorOf(layerEngine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#ff0', + label: '@layer first-appearance survives re-reference', +}); + +// Inline styles: inline-normal beats sheet-normal, sheet-!important beats +// inline-normal, inline-!important beats everything. Inline values pass +// through un-canonicalized. +const inlineEngine = createEngine(); +inlineEngine.addSheet('.card { color: #fff; background: black }'); +inlineEngine.addSheet('.card { color: #f00 !important }'); +const inlineNode = [{ tag: 'card', classes: ['card'], style: 'color: blue; border: none' }]; +const inlineImp = [{ tag: 'card', classes: ['card'], style: 'color: blue !important' }]; +assertColor(colorOf(inlineEngine.compute(inlineNode, { parents: cardRoot, target: 0, env })), { + expected: '#f00', + label: 'sheet !important beats inline', +}); +assertColor(colorOf(inlineEngine.compute(inlineImp, { parents: cardRoot, target: 0, env })), { + expected: 'blue', + label: 'inline !important wins', +}); +const noShield = createEngine(); +noShield.addSheet('.card { color: #fff }'); +assertColor(colorOf(noShield.compute(inlineNode, { parents: cardRoot, target: 0, env })), { + expected: 'blue', + label: 'inline beats sheet-normal', +}); +assert.ok( + !noShield + .compute(inlineNode, { parents: cardRoot, target: 0, env }) + .some(([n, v]) => n === 'border' && v !== 'none'), + 'inline border not applied', +); +// An !important in a rule that does NOT match the node must not shield: +// the inline style still wins (impossible under the old JS-side merge). +const wrongShield = createEngine(); +wrongShield.addSheet('.other { color: #f00 !important }'); +wrongShield.addSheet('.card { color: #fff }'); +assertColor(colorOf(wrongShield.compute(inlineNode, { parents: cardRoot, target: 0, env })), { + expected: 'blue', + label: 'non-matching !important does not shield', +}); +// Inline declarations seed inheritance: the child inherits the parent's +// inline-overridden custom property. +const inheritEngine = createEngine(); +inheritEngine.addSheet('.child { color: var(--brand) }'); +const inheritTree = [ + { tag: 'root', style: '--brand: red' }, + { tag: 'child', classes: ['child'] }, +]; +assertColor(colorOf(inheritEngine.computeTree(inheritTree, { parents: [NO_PARENT, 0], env })[1]), { + expected: 'red', + label: 'inline custom property inherits', +}); +noShield.release(); +wrongShield.release(); +inheritEngine.release(); + +// Engine dispose releases the sheet; a later compute lazily re-prepares. +inlineEngine[Symbol.dispose](); +assertColor(colorOf(inlineEngine.compute(cardOnly, { parents: cardRoot, target: 0, env })), { + expected: '#f00', + label: 'engine resurrects after dispose', +}); +inlineEngine.release(); +layerEngine.release(); +engine.release(); +console.log('engine ok'); + +console.log('smoke ok'); diff --git a/experiments/css/smoke.using.mjs b/experiments/css/smoke.using.mjs new file mode 100644 index 0000000..10ce521 --- /dev/null +++ b/experiments/css/smoke.using.mjs @@ -0,0 +1,46 @@ +// Smoke test for the explicit-resource-management path: `using` / +// `await using` auto-release sheets at scope exit. Requires Node 24+ or bun +// (Node 22 needs the flag and does not parse `using`). +// Usage: node smoke.using.mjs + +import assert from 'node:assert/strict'; +import { component, compile, decodeIr } from './src/index.js'; + +const tree = [ + { tag: 'root', classes: ['root'], width: 400, height: 100, state: 0 }, + { tag: 'card', classes: ['card'] }, +]; +const parents = [0xffffffff, 0]; +const env = { + viewportWidth: 400, + viewportHeight: 300, + colorScheme: 'dark', + reducedMotion: false, + resolution: 1, +}; + +// Sync `using`: compile prepares and returns the Sheet; released at block exit. +{ + using sheet = compile('.card { color: red }'); + assert(sheet.diagnostics.length === 0); + assert(sheet.compute(tree, { parents, target: 1, env }).some(([name]) => name === 'color')); + assert(sheet.rules.length > 0); + assert(decodeIr(sheet).version === 2); +} +const pagesAfterSync = component.raw.memory.buffer.byteLength; + +// `await using` also works — release is synchronous but the protocol accepts it. +{ + await using sheet = compile('.card { color: blue }'); + assert(sheet.compute(tree, { parents, target: 1, env }).some(([name]) => name === 'color')); +} + +// Neither sheet leaked: a third round still works and memory has not grown +// beyond the sheets we hold open. +{ + using sheet = compile('.card { color: green }'); + assert(sheet.compute(tree, { parents, target: 1, env }).some(([name]) => name === 'color')); +} +assert(component.raw.memory.buffer.byteLength <= pagesAfterSync + 65536 * 4); + +console.log('using-smoke ok'); diff --git a/experiments/css/src/abi.js b/experiments/css/src/abi.js new file mode 100644 index 0000000..5dc68d0 --- /dev/null +++ b/experiments/css/src/abi.js @@ -0,0 +1,514 @@ +// Canonical ABI bindings for the bombshell:css component (wasm32). +// +// All in-memory layouts follow the component-model canonical ABI. Strings +// and lists are (ptr, len) pairs pointing at wasm memory; string bytes are +// copied into linear memory via `cabi_realloc`. + +const encoder = new TextEncoder(); +const decoder = new TextDecoder(); + +export const NO_PARENT = 0xffffffff; + +export async function loadCssComponent(source) { + const bytes = source instanceof Uint8Array ? source : new Uint8Array(await source.arrayBuffer()); + const instance = (await WebAssembly.instantiate(bytes, {})).instance; + return createComponent(instance); +} + +export function loadCssComponentFromModule(module) { + return createComponent(new WebAssembly.Instance(module, {})); +} + +function createComponent(instance) { + const exports = instance.exports; + let memory = new Uint8Array(exports.memory.buffer); + let view = new DataView(exports.memory.buffer); + const realloc = exports.cabi_realloc; + const compileFn = exports['bombshell:css/stylesheet@0.4.0#compile']; + const computeFn = exports['bombshell:css/stylesheet@0.4.0#compute']; + const prepareFn = exports['bombshell:css/stylesheet@0.4.0#prepare']; + const releaseFn = exports['bombshell:css/stylesheet@0.4.0#release']; + const computeTreeFn = exports['bombshell:css/stylesheet@0.4.0#compute-tree']; + const postComputeTree = exports['cabi_post_bombshell:css/stylesheet@0.4.0#compute-tree']; + const postCompile = exports['cabi_post_bombshell:css/stylesheet@0.4.0#compile']; + const postCompute = exports['cabi_post_bombshell:css/stylesheet@0.4.0#compute']; + function refresh() { + memory = new Uint8Array(exports.memory.buffer); + view = new DataView(exports.memory.buffer); + } + + // Host allocations use `cabi_realloc`: wit-bindgen lifts string/list + // arguments zero-copy (it takes ownership of the buffer and frees it with + // its own allocator), so inputs must come from the allocator the callee + // will free with, and must NOT be freed host-side. Callee-owned return + // areas are released by the `cabi_post_*` hooks after the host reads. + function allocate(bytes) { + const pointer = realloc(0, 0, 1, bytes.byteLength); + refresh(); + memory.set(bytes, pointer); + return pointer; + } + + function readString(pointer, length) { + return decoder.decode(memory.subarray(pointer, pointer + length)); + } + + function u32(pointer) { + return view.getUint32(pointer, true); + } + + function stringPointer(text) { + const bytes = encoder.encode(text); + return { pointer: allocate(bytes), length: bytes.byteLength }; + } + + function stringListPointer(items) { + if (items.length === 0) { + return { pointer: 0, count: 0 }; + } + const entries = items.map(stringPointer); + const pointer = realloc(0, 0, 4, entries.length * 8); + refresh(); + entries.forEach((entry, i) => { + view.setUint32(pointer + i * 8, entry.pointer, true); + view.setUint32(pointer + i * 8 + 4, entry.length, true); + }); + return { pointer, count: entries.length }; + } + + function attributeListPointer(attributes) { + if (attributes.length === 0) { + return { pointer: 0, count: 0 }; + } + const entries = attributes.map((attribute) => ({ + name: stringPointer(attribute.name), + value: stringPointer(attribute.value), + })); + const pointer = realloc(0, 0, 4, entries.length * 16); + refresh(); + entries.forEach((entry, i) => { + const base = pointer + i * 16; + view.setUint32(base, entry.name.pointer, true); + view.setUint32(base + 4, entry.name.length, true); + view.setUint32(base + 8, entry.value.pointer, true); + view.setUint32(base + 12, entry.value.length, true); + }); + return { pointer, count: entries.length }; + } + + function u32ListPointer(values) { + if (values.length === 0) { + return { pointer: 0, count: 0 }; + } + const pointer = realloc(0, 0, 4, values.length * 4); + refresh(); + values.forEach((value, i) => { + view.setUint32(pointer + i * 4, value, true); + }); + return { pointer, count: values.length }; + } + + /// Serialize the flat node list for `compute`/`compute-tree`: + /// tag (ptr@0, len@4), id option (disc@8, ptr@12, len@16), + /// classes list (ptr@20, len@24), attributes list + /// (ptr@28, len@32), state u8@36, width option (disc@40, f32@44), + /// height option (disc@48, f32@52), style option + /// (disc@56, ptr@60, len@64) — 68 bytes per node. + function serializeNodes(nodes) { + const stride = 68; + const data = new Uint8Array(nodes.length * stride); + const dataView = new DataView(data.buffer); + nodes.forEach((node, i) => { + const base = i * stride; + const tag = stringPointer(node.tag); + dataView.setUint32(base, tag.pointer, true); + dataView.setUint32(base + 4, tag.length, true); + const id = node.id ? stringPointer(node.id) : null; + dataView.setUint32(base + 8, id ? 1 : 0, true); + if (id) { + dataView.setUint32(base + 12, id.pointer, true); + dataView.setUint32(base + 16, id.length, true); + } + const classes = stringListPointer(node.classes ?? []); + dataView.setUint32(base + 20, classes.pointer, true); + dataView.setUint32(base + 24, classes.count, true); + const attributes = attributeListPointer(node.attributes ?? []); + dataView.setUint32(base + 28, attributes.pointer, true); + dataView.setUint32(base + 32, attributes.count, true); + dataView.setUint8(base + 36, node.state ?? 0); + const hasWidth = node.width !== undefined && node.width !== null; + const hasHeight = node.height !== undefined && node.height !== null; + dataView.setUint32(base + 40, hasWidth ? 1 : 0, true); + dataView.setFloat32(base + 44, hasWidth ? node.width : 0, true); + dataView.setUint32(base + 48, hasHeight ? 1 : 0, true); + dataView.setFloat32(base + 52, hasHeight ? node.height : 0, true); + const style = node.style ? stringPointer(node.style) : null; + dataView.setUint8(base + 56, style ? 1 : 0); + if (style) { + dataView.setUint32(base + 60, style.pointer, true); + dataView.setUint32(base + 64, style.length, true); + } + }); + return allocate(data); + } + + function compile(css, origin = 2) { + const bytes = encoder.encode(css); + const cssPointer = allocate(bytes); + const result = compileFn(cssPointer, bytes.byteLength, origin); + refresh(); + // compiled-sheet: option> (disc u8@0, ptr@4, len@8) + // + list (ptr@12, len@16) + // The option discriminant is one byte; bytes 1..3 are padding the + // canonical ABI leaves undefined, so they must not leak into the check. + const hasIr = view.getUint8(result) === 1; + const irPointer = u32(result + 4); + const irLength = u32(result + 8); + const diagnosticsPointer = u32(result + 12); + const diagnosticsCount = u32(result + 16); + const ir = hasIr ? memory.slice(irPointer, irPointer + irLength) : null; + const diagnostics = []; + for (let i = 0; i < diagnosticsCount; i++) { + // diagnostic: severity u8@0, code (ptr@4, len@8), message (ptr@12, len@16) + const base = diagnosticsPointer + i * 16; + diagnostics.push({ + severity: view.getUint8(base), + code: readString(u32(base + 4), u32(base + 8)), + message: readString(u32(base + 12), u32(base + 16)), + }); + } + // The callee-allocated return area (and the strings it points to) is + // released by the post-return hook, after the host has finished reading. + postCompile(result); + return { ir, diagnostics }; + } + + /// Decode and parse IR once; returns a handle for `compute`. + function prepare(ir) { + const irBytes = ir instanceof Uint8Array ? ir : new Uint8Array(ir); + const irPointer = allocate(irBytes); + const result = prepareFn(irPointer, irBytes.byteLength); + refresh(); + // option: disc u8@0, value@4 — discriminant is one byte; the + // canonical ABI leaves bytes 1..3 undefined, so read only the byte. + return view.getUint8(result) === 1 ? u32(result + 4) : null; + } + + /// Resolve computed styles for every node in one pass. Returns one + /// declaration list per node, index-aligned with `nodes`. + function computeTree({ sheets, nodes, parents, env }) { + const handleList = u32ListPointer(sheets); + const nodesPointer = serializeNodes(nodes); + + const parentBytes = new Uint8Array(parents.length * 4); + const parentView = new DataView(parentBytes.buffer); + parents.forEach((parent, i) => parentView.setUint32(i * 4, parent, true)); + const parentPointer = allocate(parentBytes); + + const result = computeTreeFn( + handleList.pointer, + handleList.count, + nodesPointer, + nodes.length, + parentPointer, + parents.length, + env?.viewportWidth != null ? 1 : 0, + env?.viewportWidth ?? 0, + env?.viewportHeight != null ? 1 : 0, + env?.viewportHeight ?? 0, + env?.colorScheme === 'dark' ? 1 : 0, + env?.reducedMotion ? 1 : 0, + env?.resolution ?? 1, + ); + refresh(); + // list>: (ptr@0, len@4); each entry is + // (ptr@0, len@4) over 16-byte name/value pairs. + const outer = u32(result); + const outerCount = u32(result + 4); + const perNode = []; + for (let i = 0; i < outerCount; i++) { + const entryBase = outer + i * 8; + const pointer = u32(entryBase); + const count = u32(entryBase + 4); + const declarations = []; + for (let j = 0; j < count; j++) { + const base = pointer + j * 16; + declarations.push([ + readString(u32(base), u32(base + 4)), + readString(u32(base + 8), u32(base + 12)), + ]); + } + perNode.push(declarations); + } + postComputeTree(result); + return perNode; + } + + function release(sheet) { + releaseFn(sheet); + } + + function compute({ sheets, nodes, parents, target, env }) { + const handleList = u32ListPointer(sheets); + const nodesPointer = serializeNodes(nodes); + + const parentBytes = new Uint8Array(parents.length * 4); + const parentView = new DataView(parentBytes.buffer); + parents.forEach((parent, i) => parentView.setUint32(i * 4, parent, true)); + const parentPointer = allocate(parentBytes); + + const result = computeFn( + handleList.pointer, + handleList.count, + nodesPointer, + nodes.length, + parentPointer, + parents.length, + target, + env?.viewportWidth != null ? 1 : 0, + env?.viewportWidth ?? 0, + env?.viewportHeight != null ? 1 : 0, + env?.viewportHeight ?? 0, + env?.colorScheme === 'dark' ? 1 : 0, + env?.reducedMotion ? 1 : 0, + env?.resolution ?? 1, + ); + refresh(); + // list: (ptr@0, len@4) + const pointer = u32(result); + const count = u32(result + 4); + const declarations = []; + for (let i = 0; i < count; i++) { + // computed-property: name (ptr@0, len@4), value (ptr@8, len@12) + const base = pointer + i * 16; + declarations.push([ + readString(u32(base), u32(base + 4)), + readString(u32(base + 8), u32(base + 12)), + ]); + } + postCompute(result); + return declarations; + } + + return { compile, prepare, compute, computeTree, release, raw: exports }; +} + +// --------------------------------------------------------------------------- +// Postcard reader for CompiledStylesheet (IR_VERSION 2) +// --------------------------------------------------------------------------- + +export function decodeIr(bytes) { + const reader = new IrReader(bytes); + return { + version: reader.varint(), + origin: reader.byte(), + rules: reader.vec(() => reader.rule()), + layerOrder: reader.vec(() => reader.stringVec()), + keyframes: reader.vec(() => ({ name: reader.string(), body: reader.string() })), + opaque: reader.vec(() => ({ text: reader.string() })), + warnings: reader.vec(() => reader.diagnostic()), + }; +} + +/// Thrown when the IR decoder encounters a feature kind it doesn't know. +export class IrDecodeError extends Error { + constructor(message) { + super(message); + this.name = 'IrDecodeError'; + } +} + +class IrReader { + constructor(bytes) { + this.bytes = bytes; + this.cursor = 0; + this.view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + } + + byte() { + return this.bytes[this.cursor++]; + } + + varint() { + let value = 0; + let shift = 0; + for (;;) { + const byte = this.bytes[this.cursor++]; + value |= (byte & 0x7f) << shift; + if ((byte & 0x80) === 0) { + break; + } + shift += 7; + } + return value >>> 0; + } + + zigzag() { + const n = this.varint(); + return (n >>> 1) ^ -(n & 1); + } + + string() { + const length = this.varint(); + const text = decoder.decode(this.bytes.subarray(this.cursor, this.cursor + length)); + this.cursor += length; + return text; + } + + stringVec() { + return this.vec(() => this.string()); + } + + vec(read) { + const count = this.varint(); + const items = []; + for (let i = 0; i < count; i++) { + items.push(read()); + } + return items; + } + + diagnostic() { + return { severity: this.byte(), code: this.string(), message: this.string() }; + } + + rule() { + return { + selector: this.string(), + specificity: this.varint(), + layer: this.option(() => this.stringVec()), + media: this.vec(() => this.mediaCondition()), + containers: this.vec(() => ({ + name: this.option(() => this.string()), + condition: this.containerCondition(), + })), + supports: this.vec(() => this.supportsCondition()), + declarations: this.vec(() => ({ + name: this.string(), + value: this.string(), + important: this.byte() === 1, + })), + order: this.varint(), + }; + } + + option(read) { + if (this.byte() === 0) { + return null; + } + return read(); + } + + mediaCondition() { + const tag = this.varint(); + switch (tag) { + case 0: + return { type: 'feature', feature: this.feature() }; + case 1: + return { type: 'not', inner: this.mediaCondition() }; + case 2: + return { type: 'and', conditions: this.vec(() => this.mediaCondition()) }; + case 3: + return { type: 'or', conditions: this.vec(() => this.mediaCondition()) }; + default: + return { type: 'unknown' }; + } + } + + feature() { + const name = this.string(); + const kind = this.varint(); + switch (kind) { + case 0: + return { name, kind: { type: 'plain', value: this.featureValue() } }; + case 1: + return { name, kind: { type: 'boolean' } }; + case 2: + return { name, kind: { type: 'range', cmp: this.varint(), value: this.featureValue() } }; + case 3: + return { + name, + kind: { + type: 'interval', + start: this.featureValue(), + startCmp: this.varint(), + end: this.featureValue(), + endCmp: this.varint(), + }, + }; + default: + throw new IrDecodeError(`unknown feature kind ${kind}`); + } + } + + featureValue() { + const tag = this.varint(); + switch (tag) { + case 0: + return { type: 'px', value: this.f32() }; + case 1: + return { type: 'length', value: this.f32(), unit: this.string() }; + case 2: + return { type: 'number', value: this.f32() }; + case 3: + return { type: 'integer', value: this.zigzag() }; + case 4: + return { type: 'boolean', value: this.byte() === 1 }; + case 5: + return { type: 'dppx', value: this.f32() }; + case 6: + return { type: 'ratio', a: this.f32(), b: this.f32() }; + case 7: + return { type: 'ident', value: this.string() }; + default: + return { type: 'unknown' }; + } + } + + f32() { + const value = this.view.getFloat32(this.cursor, true); + this.cursor += 4; + return value; + } + + containerCondition() { + const tag = this.varint(); + switch (tag) { + case 0: + return { type: 'size', feature: this.feature() }; + case 1: + return { type: 'style', text: this.string() }; + case 2: + return { type: 'not', inner: this.containerCondition() }; + case 3: + return { type: 'and', conditions: this.vec(() => this.containerCondition()) }; + case 4: + return { type: 'or', conditions: this.vec(() => this.containerCondition()) }; + default: + return { type: 'unknown' }; + } + } + + supportsCondition() { + const tag = this.varint(); + switch (tag) { + case 0: + return { + type: 'declaration', + name: this.string(), + value: this.string(), + supported: this.byte() === 1, + }; + case 1: + return { type: 'selector', text: this.string(), supported: this.byte() === 1 }; + case 2: + return { type: 'not', inner: this.supportsCondition() }; + case 3: + return { type: 'and', conditions: this.vec(() => this.supportsCondition()) }; + case 4: + return { type: 'or', conditions: this.vec(() => this.supportsCondition()) }; + default: + return { type: 'unknown' }; + } + } +} diff --git a/experiments/css/src/engine.js b/experiments/css/src/engine.js new file mode 100644 index 0000000..1567b73 --- /dev/null +++ b/experiments/css/src/engine.js @@ -0,0 +1,107 @@ +// Engine: an aggregating front for the wasm component, mirroring how a +// browser hosts stylesheets. +// +// Since `bombshell:css@0.4.0`, `compute`/`compute-tree` take a list of +// prepared sheets and cascade across them natively: later sheets win at +// equal weight, and `@layer` order is first-appearance across all sheets in +// the order given — the same rules a browser applies to document stylesheets. +// Each sheet compiles exactly once; adding or removing a sheet never +// recompiles the others. +// +// Inline styles are native too: `node.style` text is parsed by the runtime +// cascade (author origin, above every stylesheet declaration of the same +// importance, below author-`!important`), and inline declarations seed +// inheritance — children inherit the inline-overridden computed values. + +import { compile, component } from './index.js'; + +export class Engine { + constructor(origin = 2) { + this.origin = origin; + this.#sheets = []; + } + + /// Compile and prepare a stylesheet, cascade-ordered after existing + /// sheets. Returns an id usable with removeSheet. Throws `CompileError` + /// (with `diagnostics`) when the sheet produces no IR. + addSheet(css) { + const sheet = compile(css, this.origin); + const id = this.#nextId++; + this.#sheets.push({ id, css, sheet }); + return id; + } + + /// Remove a previously added sheet by id. + removeSheet(id) { + const index = this.#sheets.findIndex((entry) => entry.id === id); + if (index === -1) return false; + this.#sheets[index].sheet.release(); + this.#sheets.splice(index, 1); + return true; + } + + /// Drop all sheets. + clear() { + for (const entry of this.#sheets) entry.sheet.release(); + this.#sheets = []; + } + + get sheetCount() { + return this.#sheets.length; + } + + /// Diagnostics from every sheet's compile, in cascade order. + get diagnostics() { + return this.#sheets.flatMap((entry) => entry.sheet.diagnostics); + } + + /// Computed style for one node across all sheets. + compute(nodes, { parents, target, env } = {}) { + const handles = this.#handles(); + if (handles.length === 0) return []; + return component.compute({ sheets: handles, nodes, parents, target, env }); + } + + /// Computed styles for every node in one pass, index-aligned with + /// `nodes`. + computeTree(nodes, { parents, env } = {}) { + const handles = this.#handles(); + if (handles.length === 0) return nodes.map(() => []); + return component.computeTree({ sheets: handles, nodes, parents, env }); + } + + /// Release every prepared sheet. A later `compute` re-prepares from the + /// retained source text. + release() { + for (const entry of this.#sheets) { + entry.sheet.release(); + entry.sheet = null; + } + } + + [Symbol.dispose]() { + this.release(); + } + + [Symbol.asyncDispose]() { + this.release(); + return Promise.resolve(); + } + + #handles() { + return this.#sheets.map((entry) => { + if (entry.sheet === null) { + entry.sheet = compile(entry.css, this.origin); + } + return entry.sheet.handle; + }); + } + + #sheets; + #nextId = 1; +} + +/// Create an engine hosting any number of author stylesheets. +export function createEngine(origin = 2) { + return new Engine(origin); +} diff --git a/experiments/css/src/index.js b/experiments/css/src/index.js new file mode 100644 index 0000000..1b717a6 --- /dev/null +++ b/experiments/css/src/index.js @@ -0,0 +1,144 @@ +// @bomb.sh/css — bindings and runtime for the bombshell:css component +// (WIT world `bombshell:css@0.4.0`). +// +// - `compiled` is the freestanding wasm module (brotli+Z85 embedded; the +// module is decoded eagerly at import and ready for synchronous +// instantiation). Regenerate with `node scripts/bundle-wasm.mjs`. +// - `compile(css)` is the main entry: it compiles CSS text, prepares the +// sheet, and returns a disposable `Sheet` — `using sheet = compile(css)` +// releases it at scope exit (`await using` also works; release is +// synchronous). The Sheet carries `ir` bytes, `diagnostics`, and lazily +// decoded `version`/`rules`. +// - `compute(sheet, ...)` / `computeTree(sheet, ...)` / `release(sheet)` are +// free-function alternatives to the Sheet methods. +// - `createEngine()` hosts any number of sheets, cascaded natively by the +// component (see engine.js). +// - For hosts that ship their own artifact: `loadCssComponent(bytes)` / +// `loadCssComponentFromModule(module)` return the raw ABI object +// (`compile`/`prepare`/`compute`/`computeTree`/`release`/`raw`). +// +// The embedded artifact decodes via `node:zlib`, so it targets Node-like +// runtimes; browser hosts load the raw module and use `loadCssComponent`. +import { compiled } from './wasm.js'; +import { decodeIr as decodeIrBytes, loadCssComponentFromModule } from './abi.js'; +export { NO_PARENT, loadCssComponent, loadCssComponentFromModule } from './abi.js'; +export { compiled }; + +export const component = loadCssComponentFromModule(compiled); + +/// Compile CSS text into a prepared, disposable Sheet. Throws `CompileError` +/// (with `diagnostics`) if compilation produced no IR; warnings-only +/// compiles still succeed with `sheet.diagnostics` populated. +export function compile(css, origin = 2) { + const { ir, diagnostics } = component.compile(css, origin); + if (ir === null) { + throw new CompileError(diagnostics); + } + const handle = component.prepare(ir); + if (handle === null) { + throw new PrepareError(); + } + return new Sheet({ handle, ir, diagnostics }); +} + +export function compute(sheet, { nodes, parents, target, env } = {}) { + return component.compute({ sheets: [handleOf(sheet)], nodes, parents, target, env }); +} + +export function computeTree(sheet, { nodes, parents, env } = {}) { + return component.computeTree({ sheets: [handleOf(sheet)], nodes, parents, env }); +} + +export function release(sheet) { + if (sheet instanceof Sheet) { + sheet.release(); + } else { + component.release(sheet); + } +} + +/// Decode the compiled stylesheet IR for inspection. Accepts a Sheet or raw +/// IR bytes. +export function decodeIr(sheet) { + return decodeIrBytes(sheet instanceof Sheet ? sheet.ir : sheet); +} + +function handleOf(sheet) { + return sheet instanceof Sheet ? sheet.handle : sheet; +} + +/// Thrown when compilation produces no IR. `diagnostics` holds the +/// severity/code/message list from the engine. +export class CompileError extends Error { + constructor(diagnostics) { + super('compile returned no IR'); + this.name = 'CompileError'; + this.diagnostics = diagnostics; + } +} + +/// Thrown when `prepare` rejects valid-looking IR bytes. +export class PrepareError extends Error { + constructor() { + super('prepare rejected the IR'); + this.name = 'PrepareError'; + } +} + +/// A prepared stylesheet. Wraps the raw handle so calls don't repeat it, and +/// releases itself at scope exit: `using sheet = compile(css)`. +export class Sheet { + constructor({ handle, ir, diagnostics }) { + this.handle = handle; + this.ir = ir; + this.diagnostics = diagnostics; + } + + /// Lazily decoded IR: version, origin, rules, layerOrder, keyframes, + /// opaque, warnings. + get version() { + return this.#decodedIr().version; + } + + get rules() { + return this.#decodedIr().rules; + } + + compute(nodes, { parents, target, env } = {}) { + return component.compute({ + sheets: [this.handle], + nodes, + parents, + target, + env, + }); + } + + computeTree(nodes, { parents, env } = {}) { + return component.computeTree({ sheets: [this.handle], nodes, parents, env }); + } + + release() { + if (this.handle != null) { + component.release(this.handle); + this.handle = null; + } + } + + [Symbol.dispose]() { + this.release(); + } + + [Symbol.asyncDispose]() { + this.release(); + return Promise.resolve(); + } + + #decodedIr() { + return (this.#decoded ??= decodeIrBytes(this.ir)); + } + + #decoded = null; +} + +export { Engine, createEngine } from './engine.js'; diff --git a/experiments/css/src/wasm.js b/experiments/css/src/wasm.js new file mode 100644 index 0000000..7262623 --- /dev/null +++ b/experiments/css/src/wasm.js @@ -0,0 +1,28 @@ +import { brotliDecompressSync } from 'node:zlib'; +const Z = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#'; +const T = new Uint8Array(128); +for (let i = 0; i < 85; i++) T[Z.charCodeAt(i)] = i; +// the table lookups are non-null for well-formed z85 input; the bounds +// checks below handle a short tail, so the assertions carry no risk +function d(s, n) { + const b = new Uint8Array(n); + let o = 0; + for (let i = 0; i < s.length && o < n; i += 5) { + const v = + T[s.charCodeAt(i)] * 52200625 + + T[s.charCodeAt(i + 1)] * 614125 + + T[s.charCodeAt(i + 2)] * 7225 + + T[s.charCodeAt(i + 3)] * 85 + + T[s.charCodeAt(i + 4)]; + if (o < n) b[o++] = Math.floor(v / 16777216); + if (o < n) b[o++] = Math.floor(v / 65536) % 256; + if (o < n) b[o++] = Math.floor(v / 256) % 256; + if (o < n) b[o++] = v % 256; + } + return b; +} +const compressed = d( + 'u?rJC0oIk*w@E/Ax1wCB7FH-q}Sxd%-a7>Sj4y*y[WgaxnQQV@ztbq@X2Jn3[pmGmrAi3Rhk#Lt4p}:7F#icX6{K0rLUj:aXu-wM(1B-Yg?ZuL3jVKF&U6>Wdq{WanbSm7O@RI@i}k3Zu2Vr}[uOQX3wVDWau^m7.uzn&34@c{P^/&&g:P(n.e0ha/ej#}ENG+.(w[pC^-VfzvKUryd=aOfCJ955%&.!Kz<=GtL9{g(c=yz[Cc$MD#43x:JYrHb#EE0H6LmWz-4yY-O.*B-Yc/(J?31zmsjAir66+)NN=tXhT.Wb6pLXwJQn@QDKzKE]/UVk5>^5C-3Gqv[?K!0mOo%ZKPcN5MLN2?L1pU{:36c7kOd5R8b50(YQn3yWty}-)Amp1n0Z92*.O=>WRGy/:cNcWZ4faCw@ElDLp/N-CWBxpKE&qZxgQYT#K!0d%peZ#n=Lt]V@2?zrw@gA@I[D*^W&W]*X(H^m&I@]dd58ZC0U6-8?HxnS4a#)y5ysewYB7K8])V+VV$F>0@=PkTfTjG@IrrolOQF=!HG5v!=Fl2l:Yesy)9*qFPre[f?L#KG@lieQ8^s^TjiWM:=aUvdpmQ^XYXDlL.za/6{qwo&T41:qO%nSbH*1$]Ue1I3fJ=X/s*C^W)k5%#LV:T-9Sr>gpgHG+7Ki^JnujUw.z^s-hQ9MQHIL]GGrs(p!NQOK0?puXULs@}FRL(]:5.9Kia#&2w0yoC05*X>&-UJ->ryhprl)2e3@.jU.zKLE/<[vd4{ftw^#Z8gK+6[Bp]Z3(Rr8qA(3!A7GlpnE=sqk/a#eLMmRugUsy&{XAB<}>FLnDNSl#z>ikLC7{cLZho?iBz)7pZ#atzE(!6/9/L$0MFjw[$d=Nrd$GCp383w}erm}*&<<}&xCEWgo4eAr62j}!U$%^K+zv0IYL>06%0g>ir0:pd=&FrLTCsz$(16[@3p{fCaR^BbiXAFY.]GJa)n[]OY(4Ya/S6>m0XYImu)KJ$nY6Ohw4)ROEIJO>60d6E^(L<.lMA>X!MM1.1jQ:GnIoJ?D.A$6nf/:$Utlm7PgmHz(dVF[CwkL1}U]@:qU$xV)!b(-KPm]P0!rXA1%WpzoV4$mEpKV}qf&]Qi4YGYj(S5O<09{H.f2B)b?$J}wjf$/f/5!BB0d7PKC.9ZdBgXzn}rcm0qi]*MFKz*rNlR4pO)tNaGfP[LXPoWVtMT/Ok%GN!Nd#aUFo:Bcf%8ryU!k$xv!YYq5j]vGwn@Fc]sv>PUP(Xn$&)zEb.?HH%Z30pQp-F2X}O6*[#Nk^zry5<2=*x]lheZrfEeHQP*vB@Ue?/O#@/9KXxllZ]FD:MBqPERMiB0SJqrBlKL?He^{mnaqMNk6hmn>@a!B^UOE6j$1-o@)x9^Spq#J2AT#%gk5O!:z^F:pUpD{OA*NHdmn}>@xqGddGK1ODqI0VBnqv3qoQRFD#yCj:(OXcv:Ge(t5sG6oS[wP.u9xuzZu{AboG6jmmqIM&+hqq{si>W0hn1f$2>AN+Wh%yo}ekp.nZu&7w315hgb])j+js!K^>FmGeu5TV*}QXZgoHBx{:xot.kv3jsYspPOpgx}}}c!9MH-CP+^[F}gZ3.-usUBqP8b}S=XxX(9JykZej(3v+m%z&lP)8W.VME7oKb<-c+dn&Y7iohBObdl+v2>Fjir1dZj?VhFp*T5QrM.p4(!<%?j)ca]Vho$2T1<8}efM/c8SGXz.@BEAIF6xJ>FrBMWR*JKb8VC#)c)3wN?4Ddm<%gpfXdzW!HaZ&5B1R4NbPkm5P&*9(brZLk9aCE+^s3t{Z)-8fP8{3OA%8msRCM{RA*9waP0cimS6c/JOQb%2K8uHMnzA[iI{kt*{wb[2GZ]jSl9fq6Ym(KrCQ>Grw7[29mqueD}nM7OZ:4hTFwNLc1boPBly^sk!ghIGyIZnTtbhji3SmtqL{FvW8$29o0e^>ZU(}dUr:vZDI{yYL?m=Zo+u=#ZCN16Pt&n]>D?svTnB@vkK4JF@!FU(%cLcJ]>(st/$RN?n2TF(FaXNYx]IQ&T^.7UpQ]&sbRV1d8r)gf^m^bU%he-2}$fm9%g:c1&s&Z8YN1qZUFw%MO2Ep{yR*harz&TZ[l&9-EgDZ(ZMlbEQZ)a2F$Ppu^{3=!n1&5yT@far-!@#VeeZAPz#}F/YUM?R:BD&oCD:g)o2Ax=Hu(qeHv?3{whCka!5r3Q=D@PU-w./2z:V6UmcZW7=Nf2[l1GvWsxM2O92f^R0}%lz/uZX-w)=U{b^D5{?g(PjV)hWMb9rOB8I?sX!xkjBaPDy}v?hR&tozT2L=Cw6H/{!Pxeo[&bd9*4#%dj3L8:SIM.(T8BUzxLcV%A:@J?zr]oF6bJpSs]9gc.j@xYP1Pyy&Ntny{53a:sZPI(!O]ri@l8i^]^9ukbsrNC)&d.{5L9c^2@9F2u!(XD6OgEer4as!!=J.%*nY[Z2@o5*jC9Uta@/yku(9r(HK4v?d/9#-kuF:aWclnbhck>fMIdI[0+)bVPn(dq3{%X}m8Leql(QM-en#My/AbYN9K^Fe-r}:92zGKUvv^EJc@=78F2+9N0ImZS.VJP*G-j0Z9?2XTw]wA:o]eUETJZB@0dzz}FOoZGvo]lzc1ya9=U<[8z7v5c#xjfd0nWJjKDOKi.0&UpM!e[*oHtNc9Z#^1fM-?+n!CELvz4qTNN3]q[8Pv]48ERBd5nu=0}BiF$OfFw<&v0(?c?&YP@$y7P{oo!#r}A}&PfdI*q^T&4O)AoBM@Xpro(!0Px!OsoEOb-tCojp.34@mO^u1nW:v(G$gyDTy.%>*oveU#+Y<-TqpYEXovtf+{(J$dH9(Jf^Hv!9=2X7k5J*HYp>]nT3iG7/S/E$k^apuq[1g{SUz!d/@1xliX.=naf-9TN7.:i.&bzHd.3M7HdH&R(]ApTUYdFmhJhn.B$=@giBHz.YU1em.q7NkQ0&&bI?W5T9+W@O=#=Z6k-v=po8p$sJ]EZ+Lp6-(eC*)F3vl56uG3o}iPrSBIwr-C^=wg*U]C1L4OYqTtKJ{QqV{S].{]%SL4u2$6@]ljz7l&2.y}m#.:xyiq:X)1M?mD3h2l8MN3NK19&CQ4Mbuw?Dugwbx&3RaCM6S>bN1kUXj5{?X(tbWKjUtG!A+:$aT@wib?#)yoZ)x*U8aYiWn65A+jm3-^?=o>3DN39w#ijCt6z7xwu[76e%St5lu]y0j3^b1sLK[w%K@on}+Fr$tS/z/6&.{XOC&w{S8jeD!5hsyLP<1}EpW[x.bGh+*/^6LOB!)yl/PStbfPIS3z>{dVESL$=BwYr+[qn)9}UpoI4:v^O]a7+t6Y

>g43++:Xnlu.x6N$)Z%ueL$Ar>oT3.%9huR47>eeb^QG6E&2q:j{A+KUfI9(.+fBel{KGyVS8D8GcXm-+zg!q$hWw[9LwD$#TRZGlhKel(vVWD.-8zGRwG}R6/)#OexB/gz1C-hHMz8(!opP^G(h7r]kO/JHZYKR3bCnthHU{eZ(-]2H?.HNi0BoZ#-ekFG$9?VY8=Lo!V++3?^LAxwdW^2e7mNbtfincH)1Y85ao>8pP{2]cn}a7^P!)PWLPO0bI/gz1[WC**k6tM0TiI^Ewb-z5?]>cY(MO.(rM@j3!-5PV%1ti7@5T9Zo^K<6U6!bsih?!/[3&UNT40g1B-n[eHKZ[(Wq=}KIu^fT2-MQifOb%AEyS[{tIAg?Ni*r)/AMp[T]dk^<677TXh/R6hV@3ORTb$/1]GP)piC2AHldco.)7/3<[UxN$:wLByz+)(xRT@1YMUFHQrRvlFPd9v[!YwPQ6mOND8V]dv4S^]WJ(iTt}-lwDJBx/v8BTH@&W9]o4irW7+C]5d@]h!GKy=Y:Y{NNXeCLph7l1?HLOIM}>rdUy@RD0!+XaxIWHeLCRWZnzwM&1dJA:jE@F^xdUqz^Hf65!=?GEjNMFl=w7fT09W>DN544]FS!ABtCu*J^#o7r0H*p&W#S^2O73NX]gYO&0)PV[HE3}]4y}=?#SAtjM&Tx$w@P>[ba{dgT+cepn9R?5ybSzkuA:t1Q%t]VV2Q8^VeT-+eGgSQSr=%i3@ntR*qQI#?-:F%ju=w=r]JYk9M5Hp?$Sm=5{ow&!iNP&mH}I(Y}EbKh538glttY.lt)zaW)8)Dot(!P2yIioz^^73=#$D/?2K>W-*&@Fu.vzmk:V/u%f@J@7BEvD6HAw)qFWfQ6Tca2KbJQsi>(+u25h{RN[>z1EOfh]rIlp2U3w25wcDbP8WjQRRq:4.$Nx)mFnECsOK$wPYPS+u@6)*-[-pU5)[gyOG0)/3c2W$mNW:Y>bmTQmWSBoh2*z^g[Y2nP:!lwiIqZm2.kjj4lY.(N^.zE^*aZzP*1qjz^H1sl2iXt{4fE-QpH:Q48x7+.82=:3jMy%RGt0d!vTwujovCh&M}OK{:]![d-a@)E*9pL7zzMtA7q}$BL3/qt6D4j99g9rg(}6UQDq[{5G0cmJ[N*Z1=KK4gq-OMtG/4Dg9!wh.5+4lsly7Sl1Gcnb32TBmF:kJO5{OT3oItT:&j.eod6w92&ZR]Rs174kgfHxibGTOa18MN^C/ewaifhaY:C//CI/yp6V2157L.i-s4v%5jRm4UPu^Pa??H<%%?c*?yO&pTSh9?Y3OG3:RsVK4>?eX5*Or4!j%D&LV:ma(${any3mlF*(00E8=AX.V(YTYk}w@Oc[yU8=gk&l{V%]eX*Fef+lCk=8zRPgo+BF>F(ab00lYm5@2p@hN!S@7oIrTdtIe?mC#F?WzQg(STqi^N42$}3n@[YlFWAaI8Q!x/pvmW[fiq2^)-3uvq(JsAKYL>Mqvt3I[ci1hQ1hFc{7uTiB{V(z[?R@joN*v&F^.vB&08+%3iAm7Wp]C+nRXK8?dzWg8^1YAbVg@h^BY[9+A{09]/uT3%0#-T=NM}?Rdz5O$Yjg^?e3wD{<:xQv!!rGm*F{Br+mXz%?Yhgi>=oGg7/pP6fBOo1p}d/U[vJTCc2v@b]L7eZTNhVG2u90O>u0Y}XK*6F[3=BeOLTK@o+17B.]?e8ov+L:b-rjunDJI+Q*^Zcxk+)k9uqIvv+Jju-:V!R(.)TkcVnW0wugvoR^/go=V7gJ9L{%!5j+Gz:[/k9]AWEE)c}&AG:a?XkGSr(Mwc3X@(ZqWFco#td&(7g-txnr9KCoDSLEvjy$q:Rb&<>J]hU1M<2i)(&#AAs].$s0+!S1gQeVij7<:TXvdp!VMu.{Kz!Z-ZF0hS(/1BJ(Mr%iTCQ7Lecwt^/VM{T!/JDPZI8?IKP^RSN+cHd52$3s2uwY}CBA^3eb=e1WK3zC7h!nejiVq#M9v?)kq]8N-0+@%ga<9!2k7Eh0p-Ymh4&1bn0BLpXKc8uR}-w{P(Lja5wKgiM(Wq*Y[>*WQMpMr4r?F}-ZwTJDk%(MscaUA4o-0o7J)z}[Dg0bWC6kJUZ0zCxR$tpd&b($IpAwXg6}pj2*#pAaVo5r@t{nGD+@B8q3i>&9kL)Y(8rMoafzI:^lPg*xmMsw?/01>vyo^wQ]yTsS0e5=rQEIjJ)]?C0X%S24VKj+X#I+Wsnn^Be2a82AP+F1:}8yLK$zUW5FO1>j6raQOu(TjS^=N)Ip!?qu7biOTxP(x=k!1h]!gsMp=aELPp>e9tBpJsQa2m]xtfhg]g$Eq)+?GmV#F]^d[DkH5T40{zc8vk!PNW2U[:T#cH0FQ/F:2V{%^zK:VIj/--n&?jALVPPro@JpG$>!O3P*T5#%h:{LeOBCcQ.H%doNA}+aS%ntla]NY{!HtD{Jr.M3usYpxvN9b-8IZgvsD)Tkn$nt:Trh@K:c(A-1U)!P4i2]W(^%1!>xPf2c(aZ>[G1)!i/EhxUHj8yhgg*U46&j#rFj?u[vtao[wP/u-j*dG?P?-p$GEv[]EH-O@WE5b>/cB>db8pD]BBPXDEUxrnqsHVm&!zvi4%0GUvTYOEWFlLxmvm=4aK]S9L-hP%?A/Ub)jQx:+DPM1yN8(uxG${tlfs.a{qwO^{P5ol]3Lt>hcNYO9esklV(1)W>8wJ8Qm}FOMrK>2HA+-S#-!>Rb.K#lGQBtLa!Wq}KH2HvDPZoT^Bvpt=&Df6sTqN.01ArqmotjlMUQN*krTcs2JV3A1zKtS+5xi0=NnHL!lb]ULevLNxv+=RItU+Pl@X.0d-c6V7XN7L/[ob4f]XC9n?YYn5NcC*Og{<5YK^P+!*D)(!u->I4KmZbKRak6{BjOhXvZ!@iOiFf{M6Bcgj*0a.:eQLTfweIjR8ZrfZ55t)8U:2bL$+xzfd}/(eD&:+xOD(5J+9rI&7h(uQ0YO?f45nCaVxLb1Y+K[kqhp+uaBQQbTD^j4&F&bBaC1@Rxy18/z(:&tghh*SMV=cSmj5Ajm@>/^tstCej3=f791xi%n5uK5uK?vlv*=CV+-bh+2w}caFPZ[dXH.20@2%a)#K14qlby23>HrAO:d@e9zz]*qZO}Z{mXK5r$e*rOy6[*0^8ORz7:)ep]DV.-i=X.Fn+z}#aVSVzsLCJB5cyC7.N9GP#lne{ha@9+g?jk)wn[2%/fD+J$Z[8ZZo0DlSqGiMn*).Bb3:rg]k]@HZ1Yh0r2Rqq2qQHVc/dp3}n*dQ-++Say@{Uw]fC&6mzE[9)yfT5.A]$td6]3BKl+EjsRFyMAn9cOw41JDtxyA3DP48B!HCv-k9m6xh}D+MUlR!9X{2hRXWpU]/dIj=b5]L.BP5{$?-*PIl.r[F]#xI{wNfxajr/[o=:AreE1{HMiia1.]8Aw5rfS!:j4o6F)*@7#fUT(PkWTw7X0deNYG/MrO%6z5>SXsBkn5z:tg1J-/6P=3yU=Y@gSQ)ZVjIR131FF.[e]5+ze@Q+5cr8VK>lzfx)i+jBkN-?pVP.TPlbpf@Oa.v{>nFX>>Cp{u2=x-E*SztuzxgRHNrOB*+2Sh3Y}$NuWGm57:<0}zplknF.n!:lOsH}1ZU>iQgV+[im:7@s2E7=+k^<5m^!8aCJ7Ls[Rm!F9]JBe8G(60d&FH=&Sl&B5RzN:Sy})MsF.gkb]&5:SlzAH-/yXNeu2EzkiR&.huuH+OQWEb&Dr07U7N$!:S}F=BVvi5c:{i%Or5iea!u1plZnQ5>HJMzbw#Q4+j>rJ+S)Al8?Aq.ZcG9pGu/nWmtrSp#gM)>:j-p6WUH@Mp605K{&E?N]*y!>q?n$uaD#1XiVHe=T]#n%n5EH:aG?=lQ!$uP{7E-y+C4%(7EFWoBcst#es5+lbFU}94i&HGC?khh(Ay[M]ux$:2y*#v?>+S-aD)Rt0Ww6{[:O$89f=aq+.Zj2[Am+-5s7:%v99+Dvo@I!YuCYCa9e?zn*?:5K5spaoeBo!k8{%W!2%31?e$O]3JB]CZq(hE&OJNBVdK>aA(g=:KsN[k}JP^#}8Tb33i]RASGh7B.WO*O]CfLLlh3-#(P%f%*B!1*WeK)iK6Ex4gIX^i&35{MNy(-z{WO&{{Wx:?(b>?XAhd!#l&nT38[^-19=[*B(A!9#iy&I4wWSig?mE]Y4l0Q+fdGCN>U(crPHOh^InejpjQR(2P2290-6#CD@!I3UK^^gRu(Wh>dw7TS($bb>I?Cs{iu>IKx(VpGT@47zR3iy{RbCNJT)LXtN}E6/5{}wr5CWV+vqf?#j=cjgr94ePKD.wsl7hcaMHd)P^Z^TLj^ltbrZf^52vF2jm]%LNKS.ixs4$#@p*Etf)*}0^[17H@U&BB7#/JK&NUI::&yR=ppL-.oc)uBEYXWQ@=uKf23G?)+SE[?)2{iPUHNRKX$.lASTD%x/+NncsP&NHhlw(aSagqvt$GMUbsqWV(?a&RJ6:WYffT^G4!x#!5uIm54oOZ4=rU<=9RJ0wa10ME&7nIXP*tDOcxV83roN[b9&CrcpJRxUPFg]*QFVn30kPLCfvUR-PpMb]LP(GR7Jms1Y%i+5C:z%-KR&rwsN0z2n2JKvv+:Ly0L[H$ocxPdXkb$cx02YSx8uW4IwwuQ^Zo#LhSc)kI{[Uk2>tEj=5-o0vfa-Y-vJt3@f2wrvm/D>WqQbCNNqB.}vKPHeW102+9/}1XXIYi/.8L(]ixOI(=KJXBbn{8M=nS%=Xcv^^00JvaUx+mSUbp+!Zm30ii)fVkCIJjldL/+jCTAuqGBX1](I*QJ:+XA%kyYkI$@1:%k:u9pHe2#B]]L5/S*fvjNs18vw?@TQscP6EF&Ks$2/BLw4VNs@&:DM?b5vPf#X%295%ne4*arYe8UF5Z[lz&^i.ElO{&H.(wGFxPt#Bm93tWhM(xK7@EHFVkj=G!=4)kB$33p2!1Z}qh#/!5@Y4[(oWtieTNRw!epovvK>^/VGYIgtbl5wAwD2dwO7o1#O%G{@Y57VYL@+y]*S4Lw^#bJTqQa]6{:HM4RMB{$sR4Ef[2L56gWXI[f(U:ZcTEvE8OkvpUnjlJYL8wAW:8r%&S]++HWEfNWusWV^3-]v:XXoxs/RMwMJxt1A5!@fv)nF]=lEJPgYYRos[&p02IBlKw>LOGuB2SH(wMth%OPJ>Wx46y6!+)tPCn/@]T1cx3Vjd%RroF>&a(Ft:1c?[9./ZhyQ:(enJ9IpjA!+Qu<[4K8[L0I&g.?zpy-pw$+w)4@T[P$FS+*ZO46x$}inPkf}il$d]o)8oDi47.QAHR2@F*UQf3MAHB+2*DCGs%Ff>db71jzO^XkIS#BM^fK?l-iNI}}UrB.+YH+o0@^DgJZ)n)pM65WX#JY1g7e5OY#uhv+Ni=*f][R]?S}+q!bJnq0OFcO8)!RP4K%:j*GmgW5oQDEoX@(8AXHQ}w!F7/sC5HTZ.]jExDP]ov?biI7bVWh!!uMt.MS:=:pRNE}>1W.ZyyqQ4]OGVo{HJy)62%zG(&G^0cmWy]D1(=4zv2Dxy[4uTBfVP3/BW&/%1r::txo1z#]<[8^6&7s^ZAlJ(nhH3V{9]-qqcXvt.BCr.2K6[vC.FO^Pzy}g0pv7.ECAx{nz:xNF{prWI&A>M8^7]^:4+1bbZZT$1Jo)5ncm#/VW:#[oLw6J-i.}/kC)R1Wz70Uf{J38>Rm+Vki6AU)9US=^O%[qrC:F8]S=^j.admN}>FTVCY6j$P79Nd)tu:VszH#vO{sry/7<9=[SG9ZIZ4-Y+yTK0=sV0!O6CGb@IH@wu*rbA6HQhh7f?vXF8aY5&MD&2gHyjP&tNYWG-hbnxpw$pN$-Arrz]il:B=sw&7/qIh@sa)}}tGfCOY:]EHzatt4or1WJ/z3cUmCd&jp?yzps=FMxH%qkOtiM2J?X./JPTJvZ&hLNHPx{eZ!mX!2Ynu8lbltb5)*}if?twPfZDkE>qT^dE4sd$bGlPJcc*.Khwq73QM5F4IcD&Rw3Co#.ElVDZ+&SH.phbh35Mif^@&[G[H8YP!&xrx1+P?>S})y87YlHtRMZGdA=z*1yk++.ZE=lf4HxQxGAr2vAsf6kmZ2/$I{%zTF<*SaE{@N&Ps4XboBXxXn[5W{^xZn/0RrN[]NWBOTdL3m.E}]ocwU:Dc*ON&UJnif?U(bRy6M[W4Okpg{3OxGLG>BRtUm6GK4)HVVDyV8}UXa<^9[YZj6mupj#A7H[#2!E(S5G(&{1n:OgqB:>Nl4VEhA5DE0I?vWRa(!6vy/%)9x84djPG#vPrm8}[.SDIFIxGlV%UJezI3No8sHiIs0^H2B+EJ(Hj&)J?V-YX{:}^?a5YZ%OZ}@jkVyT3O+M9z7#RrtoKfs2=#N}D)qOKIWhS/B7Jo0%xt>H()hn.k0OW=wkiDxM8fj5sHs}WF)kn#ZHcR[qYfRDVcj4lWoa2F.G88L1$$3gqJk0D*Rq?q{2UH-*$2Bdk9]Zr#-=/wj2G.f&wW{y{WvLwk./nnS:dTA8HQzLr[:0m$f$*m?o@jtK>^FbzfH)R*c]4!}e2DWuC/u)RSUDNl]L3r.pnJI/@S!cov0w%))AE@0BXxMsm=e(vVUlBHT-ol&V[0rZxED$2](9R3Wh2ER.jXyTuKcQGpjn7&3w*/c{s0uHPhME[MZXK5el5vI}*09z}bu5&K.p*crP)DLHewoqetMas$5U-6&QSNKlgA&HEJR#9s*+RaZMiwLP%F+y&oHUCWXba$9>HZx&(}@:7>yPfJ$l*>iGCi=KpWMl)If3HVu#1fL0hyCqwP1reZ+b&.ySAb4kXl]{+1yT[*4we%(Kyx2o9<{0NNup:)(Bpa&-?A/Dax/D]qV9e4qYPA4I4OnfL8Wf@+*mgC(pvv#f=FhqV[06-W2d{o1$P51o}OL7OE}rvV7>^8.fChe#%(Ci4H:Z^EEX=-tYX3i@:]=/5Rg.J6#>utd{{p[RoW-UCp2Gs/M6y/(3X0I?#six+.M4d2C>UH{KvMb#&Q(E6Nmjf@7fssqBdlgvX-Az}jX^fgP/Q?)*.n4PUKZpB#9LpE[aG1-m978h9hXxi^(&-@AT>3(&)=F7m{FNO-&dS@C%I=IEUD6}+RN6SPMUv6{+o%srUI+uV>F4c8@l]!J-ZspecSu@=I2puixkm=5P]PcZ1kh-{)q>XvO&]ry(-=!^5RRvy4k1kfBaBIy0L%q=$AOT^93A:=t&5QzXfGxiyYO[/.c7SwlDM?w+DfBK3RANVu1^[]<5WR.TL8!t)aSjP:&DR#=Y^k8J!I}Jon%ONIVu]&@U3(nHtBqUUF(JqEuR7G!OxZP3->l-[>rkjp?q0]i^&Vhl9Y6:5LvO6S}kXOoL8?HVAX:uUdLQ4rMN#kIlf>Ws0]BphX+GD%%q?ROk9s=Gv]jfB=!zzDJPh8Yu^/(-90W]aSE$ZGidJ33tpbs[51R&YM}hV5XBJF6oAY[V$u1-8inJMH.[Ibc$gk*+N6$!JLAc3wQH+o?{hJ-9f2oPJdSL3)i44gELVQb!L(oz/7MJwmCqYpX+Dq?i%$kHHlQu0eU%KRpojLi(-U*&AQ-1D$u.qQ{?ZBr*Mnej^/06alKrp!L:&No^8lSeyZX]qs0u$Bk8!tPkkJZw&*UUDyzx319H90X>T5>9*HSFL3}25Q*W&TLgoF)Th7Crvpc#[u>vH&jR5NAUKwj4kJ>2($9gJ=mF:0>fAKmRLqGkeeY53WDq1y%diC6.L.3cP#Jec#$/n.SUQ+@xdL+bR^V>PoFtMu}xmt3F}ub{gT@7Cx^7IT5.5+::?C1L2mpV7*DbP6h?vrDBno)f-G%NqzQZP4:+LS.5e.LC3Cg(QrLn*4i9*xM(d2@ahYEKs86u4TTGLWC1v^F60xqnEWTxm8Lv}.*C5aG3[>8X2vEimJ(EVsd4}&j#9ib/Xrl33$[7{z9izAgDb8]0dHFz%SFMgx%!*XXiD}K4Z&8)#j[C4FhL..%U{9zcWplCExH<#mZ3DCU&cP{@}TTL%wF?=y+5BW5>E7VUv(3*78?FY+:auPv=+MfPsfy+{=i/Z{v0Vl5*V@KqhR:}{ZB.*RS}Z3)*zEvYXi@/wCYIX@o2b.Z-}>E2oh(UbjsNjaERY#e1T9X.li[H&I6m2{6s!#F%0)XSmcm>.u>aWMa2dqd&Hagp]^YlC^=e/LH6Z1n@hmvi0PmkeJ6k+&gOXvfRLZKC(>Dt}cjSFbh)=brZuniQMdPFb*]ehM0aW(>Q8h-@4>YDfdQ4%A]Km&alZdpvNwKF2X=MX%EJFR#Nrc@[D2ZL0+:c]koEzd$&ZscVQ)F?R&8txU78-}uk3[Z6c/5S(yEOJZ{T>k:QGX*31$2bU?{2js&+4VL-e*!d+-okZc8Hva3b}rgBAqI?L*2ox]@bBrk@:.BWBN/9V]piEozXP8FG8NfKB&T-B-uZ+mbHAs3&i]ygQ{or2@7$B/Z-5x9iv^qw1av[^Swe%3U/Z/psU5tZv%K]U$GlCeP$TAXHP.3z.0G51]B*Jtc%Hcv{$SI[9>cg3QBlx!FZZpb)EV5t7C#h=p[4rhhl9IC?c/LX3>3m^p=t?p5gBUfu^87b}Isd8^9K49EmV?jsfr6CkafGc-O4PJ*H7t$.8@lFY5E&.V!eK-]5=uSU!APT@o^Uq@boC)^#wHR@u*9!BSCMIQTjsGj{0>VUOt5pAwZW39mRbKZ!Hy+n9iWKzrq)hEbEQq}TY[Yn)b&h-QN%uGT/}H8xS<1.!Hhx$5pY?JlO//Lq}3hHptkDfCJOEHAj!Xa)Ct5/4EY<1GKFZsVR2M/^4XH@5s=<$[Kiu%S^.GzP:d2q$90.z:nm:IB[f=my:{4)L*UY7P%:KZ[s!bzt9R{Wxc+KL!ZH[aG=SFX}+e{}m8p?}/qB25>-5NC2B!&^Bs.:[+e>0w<9mCwj)w1@:@/)*Ji@O*lb^M%d56R%8erc0>f>[MH{EgauWw!@:*K72)UWi@PPPO:^132Lg0{Oh.V3&b&b?(crtVQTKmuk5v.#3[kondQ*3csWZ@]U#Ai9tx]EvCYT(IwUAjtgI6HU*o+(AmuL%l1@9KdwV6%J8hwq:++UIXJ(ayaIGR+35hgS<3.(t]26X0Uvs}sr/^Uxpu7I$qoWEOPw]{{tFwdYWjho1Soy0s9U?BC^G2HcT-h=/BiE%z*ffv6cqIxnfr7w(q2U}k-B0ZNnwT4P9H-*Cm(-96LNOI(IIX7@JZp}4L=ErJ7l85>cdP/Rg{5%E}f#S[62zl5&TbBG@0Fv}t$6[uyZr^?lODP%RrGcr+hXDa=AOX2LU#]4?>5Q<94E93dM+cmv=yZGY!z-JspTX-a0dx+Am32Z6PC$rV2meCcJho?.m5GcRIr$6B](HsdrofsM<[c04cAyShE]fkwAWSycZ4g$f&6b{h^!a>#T?zpQ7D6/Bd([Bie}NB7SRO1#S)aHiAbE$C.j3FoV-PKeGD!=v:/0d>gt#ae9DdFt]{IF{nv%=z>10ReCR:.IL#sDZ)y/h#8K.S5UP^KWau}3{2=mcuearKIIksjBH>M>3.YH({gdZ0Kh>m>$m:y1aupShuW)H->co5]^mU6lEreBihOii8k!s/FW5EZV0ta}[5C?)G+<&5X6J8A!VIbaUnq)T/lY[&/#E/Xg9FX&?ikBhgw*>ql>yQ3fQy6ztWx2cZiUJ7K!jGdipP4j5>-LdW32}.K7E%VlRF]4GC9c[Cav[1*0j+#aZ$G*AoT!^[g!U=!>wIPOeu*Ie{DN{E@D)HmBy]^Y-G#+xZAbBQf--y/g7Z14&IQ=IkMK&4io7yQ)JqhL9H&rTt-ZyRf$b]uL!>y97}zWv)g{@enqh?cB6IHhDDMUfbq=$Aqt3l4iR&Hw*!/j.+4gkB%[xFQZXnWC2Wf3Jlu?E^HgRjkX/GoF0pjRGvRUD5d!LAs!F[y:Oj24/cKU<02-za4$LFK]/BZH6JG*3)jL.iArcMzaP:Y?p(dLHEColuPvvWo8GoqmJ@-hoU%K^3yJ}jl@PURo-)ZuJ/@wmvYWS&ruek1jQnhEmtpw=]C6R$UO!.c&0WnJnE1esaKQ)2F+Q>2-mpqB2}.JxqZhQ(!C%x2yww6q2cDenATW/R^fIMS}v@wR!+eyg4b.ik)}73KNjF/2Yhi>JwzX^^:/JhQBenEOou!H6%{>vgc]wep}rzN9<9nA-?a]nXxMv?R4mNr>30@@Pz2b]MyH]7Xd!GId.2*8YZ{dlPDaqzIQhs:XJ=pL&O+ubmz^0oI440+IrfZAY{8qn6wSKn9QLR!y5V0!WHr^C.$Zru:}+x}2lo-hodY>}rZ+PkU=Cf3nh:K98L+-y-JtCd}!cRic}1B?Ic@JZd?(]]7P%ax+Ud][]mBo&-n%]nLo1Pqkvr7n6vc:}l9v(r>^Wg%h>9BC^$SoTDD-!h@8@n)WXMXu]Y?yMpH%H4Ozs:yw)vIV(-8Dr>w+*3OK3pSTzvczeaO1n}QRUI)Yaqe^47A>m87KLl6$xt%1?b*)KUw!8>E>E>Hil{?U@oDz1lSGbH[NrbHz.>nzd{vs/Va.AT#O[z/NF]:WHV$7>n[#IMiYJ6-Q@zOE/vg(MpnWLn-dTT3bnaq)pq#7HuGhKo!Sf/MdTuc&NzeBU[O#ebmI09:p.sxTvt9)RQTMlL.{zSzZRwRu2MGAsV2TWOjAj=O.x3C+WUn?2h)[ybMUpWOYg}XOz{IoXx!WAg1C8qi$}F:Ziifr&O4>dkOWaRKu$3/C2Wmua0cZc2J[Dut!jQzbsk@^a*S6SZDy&GM*40r]L^BCyh.oXj^69M5Az2q]KAn%[v*z@Vm*OmR1cC*B?r6MASbP@@2Lq(^oA+RCTM%hWsXuLEw5sv8wPXC*HD=+dT1t?&Ski5>1nf[>.=.a)x@20JzB%&W.g-RI/ZjD2W^KkXTvN.aN&RBnU{#SZ%}%K6{0Ud5cHCa)pjg->7-*{o#Wvs>9}QW(H8&}o%XkSvTI1>d9tA#y5UOLgb9#Z(E5L8kx?09c$OQuM3DR}J}w6o(-I#2joXqVH>W+:qjD4SYgvlJl%UyZQi-Nj!(e7!Ag$@oKJzqQ}jHW5@1HkN/HTqXL^(>!HJJ:{Q8-jWOhF!r=IBc=F=5FwjuiR?6axu:k^?PgtF!@gzssR]aoLLz2wQi7l^D=sLGeeOeEwnuS{VB0%u2+(C=ps}a-JJDe#+()3sH[^JS)?T5KEW}P]*w1eR&ZUV7pUkt)6YStI^EV0>)V^L6U:Srp9i!/{6%nMmx{4r@QJaXR9rN?YTE(mfBYHA0Pv^x-x}Xbgl)AL1Ea9Zs]cOz8^r9p(8vCfZqyLI=lUwRF1*KG:Q8RtiUx!g#wl5^H#0]xE$*z{<:TG@KrYMtHfiRqv$e!:s{UPtzNQKauF(17d6fice5%=CPm7)l/af*get=e(lxkCkv5>i3}%[X@rbJ5Ne>ZwiR:)UC8}41!8*nlZr+:*tDdsLg9^-SX4]{X5+kKL-OxN4UBB&oxl}cJmfqVqeI78QszS&BoUt[C*Z*-E7o)&cb[zwm.90[BkI8BB26I5Q]5+hc@Mp1oI#ZF]QFUINa+6^X(h:Y@C}T2uTrS@TlS3mE[q-Lu/(ml+Ga5-4CIv0*H*bJMFx7:cZRG*r{qQkP5feAN(lw4NVP5&Qen-:>?rHRUy&F:==%FiSxe0Poz&h/9%s8RvfYpjiEyiF[?hFe1w@%O:SO5d[{?tSFQ=ip@HwT^iP)7{r6OfY^w(nR!T{HAWwys$-(r@wsS3$0pf$.N:oFfHEYt[F:1:zV:!}P]ROmhPafwOzUV!efvu4Xio$53H!@w6*NJRwUkY3:O48eJqcFc]9zC>)p*PsE$SYGx*f5z@)-3lg*>qe#t?DR%Y>=[sVqasdo3B/e=yew4EU^YEw*d(jag{O7fKnjp#XNR2^tB]+@4guLT.f@w9)-*ullnD8bv{BzdIYywwGAUw{=V7.%/w.T2>^a[4jkV0Rwt2*ebq#oOye7v&jM-!SW9P.Fp5#M]aV%HGb#deSH/:])8PiepbUE$S:?*Nc5q3Me8csXjWcnCJih+p:O?[r!Qaw!c!&N7}Ex.9*{pgHYO-e]g!iN!{02EI0&9ct>+>kDt$MZJ(S]Wk6*H^>j{ChOpb^.8ltb$&1+v=1&0cN-&MA9fbUK07o4&SAiPQ0k6?-G:^8q%yiZc&eX=9GI@8!Jf8mS.R:(wtdo#!/qnsQw<6I2*PM0:xIza42fywVx@+NC)/YPh0t>*T7$)8@RciIYtX@eNMpgO3yg+uZh)7j9G%[Uz{}e4gP2)7#wuRh?Sy.zctt]hU4dP]=Cn67eP-^v*)I]8)bGYtg](%^}c&:qUa)jY0?[r7[qd6o)[EC(G-({v%!0eIZBTojUqNcf:jITC$ZDkEr8q#Mv<5Q7!B1^[0a*0W06]bwWtp@15IICPBT5i0HghqvId@A(4K5=UaX*6-Q3)tKGR49NghR3Vi5Sw-ygv4Cm!lsCQ/ji+!wkhSHNd*VU:b7eq^r(L&TOfQwAy.x17jO!{[D.)lrxc(G{V4CNU)qzKYKZ31AVPCQ#V%tWDVzQ.:ok$hK{mhz@$6Dg!d[P(Om^JeaoI&NHUZ9[B2=T!^4XB#tnthPDAy]3vppV@38:YF=$hZjqVu:NlgoQ720g?n9^[=lj6Jkpr+gbd4&sD(sQdG@E@88Eh)}W5d%?=x>>rf]Sz1+tN+gc/LW}crd:s-5^YgS/cPik[okSg:88t/U:66QlgH*Wwjokj@x:ikATNK&dUuASpnWYG#f{SC}[-qf@X!JdB-YW3NH%8Kr=gR6A%CO&(d9&iUS7*?.@zCyfgnkgol>e4CsOP)*iAm&q*WR^2-%}m}P.5*siD)!ICXaq%Qq4+XXxT=*4^hBUx2>oryyDD0I!%T3?jRR9mt!Rw8rA+JWA!Y3-s#:b?sZA{4p0-wQM{s{OHogu(oCzVDnWpIZC%Jy2xxpbSgxedS&PaLZ9fF^]I6sY?:E+M$.EmR{DThHh^FM8M/$78MI?nb5yrcq}kz6k3ckfl:NBVB[^=ujkX?J%Gn+2urigEzPc9qugiSU#5GcR-2q0P6ds-l>(fk4e1oS6<<.OVdzS2d-^)zc@#c^flhTb]bB5[F>HV!CryHt52ZpuYK>D1Rx/k8C}=mQ/3Y>:A#2<3(P(-U^Y}VgTC*]A{?U^x2D.#kYhmGI]M{lKDn94qrOT!JgqJO=PH6lb&qb9W!zC]Vf&iyHeAGExBJ]IaSA-Q#M7@noMFqE}bg}p9{T(L.4X3{a=(Yq>a]fXH+^P7-]7uEA?D}7j*1-c(5T1oj4V67J!06cFM0x}gY!fC>pNL-tjt*ruM!1h%E-&BR*7<#CRufOEGtOR&wI!+mlyb6*irhedAY^r(&-*bj3oo2wL2A&rz:RO:*AYTWK=3+cu{hi:pvEWe8.f:$R#hcK/d)Qlq.(wR{2:CTX7lEXtSFScX!Ggr&ed[+*>y1H)!rFbPhVy[ZF@ZZl$uXg6Zk}#g*o=pxypT:Z:t=P4SZ=?bQLfMS[MNBYXp<{U0[HcAVnwilF4yNyKQgW-]xcH+1tc!vOrD>!PN--7]hMGy$Xuh!Y@NF2E&S7^=y#EiDiiXTSJ7e5aP@1v+*mKnmZKwBB:)FB4bAjV:z4+SNf$:E@5r].6h9Ty3CRI*v8X++&a.>MdF$wy.MKA}GFPNOgjRk/+yrZtn}[qlw.9{Ta:(e@.VHrj{MZ]Y/-2y4v)(-nvIjOCbySIKckJ#61ef2DU>Wf)FM:qqH:0.Q@+2mc++bKk3ktj*&0/AcW8VCSpJeD)h8#mzMbYip%njSrWRxxKDS[uJ{*)LK3h5Id+S+3%[2-(pOKa.(kEbVty@(kwArA3f0o2xomw<7ia^T3J9=Fbh%ic(uvbjyIi>}Ei]+@8oA$${:3A3{}(-0U8LBDH1R@p!^aXA].fMd!Zd%s9[ii{lmv2#0U<1ofJ98E.PM5nq>K8Bk}{gwQDB[DFkvvSmGZT-d{jWUqYG9At{[RfXYFS?=7L@*.G#VZDr5jG4vgyyyism<3LqnLl{NhCo(O!E7IDN{e&Rct4iQ+kw<>Lk5d5nfg?s^[bBXepR%BtJTvpE48ahBGhiFd5yby4O*X6A(FSR3[QRHSCFWWHuymmS)-f(Z5+!%V-AMxuB8s)PmRPKB(:C6TeLS0TVD:sQ3fHsnjvO<::@l!S:+Ct7@c9u-fbZ[J?Z^wn?55Mr0iSJ&bQ&YpbQ.cg0:I@=8diX2L1Iwv5]1aNw^*SfQMS1l=#.1BD5mOCI3M<1k^<.vfjIduz+=ddjL!MQjhwu<#UmjOQjXf!>zs=7MW>h(uwOUT)Sg1v&(JF.A(y*#8u2tkN>H^9x6pXYc*BqGnVX/8gIk:WEjH4/eOhH$:7J/hhpR4Z4@F/)gz]gaYI$M@!n]=NXs$vtn?^n5jhlf0@5lEwstMCTMvX1Gdy(BQKzc>&A^ODXm)!t-UoFUnv[.HXpY2vFjEk=naUef(W57J]h3@(arr^a%IO)*{(?wQYy9LzZ5qFfO.dcuUG6{93lxSFL=44V6)>KPa}J^a+zv7t!BkT]=(ZRM+-T{Q}iRPRHP>G/Q7?&9U)0NXy{KjrDS7H^tNEzsP?P$Wf%llbrBig>KpFsK5}a/KwZm6/3fl&:pSDHenFx0&OBjzUkdi)/H:]75Br/QiBEFY2+r-:+E&R[BY{A3I/e^p-n0YYVay54-BXCqh>]2zpu?G!.Zc^eZieyBnj>rf]l1<}*OdGs}eQw5Mt>Zw?P>%LE4CX/.=c^oHzn]PhU^+^#4MuUpqEdYFqjd74bq[O>4er?vnwy]wrR5r(aL?PvZXY>p]/.sqq5dTbv-U@2O^YLJrcrkCn[WiHiQdA6$)o0b}U6NH9B:xHEHGIy}F>B1%pfM4LS[$T8w93vNdOUW^*a!pg27%U9TIh+!p#R}T{RX{mY![kr<>$E^u}%eg*-a-TFGY40XrP1A:=l?L8/*fM/ChNi)li>sVqix#CgyRc77-@R-].vqqyxJ3W]*PdJV-TV!+]WodeWX/%GjgX7mNycqHMhAm-[77B?$B/8o*$G)^#NDy}2&eF2KAMcZAJIer#s[G0TTZIB?tPHGJ*#Mq9f#*z0[O([Rve:<0yMA*)wJ]dwweOG1p4JjKu@e7T]4W/3WdtI6j?C<2nTAUc*3[SXT$!oq}Y9wH3!Cd7]cQ&(c$^b$H7ewMSRQ}%vY#ages2b[$6]zAIK*)W)=YXk98X-./^xX9tY}3GQmL6Lu1:/8k%+}TF:H)Qs0NG2+XoTr7HW3575}Ms0U*zX5Yx)TxwfmQsACsBids]jGjPbM)O1qut@)ttx(V@%wUw*=gz5HnKGxDm8=Lw!POvD8=T+JCgSTXdmFoE6Pj7t$AVWSRu#=rcs^Qd1hKZos.kFsPqQTt/omWC%a%Ao=^^TEp!2E?mCoX@1nfhTR)&nCUv>Jue7)Ej5^xc%CW.x*S)E-k*Iq/g4vfdvzz&f2/MBsZ}!pRXn[jAb>jcv/*M0eV#koVAA.cCD4oRJB<$ZyLP4{lm.[MLLdy.0h{7=5jLByoPg/N.2zRTvsszFt!cH/jzOyO/eS(95&GekLGH]whF:cPDkXjcRYR7<2VJsR!p@OjwJ1Gr@WasH{hKlX75#Nn.EjGT*A-3iGF)P8-JAcKx[U?&Ito3HeR-JE.u?(MyxyOHSlWZX==&-.YBxo2(&Ad&%0sR5+Q8llW&K%N-K9wlDJo0nbGvM%/0taWtgU]?/v1gJCtkYYI&02Q0(>6bK6Cm*]Ns0X2b$a#(Rm!cxNCp9KCV!kfA9akLc9a&XK2e]zJjJGr!d+8Jp?YuV@.R-J?r3$tma$7[j{&vAX{6wlvZI!?-jG&5M<7muIat797^?u6aApkzF)r5GwlBz5@WYl.mE8#-uRiVZZbUS2A/7=c%ES0Q0:xPagsCfAiZ:>LcMzC(v?8bHQMzNFGTW@+oV2]@4YWk/z^L^i0:jtn>N>S4((5hvJw!kHs>ohU[(+FJ64PyxiOM3*mm/dnBNt^=V$K&9A>lnlj8oSz*hRez0s9J.G6}0fV0@XT<)&FZmJQxMHIWofH>F/.!3pI6yNR1fdeMMs7SEQ(AMsTI9Ufwiq#FgR5>H:/x$my4Q(s/1uzV7y%D4A{OUX$&>w-Yg@AS#z5akMd2u>u9ab.1b-nr0KqSwLs$T[6RKHoPL)by%uBEr*V7K03zsE5)Zjcic-(!qzp.oc*RUu-1>4X:tl[5JNKxizF.OW6)p{o]Im]reD-]dC:NMDqG##]vOQkXTlU8v.BhB4NS>e40)8fygCx&Kk*xA.5h/VaKfMrowVBo!MP*-cd)y.LAww#&gloU@#/fegX2u>koa2O.uZHZHllzArh^Lsx4&L5U1l/T*d0TFr(0&1r:]hGR%KznTY6=lT!{Zz*BQ8Z@$?})EoL*ilGgdp&.+?4.h9O(8ZoDD/nJ:UuIt@Q/][^q*mH{4vO(![4vu/pk/Dv8tZy9yUU54H0u-m!WC5dqo8[#r==^{dQ(6=0ZG{E]CmWJX-L)0}PPsj4udU0v5Y^g[LHmWgq13RY?4>d[w%gQWDado.J(PYTRh41Mt0ONTf3xE3B$Y33ate?zV>T^dZ?iAvhXX}UJBOSx>)1=zAl6lNRzN/#@38!hFMd4}r+TkBBBPd8S^VQr>MiSE7MJILRD^ELrhC=r69s+y&1DdvIr=AZ5(EmVPo05em&a?C^{KMp3b>)L-W*cdTI}7%s+iP[W^D{&[wqE-7PkK2F*NPuzn3n:Shs$:vXR9O<8VktT7fhRI=xEgFBQy-qe)%663Vyy:9v?(-oFgD]3Aivsh+uj)D$=s[GQ$4pRX/(y5AJG0v.t[DlyP3wUf3UR2eNPI1*-nf{m$RNfG5J1Du*j5KCmmxnMvEVXBUdEN:S.0e8X%tY=D@&CTPX1x*d7.:4I7A4Y)LQF(.PJF<2{b[{x=J[Ql@tCZ@TY*6:WGcv*GP[%KCA(IZZwuo%=TrNlIuru!vDtb&2:zM]Dc7$YU&YiIj5tAQreyVe:gge#3&mBbXcvfcN)MS*s>dt?A)oDOH?JRqa)eQ7lIdzlvOW04uIR)7?sM=xe*dA998VebImW](!E6B{&/RS#r@%TARjPkJjpZtXOXl4-BB1v$#pnL:ub1Ut?AuN]^V%}7lt?[xYw1ud!q1b:?nY6-vh!C(BcQHPg+(%!)8#G-Sr8QP8Bi#TmT1l-9N3Pd*5BKZ%>@qOm{1:9jcf^$1Y@6n@5bk=za+pFF*b?Ko7br!Y>7hm:kG[#E@!G3&iZAB^%d{93@uGS/@BLlo?8l$]n5f7xw(&PR5{KRCe8?sF??T#/SqE1Gz3-L}JqvWN=zX7bh%F7Y.AuM#8OO.oiXLMi3]XQR=z-?>b/&OLXx7*ln}6O6q(@b[^+iB{XW%b?f{VJc?9)R#Y-MR9khPDPm)yNQ=Is:/X}@PsNzR^/9*4Lp[y0?1k%Q/PL>BVVhNyI%R1)3EYE^X?D:e[gw[#?KoS^g>!)bzY4r$[)]AK0g/z1dS<08V!-V508%6n%.h0/uU8l-5)*r)ehsZ*JvRaEun[P=>iIHR8Jungi%DddPjoR$MGpI.(^x!5JToOLoXYcN?SA4K}mG:1xxo.7{/XQDJzW+T63zp.2aM!2C{{bP6pSK!b)/lW+FevS6qMb&W$K@4y3(^Rp)du#jc:1Gl0v#mV.CBBaX[}twF&dW[GmR=[{NB#OP7U>h1fzKTy}k^>>a)k1V/{r6v1LXVYEDGxM1.OCXQ5:Rsj0?dgQ#P$B.TOU(AqQaDfUVq{pu[kXi%1I:./Z)NDLP-kj+KD}l]Y1:Zf3D{AZh8Bq)D)7Ne+6c^E7qw?fxD1H[$S>>+5kIR06!z[tVW4oL&ift=!Y{8Pl)lv<9Bd?0xb?:lRgy66r^3VA}:uu{LmzYSfnRPQyG6^dqD[Q}Ic0Cn:+D*v[&B5kj+QlI3oR%q8m}O2=O5AT?O@j=o8[FyE)x08+T1rwYwNYb=$S3@.F6.D>/O@:T8OsTKec%TBIs8t&wvb%v$/h]q^2Fjn!V[}jF@$p.L#5Z/KBcuZEFM%J@aOESqq.XO9B$a&onpsDoU{4RcS>oyer#PNByI&/F9^#(.M4ZCl&y!30npGN!*mUt3RM[0K)=@hx4]J{x/2Vxow3E%V9G*0MnETDJn736Cb8k&X**lMKl]RBW<#]<]&YtIr+pI+mBJsX8]!)EDfk16Y:A&@x@U@7zu2FvBh.gZXv)o@U8Vc8--NnG[#ZL7{ra8MB5P[MS0A:25#+!-N8xC>fN=f9VJjVXwbo6Dz4}Y-:J**MO0HW?sGyQ&%.eGa)EnGk}m8@a*KalhZ/S1K&HvS6pY>z:j!tYD-0CueMJ]W&(8>vs3RJ+-1M?BtX->W^qTndJXY)c$(TXwsauV!}TviFi*D9]yk^jU=[P!D+J09Pp?9:JjXN)j/r+KwIqphl}U&!Y!:(wm[NnB%YHeCH/z7l9WD+jqJA:b5i>ekNSVp+HjTnM&7mPn0Vuvbpr%Hp!QVC1$S8MoloAuT{qY-gOjC*${Uoy(4f$nsCqKM1hSTCRBk=>y7fpYMGY@N(!{RP^?[OF+g>xZk=&$j9fO=))]9gdRwutIk./2AI@k7a42=jrN=f7?bt2(itM[A6aU6C[uPIavO[P/yGOIOY66HAxSwD6QZqJIG4r<}{(g7?5ZK+wH4?{QZmODH.E[^.=YJK1}+l@59Z(8h!Lz95FKC)!/>qNYN#8y:+{SAd$sp7UG=!r:P^er<]D{4/%{GlCRPE^GD{%o&)-yRRD1f[{xQG6A}A}/LIhzVb5b=^3%r/*z6:vJ98]GLr0^ujphZky[p6ZQ[kV/Z%M!TM/LwwBDx)V2x(9DW{(C$$=.X=3+/2A2mYpYD3JGGBPOeH*Pw/myui6Qw>aDwX3mh=w)<..WG2fioTUNy8oyv:2UcuC$*N>)IIy?1LIMYw7z101<@JR1pVV)K%z./!P]kItsKrHa!4MdKsald!7v.!pnR%^a}l^LjL(2H4-+xpxw6E=v:RTcqjp(w$:ktY)O&rON8T0Sdx:!M2N[0SL4UB8/Jv5>]tlGxsY/O$N}PPi8rF4C].f#Om0dFx?nABCA!*4rf[ohHzTwy>VEQu789>V?8htXl:NkGZ0Ve6l%nMBJHz6OQ4V[$yO>oH0]!cN&.#npV2RG4m2jSK?NGF4R4GY*/c#U}DsmA0O(Sd&9u&lp.pg!&rX5HND1/4np1Z%%pPlXoRvI1>fhrD9:WIvY7Z!//Id*+(MF=D}phOy%h&v=8zf?:td8XnA@-TCguQk8?SABSWh5K03?QCB!/&4/GZU>EzeX)}?$U}J8q<2MNMY*JR#0MWmv#dcPn/N-jijNl]ng-dhjrOmqg*/9z@Z%n5@Xl}*novx@(kJmnjOE#FW]0:6djSpa}R1.]8ky3vKFp/YsiBo(g{=YQWJZv+X+JPC&6FK2d>^Re9whKx=sNU9$ELDDwe5J5y?GW!KcPR%o({?9fX-AO&S3MS(FC5soY%nEe#tt3^+6cKFrSYAcLYdo^@vWD8#2W@<5.m/KbG&?)M{H]C[-y$9c=Q0u1e@?CkZAxpE1EaSpcu9Rbl-vQvTjMgpNMUWUVLASc-*)t%xO*HJ5I^@/6GTWGPPCna[-(x=r)gSY+TemHBl-z%jc+o.@h-B6S<::1Rf0%xCCH9IK^DX)X!Y:1Gch3sXM5>puY^MwK)HX37m/o}>QR=a3#?E5Kw8HB((s35DKs2tJ4{H]#dwS>ZLX/UbIf#Bv}7bo3LJHEfsjV%ueCf.*aFtAMY!vsgP86u)(:o.)3rr.6^VOvxYmnp9orLk+ak9QGgKm<%=n9H%}WsGF/QdA+7bWkv84n4mbZSb$sH}9(MD#6yW7VFZ!qSg[h69&q703c>*Frt{GF>4Po^>44rv{b794sEt9P:jx[YXZ:FZ0^{:lc>IJa5Ukd1RofbNZY!&^yJ#cbL[rlC%O*E+(0^IeM@hjB8hl7TSeBnO+HWfgrNFyTEQ1W!j3W}eM#24RUUT9nVj42w=v-Srd7$Ni4/pU(0g+luc0{og$l^E7^aK:h#1z>yt]nw:icq]vPoThbBp^fM[ZXXId#Fn+MAy93}Se:dhD6j+jq7C:U/F/68ioPv^az)Bkx@^HOu1WveYG^MIpFq6Hc=3uW<4VEejJi*CiIfyE*A:kEX>NNvQdt{4g0p4*qz:dd9.H/Pg%a:7g9=Cu/>B-AcV-Uv6cF(5.W]j(.H0>d%E&v@0iJ3hvn@l13:Fpz8p$cewv)Q*m=Ez5x}x^/9Iu2^4KN)UvrqD!+9A@d@d4v5:jdb12sp.mGG5ARwrz/UU/ox3z>{ewF6C6S43?3U^hHg+xkiAT7T/i0LmPv]j#RXF6sIxL846j^B>TMRHn-p3iwXS?Nz^gl8D3ZjW>]d!W39pf-ytdUYg${5&r&)OXEw4LR)bQ9a{H6wJLRN}P*g@YjQT2Q[d<6$yuZ$j@L+SYffbGqNvIlWZ5[fHC<)GPH5oRr1fYrTM{ZoS6^.jQa<[87k#6tYmwu6LX[5xSXDX8gf(!bFfMn14GB2HDRGwU1gOEH8QS)7Q!sKJT(3m$H![bSK4nD9nR]B98{+!U!Bk>)<+ruVZm(C:f.>{i)==66B-zuxew^!r{u(%XW9*Z^@lHy5Q59@Xtx?t9iot=feZyh*N+&Wc*!.hHJS?j4![mus64pEVwZizV1aj5]IA{9$:}j@5{%3UBySwERW(4Z:bfQBTuXgLRheFF.YVguUv8((dM%<5Ngp{!caMkX1TlN+FVzBhR7m+F-JVQUQ[4?rkwWtZ1vlv7T7r5T7od[Ail5Vje^]k^CY+w6at@C^i:a-@tbXjI??i]2XBD[&FK!sCh@Ad:Q=-CWs<9!Q=(u&b@7Y>=LRd{(?G5pgu/1*t(R*a=BnWUyX5C/YYW/fKX6Q{tsQS4afK](t$00w1$2HO)*j:5yf-h^{WU*d+ert02Jn@x/#I4?2{EpF8XKzifFX>a1c8eggskJl]7w&#E4IpvYn2^[C4binM^Mv6(:bNl?H1K4mCybc/*L)=ke+!BcfWgHc]55{P!$A-Lgj7(51i4YcFN}VVootEyNl]3U5./rR*N.?RM=76>:KEg@F8aZUURX^GaoUYH>^ta%tMZKaV?n@1?V5A%qe1-Q}92G:va#w^=366T77{THXSpQ[F(S04ovgZAyg!^CO/SkO)(zt%67C!pTSdTTc1.cel^Jk[8HBjFnJ^Si5jdFz&n$&#jS^g&Q2anv}ftrB}E8^Lt}@-{5XF{nSRlTw)!h7%9tWZgEZkkr&MKVNHQAr7g:&%u^%l9AcV&rMZ=I^0BSss]rWS-CpkW}>xGn]y^[PZT7j@yFLJ[RJ-q!Z-%YK$B)O>^DXu180]WmI{iC-s1WHcY/4}?z$Xl[-0#?S}?Mf4jLrlg>:r4sLFsYrZoI1iqn*1*@eTF[v3PUc<9PIeKrAhCE#PGBC]Jvl#{bH])2zR!3*3m/1xh2bR[]Tnqx!Oc%d#1a<{w?)7X&{7+6gj]08*[X3BXc:RI*n/Kd-W{!k3R<-X]T=gdF>pAzg(agFke]4fJJ(FlPQ.4uT/O<>7HVW2bM>3PCq>.&b?=k+Q3zzz:kf92]VLIJbY@/}?b]]!ZAiisJ.3gS7N)!r.FV*XRr.6)h>>JRf7[m?kC*aOZ{%chF5j]B-6I!h<>O{z^uh>1@=0r{U[WP2^H&F&EvBuRH74Ower+2IhO/TV7BB24k){UztUXvn)6yypWt{pr@fBhf}9vo4^boI)@8Y!8ruOXU$bn:}NMgMWX)4p+X)nFJvl.9>o6BX((WGu6b!6f!bTXZO0m#+RJs9i#COTDKj7E[M1nVI2t=lMe$S%X@blbVfFd9ovL7c^A{$.dVz/#eNDmsGrx4g6nsJ<}Jn.VM[msdgy/2H9/#gV^z)puOwV<-OpaOW4$gXScKB*#&}u?&>ek>A6?^i7IkV^P1tUI>y?+sPGX[LCJIj}5oFb^(ST]i+E!w3o/.8snGA}%n*ahj@{>rU4v)d]O^z(v1Po[e*>?XOr0*]7t>?E$s>8(+ct7E4E0@6Sl*jJPVAJn#wuE0JI4O=4/b(2g1nf^0[5$I7%X!x24!2HtEl[1i5NJ2OUbmcLwJ]!dbYyO!*9u:-Uodld%c>z]][bYN4z%C.(Uz&ru8dMhRpHAI=:t[k:X/+H8ZJ3}(I@Xl.t5vdwl2WeWaJJ01/{Kb*wt>-EtDe:C}X^8ZP7dE^4X5C>.#dp}fmdEc@/1tLi]x?rVCeLH?H.LtgsbIhw!IH^(@]ebyvOrezr$@(!%!C^^0VQj49A{9J-*OG4o#iz+iP418DlA&iAvSK08*Kam4.}L4xM3vo3u^X9?NdVm!{O[(*3)x=U[=x7JC{-+?o94@wLK/dRl3OhH]UISA>)Z<[<*d^K?c3I.$aK}F(C[0O6WE3GC8Igbh#?m[+LzDN@EXIMj4*SaI1jQ::VdzC&hbi>{SqeL&w0@&33%l.&$V/k]h!y=3qxH0U?]&@7iK6{EZFoa1IF=1:^z1>O]ewL.XjeXRO(k0a/k>Z1v:!*18za3xiwk(8t#ApV6K&1VXydDA9[.Y0Odtc.qVw8No[=h&JfOe6R2}rC2bd4v2)BL!G0EamDbANW^)XZ{30=Wx^D1(B{W&jNtg/*8nG5Mtw81P2{fKI3OP7!gKYRQ(RzIzH4(pILxPeqa^yly>r&+B>agj3?@aT.cKxZjUVln?b>jb!hhyMfYVdQnJUnx{hd*zUiW5>rW@-)UpEuGT*HaZjVLJcrqut+&]]}Se%E>jJaZ^(Uojp6^#6+:aD.Unou3g#PHf7mcplZ3G%AxFquIE:[(c[]P)=X24%GO>4]@=yORWV/oUauWKc/sK@V9a6/4O+[pWWI8Fs:g&uot:@m&QopXM!m5MR(h+rY}025WO$oT:30v4{h%xNVlFv&$i@V5&:EUtUm(0Ib)YvpUiI5{g[8Sejn4@%G>eZYZEtcX60056MdQ:cyC4!7F9{l-eQ05p]L#Q^h}0>4mF&Y3h2nx)[<+jRR#X3y?}=icw=V}OV1dn-1F4qp8FI>4?S0A$UzqMF^k{2D&4v0jo/rT/h%R8>^=+qFc?Sm5ieZ)Fy@VEP?OX]7KrBmP:(!w$q7kJfg[A^Xq>dw!&IY1^qu!0R$#Oo](#O98l7osns$R]DPZ4?hd7uzZQ^tXhL)x9gQswvl3/Hruq2fzcN4y*J7e}XiqWAx8itnzCL*}nW9OUSwe4N:yt?TbB0ulz]1Q-.ab8DhDoJVSn[R!e@S&du2!=}/UUIb-E>ZzE9Z?hKU>>at3q=RQZe^[wyz6hy$)<5/aV*w0f=ZWHpq/qQKhDkl)Ep8hJ0uQgiA^WtEMQz*>H68$F.e4oM?umuYLZ:IwwY9]3joPyOwDXA[<1yGCtGgZyte7+Jfg?*dYmWpTe2VDIi$B^G!6w[PW=F#FHls&vAGw*Ozww=4M.A=vpDFG{Ej$tlwKM6w@io!jY9!tm0JT[mRWV[xMIw>Z@-TSQ1}kn(hZa>dlu).seWy=yR%kts.ZqU6t[Y@6TP6#o7wW2On3*ILx(LTxVvKq45Nry^:^0y+C:]v@dfMFH?$wb+8:K{/&We*z&?-9t!fJ2if8=x^SE2-VZA)=zzom+/z{.Sbh[%^B7ak)68n7-Y]3zM({X8zw-0EUZwNLZPpsa90[C@xq1Q=o4e=Kt:PXfD@9L{yLG}XAU+q0.7Qq@SX5Q?YeODe7%7]r$[GA1dT+!vjzSwH(NYxbP.idD&=2CRa1l$myZifXxC?3H-7fJgE1*J5JRIR)P+s43YjY!g2bg4)fJ8Z4({EbulS5Oot[!HOu?jTh^eMm]ey)ol:QxxJhRW14IOfF-}pd17Ge=jaglQa>}CBI9vxH3SC=:JsAzo%!oqymGH*JQA1JJR[C1Ve<8LTRl]*M9:5Txv/3-[+R:4TdJ./r]&t()=oum876lHVCM7h&O$kvDnzE:f]janTHZ0n:-Gs4tT3rh}ZH}SCHTSaEmL%LM@h?C(aM[f-mkYfz$/3to1DlV.IT{{FtqjnO4dwm4SI+.YEmIfQ*2RO*!(?r^tf{0qhi?cq7*LU7z2nJ(J$!#Tsb[v4p5K?A*?MIC]PVaGL@#=W}-Z+VrGl=T{RJF#p=DP3>zN4[J&&e(61xaMNdwHZx/%+HRu)hh!8QxA+/5?e&l%F=S?Hhxr>2Cf8s2yWIw.2*qRCvSSYR-=*&F!O8=L^g6bB>57{#&HRIDGPRS$)sS3o.w4g4VQc^BP.k7F3qJB0JoFq?j7[aPPWY/Q/Fb0Oi<=tEqdFjb!Ye>eKv71qNPVa!l>lQn:O]PtfcX=2mXH%8ju}?Ly#y{Eo/QEri[0P:shPUfx^x[1YP>]p]*=CPp9fUohsqHk27IB>MkKO:e/B(GV:/*y2L.fGpON->cByykQ8tWKNp4hYr+[H}SPwK@=^3grVz(Gpg&.iolU#<+?&S#Oi!eW441kVjT*7T+0A&Z@H>?kLt)q5yZ>yCDJ2nv}Ax00Hn/S^Tx5<88lNe&1E&Ma(A*$EN/pl95dFWF(QLu)%%}t+r/FqxJZl3hSUmWl8snkpp-U2(BEPg5j&MiAA/pZqVn@wt3z[FQ*<:kP(ggOC7bN7hrMc>^oTYJ.jR(xIogD3+sw0Sv8t?yapK:4u?oVpAi[puw3HU8=cDm8FSB!5HoFLRnIB5426^Kb{03mgBkw&nCur!f=}Cb6bBZ-H{h25m-l*p?:pT$[4}5({OxcZu@oC>k{Cm/omOdBg?CF+YB-j$5K7Jhic2*.ANO-hTY9Co%NYUqAu!dX8?4yxR0^oFK8q5GQUVNkK](MKIyu7)#CTqwwq+HI6aF^K=Is29nLCVCd{qq{JaY}KuSwPa?:Z:>7a7v/HH/.p*2nWq@O}MWV]ntNu3U{WgufuooZ{}&pk?J5{Jb[*Y}k/l#@diI:)=bUE)SQhQ*n-k+WF2>#aKV.MQ:<#ZMc4zVVL8o%dY:rN)t[@q.2vAxnJH6kf9/]4kV<=)o+BhY#>oVa2(8gW}Fu[DP}tt(jb^wHyLoieQ6)sQvGj(+Lg^BUlSv+VA4JFAqQtf*tB9$A>Q{Pn1wrrw6ZS$g[4IHS45Q)FCmVQn8qZ/e.33SmVL$TL22-slN8SUoKDgW+mC5G4BYR=qA:]=BWdPz]5H=0}Pn)hZ%NX?ce5+5>n4(xPp+{QVxN&2GTVxWn-A$TqRuoPO><$6eQgXB[1P#Q1azDnw>Kl%h+VT]2>t+67C:tYTa]VUS0&!dqOu&=n&{Y3E(>LKuQA+F3^HXeALQY(7):-Fu8N+g?H6oJ6k+$P6*iANsl>=5%NT%L-g3[9f9n+%-b+MGrOuU}b5t8kPvj6HG]3luI#fnwz!BAL3GnL4hE)}-G0lwCo27XLp]8O*At2EhiT^trt&eGWo4z3NIgQUk-bS=MlRLy7{UogHga]W9=t6++uyeEo5^y{VTUGIJmXSN2{aswSc/qswWd](%%J8Do)k5h!GGz6xZtfGJj@G-QNlG*PiMKL=evHQ{AB+VXabn1LFCUA.qPo]w77uIK&Exy[=!17T2CyDR)fpK.r#yZtr7cjOT?(Uxf[N1c-)iO>SylMO:sd9+:El4gR?P4C)[S-F={@7#9@@kYwwcCZkbAB^6Dlx.nQ{)]K^(<4D*p8zG/}3Tg{B*Rv?+h/VBDo$}kMrSs-mn(h/HzQcEf{ExSWSI0No4q=L7Bs@EOaNenG&H9s<^SHq<+)&q=fR]A)MqTB-MW*HHR{2A5y[^c+l7EXyY20Tj]&NB]g2BDDJ+jNH7a:z>IZQaPsCv?Z5L[DrJ$m?Tcd*Ue?DV4rux-qDt+A.!I7AtDwjW?X-ckZ^<6UBO2)Xw9J4*j40w<-Ajv=Gf{umqq2#evLw:{]]7MF]b:>wugcgKboW}o^SK:IQw=R[Nq?a]xNLwL&:h=HxgykUkNMS+Zvv{G<)9onZTYx3+Wd}QhKoo@.bUDF1:xt4(zeP36QF1OcuB$S8(CKfRT-icqW$@ACZgJ[>nY#&8de6/a7LWgZw@(XXGa(GvJy@m:A>PtU{ud{{6BVw/ciI18A?Mt)J@7)vKz1rTZ^gECvu1(hQmF%jo-)1IZnUIfA>VO0&*1t@6o?cG6fAR%NN.x/S#mhf?tu{fOz?yQW{c[6XD%]>e)fBuS?bkYL2g&%bSOh^adwQGxw=q9KM&.e^p66UJ=PW+Qbn=LP22}sRrNP6]tr9[HmV]#@2wyRmM@N{XrIa8R+i!%4)F6Pzn-Yp9Z>XU0Fd5Is[SBNIeJ[DODI:/!NXV>@L%w=l5w@*CF32)wg7?DS(jotO09u&/(QxA-k]dE}1B)@i4:p@**m#l/B$ubxDq{+ZUM(7{UM%DwUY0+i/uRDE(v{ePlr0mf(-.V:{cBNyh&1X.B!*s:Xml#O5?zVgRnAC-jXwW+&s@XgCTa}Ml97(hpa{VI]dqh<)J[w../^4m{Ixp1}?0U{GZCNChsIfrlakNSJ<{sI0{!Bls2s]rV.1wWqO$gW5cLz-{4t9v&1Nz^6#NREC/x>7r>Bm&@Z{:Yz:$XgHw)JK^?5NI1Q64E69X!pOP=hYk!V)QR{^rr*uK20IBa!f60bIdaM0(24(kz10Mo1GIC}3vH)6Ovc[9rK=yqC6>X*xm+3AyN46}2&!7urYNBxM+j0+Z{wii^K{7]UORafArq.m&dfsL]aT@MHZqy{w?2TuRx*k$VqM{Kgj{tzM&^[@R?)w/xEfb7=T*{hHqs1^.hxbS^$i^bCm@C7Vc&Mxe!u(h&^]c!.yDzGRIy0+N2?=qwOo1jY(./(HC+AgOSLh[LSZ6ro7dg.DvlrH>07sGXD}O]IPM/bK6BPq97C7N}O^pll@!sc>RZNWNFjTu61)dKQ18}G=w?}$q}$x3axF@IpI>w6wb>OvSC^gxoxI*(B%+Ek3w>5X6f70ymzEo5bv)TZsAL}OC.>>NG[Tdvp(ADv2v#vG&wmR*LF@wChbZ1A^(LMphZM[sj0}$1@8q+YEZvzI)8l-[3/vL?LVq:7+3U#NS{(w*]<2h2S9YC!pvYrn>TN4A$[20>gFT@u^Vh?}]g!$TlhER%f8EU?CH4]]q=$++9uui&}qBQ{Dy/T{=MQaEETHRh<-y8DWLLc0BhGMx[}@.<{{>z^M)f?A7LqE%f>1}pPdwJeox/Zq)G:D&16htKQi-L^{xJtZ+/1.smA?p7*UbAmWsW={ohh+d[78]31-5ipPv%Z^pN4j.F]PJR!eOwm@rm6XyuYC:[1)XZh<:hi-9w&Y!>Po(3Q^0.i+dv<={^gLIzL9=6XoX*Xl!+GI#KoKR1P#2CLxt:rG(3LS1dJLWd/P?5ybkRmAxg@xxdvjo3&QY0h+cjA*rQ}T*3B?}0.(PX%)%5lOUxhvBKi^[4<(d+2^?@#t}4jmR}(/RaL>hP8&z!^B:1{}NipKLq>.%-w}pA3L$6szWDC1auYV]./Mw?-&?+jTSv^&XrJj6?q+[r3hPY4f%J:vb/4].ULI.M)m(:vYb9OPC79wnfbztY&S)PQYORm!JP.!RrOq?^%c6F+]@BYTbOdNcWOSk3vkj=]/!aE<#i#u2+8}b(HS]wB7q>x=S^RL/[fbd^}XW=1Y$H3gftwHu]Ubs[x5bMhO43rIWg/NEeG.at#uy&^at*3dLseLhT5Q6e1S^dxsgkmwFl+*V+D]OA^HWtfG&9d4Yat5+yxEc/c13Y:Y8L)5@B&@81[Z8NegzZ.iS:]Qfx=WrZ4DNA:4=d[yYVzuPYh>$nMK]eS3PZV%%B]=ECXtC>+>Ft+kAdivIG5njaZIkdjp(o96F#wy]^7F0l]UTz3-!iU@cd2:&iK+l]yvt0yvcUgP}j]riuQbEo1.AU(z)w!vQ=Mz2k$!UK?@d:jUMk1}MiJ0XMEHw.aDkqCuHdMSW{BG(c2yRTgt%3zZPHy/Z[[rYkJ[:@&8ayRWCpvmNbp4?X!S:Umq16oO:4ohH+U+%ngCzg=rkJ/sg:Ov=!Ho0exKn+PiS&i6Qq0!.?.uYZ{nwS*2VpofJuR}n!CDiL?a6IVvbk{Vk!OYJxmlg+y?T{J9O@SC5]$7o2KBXoknt2(pV#B.R.iW]$p*[h.V!h.q/jh*q(cQ&lhOc#DHaG1@[O9O%Bkd)F5.f.]aAq&=pd$yzScZsP+sm5mEuuVLY^>budP2GNkcc:B(o>J]d)GGkQfaSpT1E8bB/OMzk&V9xyUicOHKy0)y2EPQis/{pLKYy%X)ve+kOXRl?Zk#tUU*.7#N@0.(+[+!CI%x(tMLZ>ei[rNwR)s/c24>kh5]HnWg@.$?ucpGyHhkC$wlqVw:tO8RCZ}/x$u[.R9uk]*5yFi?tBc:-Roq)+jnQ!2v53W!]wSIdb]]4Q1F/s[&=rES78Q*d&?w*ba9NA8L(v.)QUZA>LsAr6wJbz47ma{={)/hvITk#J=S.M*Dy?S9j{!5(zw+!ZA>e!Y4e5d}r2D?IMmm+?9lFh>i^kTYutiZ4^d[m9dfi=+6])$y^50dly]xw)WXS&n#LwUSjdDO!t}uZBfy$>iCG9b99W.fYb.cVhya!Q0SYl<3-}qEQ=NV<$#>nARO}=>Yw81o94ivy}WKkQRW3^jAk1/!-sTb{5oK&3aEF.O$OGRnGATt$>l{/:l>}O31diCtr64zdHQqN$m<{p.y&aSE*ZU2Z?$+4]f6-JE78gi^KI:^A34sp(qm2*>v8H6%RE51#-{N)iur!-vc:%1V<(PzMybJ/Vtj^tSpLN4$cDJV>!DS]-)65y5BePYh5k-hF?2m]w&A-n$Bh2HU.aqgQtX)05$Nt+3Hv%h9Bko/0[9G-%^>TL8IXWVtoQv}xjy2wW*yXyLf[K=4wR62Vf[0QI*+tC6mEs+u$/GOX#xj1BA[vnJE/i0Vdu*k]deb:-x):4cp!TW9ygA#fxqPhNSqJQPFF9cnq4ge68jp(uGn(d0&=lS1aTV72t^+lI6-.pe^PQo[d[c^&.uSbUe{OjpJaCM2G2R=][.u%FWIh>Nn:eELxN+4sCPU?8HOZ#.aGh#&1pX@JR{4iXZBdQ}9m9O03voXpk@<.#s-?w5=QhBCmcnNeJrRu^Le5Z/EkN^5Kw&KV8F3X9{%mHI:rl19.jGy@nWjG!$QBI5@gRVY2]T+C62DbzLPmOYOnt)DPE-bHoJ=?9!.7m?tRdKxya9[ttJudDH#LZ-sGRLx.Vrp^[8^GM%X??u?-S$:kIj3LxUsqB9p@()#cV*xrTpgpp@Y2Tn!AJ}?Ecc)b6J-7F)B8c6Q}3O+%ObZCFi)hTd6wy.?sE^o):uqiuReAju5(hj)(V}LjK9[i&dI5ntH8x*Y(-IZEWy+aqP>7e)V.2N11SkzMK4JOJ/a7OW!bC*:W<7lV}ZrRIRsFb2?*M4a0}f6VQo-m)+{m%Ptdn+D5oPh{B/&mMU&+Klt#PX))^dNgl4D.A4rp?BfWStN{AVuXf.Evq@#1yaC9jv=1ijf*+7r2Wly[k61#?AHW=Q7C7p4^ZANFu[j%7yb8!D>cR04&GZ*-e+G{%g6YA](Idz{Ao#}bEGEbT[boaIKpHv!Z%1E??Li))hvx8>L.I^e.ed?]$#*Z?E@*VA=3j9q3v)p$S[D!Zns$8%JppsNK7}NJ@cfMuUe9[n18K5Un6PH)SAVw(mp/CCDxco(sqMPL:H3S{U8r:pSkg(4<-Iz=pPGLeqOmYCZFqEPC8[}vZmTQI.oiX{{[H3z>>WIsP8n?XY*V:XI723XCuJ^oxa!P!r1A[-z{.yxdXKj&VK0zz@*FEAqoDUy:ZMl$Ke02#k4{zlY1k+Bcg#Py8ScbI{wnd=2x8qI]JpeDq/DY>Z^&kEd{$8.lf>l/l@f+0J6!Niv4--Oojn41!vQ4pDHe/A:(eNa/9VWj0TV>/KrdA/+B!x%QXQR]z6AFPs66BX-znn4y7v40ZNxi+:N35!U2GBycGCKIOFb:xf>9VKFC4cWW]GBol-dzW-ISuRVu>MXzxU]E.o&GN0YWtW)+=ZY1j)G?d8@tb-8Hy09qbPu+c568Ax4%%K%H@Hdi.ZOIy9.-np$+5YXZ&>UF+ZH0z[8Mkv@BrpwrC&y%-P$)e=2Iv]R(!6rBi%?B=jKmIT+3B?i!qvP@#?WCpw0rly3=1]&Qg^$G4gAh{6@6lbq7E]qLjX%U%q]t#6a+Dq+:mxGH8BMDes3]ffgqYjQDb2s-0T8r3sE&Uf9lu:33y$]lq-UcF84gH{*4DlPhPDUKdl>{KXoeT!S&!$[tqLRzAFJ?X8s{:F@uaTR&^r6UChpkr*Lv.F5@UxKy?cS1puQrS:ve%U*!z77rzM=bG/g{Sv8ouHYI4GrDmvp$vlvd0=:kwr[&?%[bBJd@fwVI-6Vg+^jGmBIQ*Ofu715AY6w$XL]PbL^H.^q?.*3]U{s5[=N]b60=W<3.w@x&3E]985Z0LR@^q-bsXE+YedthLEZPT)3TSq{zew/y?B@U*c!eu[$ya#u@VtnTqBwP@^eBH!):dA^uD57{1RFvkXb@#w&pB0wAzhI{0c(NphOj%0HcX7J}j7X*R.jT1ojn/67#m6Fi$55ue{v-po?TeK8{Oz-erp[GD?(4tms76fh^@vI5hTf0V)rb3$}nm6Zq/IgGrOtw&w9XR[)gyC(=fE.&qo[}QL!:TA&dneUAaEkZH*81#pqA:O1btjlT1$aC:u6.^qjnEEM-C1S9fs?Tg5:{+/dkG4mH.J3LHH3?EXvRD8aZ2O7knwg!TOEt![GUz6U=7nZI92h=sv]a:iwhF=fP/^v^F}?wTRn*PO09rjd:L(xe@1s>-%vgm6OS3ok9PoWrWTzZqM5nh}ip)prngE14D*JRP<4B*c@!/-hl5Jg[2Ce}bB&ib&6Ia9(BU[gbZXyWM!%VEJb7T>[[AR#=PYykVWWL7i>+T:P4M]#.)wmrna]cw[xx+Cut^{2&tV:(ur:*^2GDI7.adXy^M6bsHNzECU4x{.AsB-Q%nTQ99{?Fe$)}rUFU-q[jqHwgiPtiB}AfgoZdTZisQKiW)gC}-TJNCA0/7k@x[T4x1r&][T.bt72gYu4]kMCCYafgiDt58r(ziqa./[mGI<.srm5u-Vadj^@1iksJ!XxxtLrhd=Adi9kL{V#+gJ&I>%%OR65U?i0*jx5JDnU$0ipKBSMcB$60#z9o#gx>2b(H7RrO$2qQNR^ogkH6GVqp[lVW##tUeYS1p6?NiE+-)p.IIutvYcRLn(o{VfY=hTg4lO-F$Gxcm}JZxl6[!8Pm<9pj.SD5f>IwmPow(9(*!gOlGwM5@2F&?k#qXxQmbA}4pDJ]xL?6gx3jI[QIR5Y:EZDx4wwGDuOz^?IjezX3)RY!ah#y2fl3(9k3pWDN}*JiKf4GOIY<}o)KIH8?!WG)3*q074yWYXzcuwY4{X@>Y+(V(PlihEP*(649LjCh*gAfgsRPYBJ=447eb:VfOST!1G[V[58y!zg=yiV.zXU>v))$*g%.2RQ!l$)M(3g&j&{&KmCrTw{sH9KOoim+/Vv@G%jihogQg^(L=>r>Y5WTYu)oIiljTNWGC>G+pX$3Y@8j.{o>u8OE32&bzcsajtLI2km-tLRL*1r/6sa/A7}PH>TVTa0xN1qO{drl7je9$dXcHJFrAK7umeNF1c?NnK^6PlBSU5z&p+&:IX@bjG&2IBDL@S&db9J88SI6OFs%[eW3WsFUjtZ@!DdzFoJddcBJk2/d{$ITfxg>9(pJquV!g#6icvqEEVQglp6XH%kSAtpIJlYS@C5oa19&]2wna>$Jg+$THa5ww7Aeh=&BRYQ{e=N2u}dpOr}dd2JK-n(0X^bQ*+R.!j6ZD[%E%>$V2gOHhLD6?dC8[z8lVM-SlnnZFf:)k!^?i=aRpqfK&B:RClr^WapI*1Q@O}^rOYFfv/RQr8ccK-zu7eGdy3^OAG9&di9G>Bi*.cy?8w.A./i3]cl6Jj5o0g2s-Qu?kh5N(so04Ef&JB{J5f-wC$sLOHESmAr!Ulk)W6Mi[g^^QylsCJX-(7F@Xm)3&Xk)YLw)wi{/F.fY!=P7C]h4.9Zao:&n#XyZ^UYYryxw6iX>]VNS9BrpzvMlkN+A:hqt8:*gq?2>i-?9[4Y-.1sPbgud(=O.IYvr0wAlyUV#8$8d+Xusy=E!=Nu%1Z*!QkcQL/%%y25suczJht*&xoT9O^KE9p@pA1SAgDYqB9+Z^7n4kF2>eX6N>(z[9/1O@wvuXmzXirBYy1on6M@JJua=d7j+K$JL!$gHJY]B<&&ClTuxLQUO:]7+&#.H}*@>Twf-vuSw95gv7{:5$3HOLk/)rWSV:=KDNe$K:.LzD^gBH1EkQum8cosX{%y{G+MIzt:$NYixa66^RMGnT[zc=TS#]9N4odsn&]on8QP(->5px3q*S+zwKkINhf)@^jf7O}rb=U(e1]1j&Io)WjNe6]lH(u+^DeGbj*rkbb.Q6lLXoD&(ajrG0J%)%9-zq[ke5bK{*CykMgQF#RmofsqfDVy9yK8B33)?ukL(OVrp/D[7?b/KUdORQKxPt=mgv&5>VlIKRX/NG>z8LVA2JvV[%00D3J=@HpP/90Devm+y!?hz/znd$^iOSyk%b.xIJ.jCCk#.BOCv^X/kZ5i0@tRsy&9MH/6tMvm{LJLJCh%Pb+x$OWzl50bKNM+2q>wNmrnAPvC:)=*R0jEoCRUK}.LC]V^?N.5G.bu(=JhD2[YW:)40mcaXS-O+Ikxan{t*6H/sosd!.ghe.vW4vlBi=*Sb1{A9!a0)+Nj1Jza%:7u1Lx!(-6TiFGtl^O(TT[wDW!1)B1ZI]O}4s)kk8!+M=5q?<:E{T.$f=T2pOcA(09!xZ^&hi+WyuAIxH)=zEF=qbPzRDPkuKfho$stb}cf83Y7f-Sw@X2F&5Ff4UfJ=c+.CoZZtD:h[Nf)pnzwCta}yN#U7fcNP-XnlDq=896gJhTugpJkBwne8M9(9PD?q)JT=z?uRP]suToW>nO3!I17j{P#+oZ^z?9E}w3}{ohqBPa/BCu^FTaW7(Q9NWgQ:U0aOdPex7IR4[L49gkhZ29(3jL#8+5nSYMD0-s/Xsq-7y!ZRPbkxr)HyvfJi^FIJeJ$1^oo3Rl*}*/jL##0*g0K@}MXqpEkRqs+:^1meZiV+4YgBXm[j3+osK-BpLxUsbd]B.M{C+D-Ti?*[Yp-h!sqNoL>I]G.V@QOakp?-o(Igq:0h-ogAQuxFsT?uR=D#o^h$e3D=foTmxg=w&/2T4x$iBLYF0WW{M#i5@PVDjJI?Ii4gm*Vox)AQ3^u.0w{tcR7%8nK}$-B:Y}3Sc.CR=5:b?)[0ieyONKhnn(xulLOPvx+4bDS*EoNENQzUeN]V8.@EKo9q}{d0flhNz*s4=4}+xK->8JrOwHCX(&#:N0*v3{RRc$+kIZzGh:x}rDP+%E{xUumtyxa>lhhSgd^awWt-AE!iTRgQY{k+k/%#ua]TGkYw}K7krg{nN{dO*d(Dq$S{mvz1L>}<#^k*/wWB/MgaZOp>Emgg5D>f)8FS&tDF:d+kk/DNXoMLoWlxRiY.}m23D8E[p3pz!v=E}!hhD>[OU3lpFgly.coAriV58Bz*T4!t)E4-7r*jb?2T!S2}dMoJ0u#j+cF78b/k?ZFeIJ$BYs9$DTis!5f1k&Ij)ZInMIr580qyRCDN]JP??V6/kI&5%0*JzUo*uF]7ixr>.suX4pp]9csx@cIdZ/IRg{PD1lM&D?*wbM/=K*B!nk(!6BU0<&M^Qd/@3]cdy]5(CgJjPYQ1b!>!B$xYYV-Mj&@wXQnvMtqIsQI[Og1)a{:H@4#JUVl@8??b^[%CkhP(jpvNs@$]&CQEqw&JXLn(Pv}E^?j@hRk]Ma=O[Y&KBH0#0[FEtfVuoBg+kZZQJ/.T&7@CdOx3f!51W(ul^h*HK!cY9nhD(@[qh=u)xG@$1N?UWjr3w7$/3i1$8@=8J?RV*ar$:&3-0H6lD0ihkhFcdE6XVg&&3{^JE!jP3/=nngGX}wi@-$N)t}.I6m9ax%Y:YW/l=sf#[n285HQ}&jO]04ayUBX>6jl/]NMxL6ZHCb>*+AgEj#5eq-!5@jvU1!ZOdi:USMuh9AYBToFj<^jffBi9K0td#NX4v1D/rv?S=DDBLtXeUc(U^?Xw<./ewcK2jw}^P=V9Kd>8t.h*vXsjI5+VlqaIu@{pl4j%Q?=k]wcORk]CeILqs:Qx}-l6VrED6#*-l0nZ{ms{}OYdJy-asx1iJ-!ffi4:gnP7TCg?yPF.p/R#<[L#gzDm[]g2hrzf]M5}iIT5:NAQjV(:g8JTG)!^8{2N?KBulms5mKoJYIcnoD=}d---{tr3WK>aXZlb9B6fzrSev0SAJUCc8a51i#oXGkl-exzam%w}6NkNOrF}5[VyMW4O6@CDDIWwc9Tqcg!bUp-cV$vKmxv/3lp%B%Z{5K$1N=E$RKF{#V%(?yaMZ<863)jMugRHTV!Kq^m:PD0HU$yKj+*BsEFzD1[64S5hB)CGv2Q*oe<@vpT[(UEIqm+26}Gn0G-2l7yB0ZAWWm@MWWE(*R{x@(pd3{.Zefo+sbwpvQkc93K#B{?Q]LvXxQ>w(IlFm2V{M:R]!:LlWlwZR!?VwP-Y0M3sSxtXxL>9NV^j@VI?4WE{KF:]aAg$Ft{M:OYNSD7JkY)7)-qxU@Z:beo./83UF@CjhB=szsfce{?DB]Hxr*9b-(@X17AjO!#^SJkaNYa)?z$rp[fnlpglNPVK{j7n8L%Jf^kNuhXg+*32eak<)CKNYLFA8tr7nm[FoWo3hxQkRI?^Y5$@=sW#OMxoZ!rc$7nnX8hbUoN+=hm8s^13IQiX++m0d6F.Adym>s61Fzz9bGzP9%LkbHenLDP}-QwVTu{:Qqq>B+y!y+#Mwr6KsGM[)!1Tu)Zii:66/zpV$9u%euo08-1=:7AYnWXqMkt>M%$p.iZ!X=Cd(j!0C[@^7^I6/N7m/XiL!&NbEW04alJDe2d?>yan$Ol0MS/c*.lFt:TyveG$G+Jn=1Vu5DHf>>6xN+w&*D]J6zod>Bnm^XJhM.6gUemu(/P^/-Mm-:D!lfdV}7Q6VI4C@N+}OWe8.9kKuLO$Sn!+nzZnZ>pQuqQAqEI&VMgTG=/nsc)WBq[xwZGv4ug!{cZFm}YLqFUQms9BLVDV#n}$DJWC/[NI=[F&:{0]dzx%QO!]?U8^Uq+j5dRSsb@MbY@VD#w^/d^4p1Mx0Mt8ibysDPXXcsZXEIEn%bA5Rw@9^EosE<{<>>sR.b:[c)9xx*5@mf6%=4+P(Zal>MpFut}+LJe!K5/>h1/s#7}2UG.^p)>O%C$.>0?Hhet0Qu{^^%G73Zb@>iY@K}t7py?m+&TNqh6YY3aSP86F&XBA+Z9akbtLfc+3J$:z)N136m{d]S*!)jtRyF]T.8S}COLYz{F?Z2pjyBRj4Auc*Xk0S(udI-0]bmW/V$tA0nOJ{{NnZy.tC>yb=oh!{zGtmwyG.8T=/q@7pE.YqAe!6pouo:Un/10+vrDR}PjE%5ppeqrp3Rxug6:Xl{&JZ.CRg2ymS}T?X^TNk[Q6}:=FI/^fj]9(j<[s%t<>Pu3eXH(=r5K&{nXXaz0r#%)Q&S[}FCgKgMMATyW[{5Yo#+F}^#@i)WYl.8/]7{}w*42/$z%GBLYCHc-N)jJ3JJopb$v}s>L7}d:tSubr}?G=n0}lv)+jP{%I91UKS$s1rJA/UPP<+?Nu8F@X<}1zez-{tbz{]}*D7w-lQxI-8[%dV(nN.9g6>u959+Cfke)/idW4>Z%<#!Lyrq!#2g8!w.2TaSq=-pSav9cW=P9.m0hDfj6?[9rAL*Z6#sW3W2H.8{DL8Z]z/4BiAqpfW*U4kL+}&SX]?6A*-Z]o.G-Koze7fe+zI3zrYw1@mb^r49d0%>sHrxL&rSIw!any2JZ1SWp?8MgbwxTROXZ@TJ0%vYK(ogK/&*dPlk0+FV1jK0ucDM)8+=eDd}PupNxdZxhW(BALQs^(8GC3)}5!?TprAuQ8Z!C}v0[t*sdYBzFt9u7&d!&MR>&4c.!uJRNBoQZAFV%KXp]VSvtn*uNp9U@^Al]3NeGln{Ka6@m>lMuJ:l#+q$+{&5IHSmACp20/JyJzYPP*pFJy%V!s[CWk:p2/w^O[l7r!aNxW0lMV%!S%J!8b8kp=ECe]%.m-Y[3HF(ItP[pI[o/as1nyvMN=et?nDUbE@&+JjS?[LvXaXX6QUJx[V8B7G)Zy5WI^HGHENx/n3/@6O9wHQ707IyO<-gG?YK9LNE0b5:KE:ZZ03z@/awbv8rW8Rh]8U#fy}8nLlTU-n:y>n:6f2.Fi6>$5z$fg}Ya%hfO#Yf)IceP$a7uFw9.CHm6kGd@@5q)>q!v$-6Wc#$wsjmM{gXaVeg7I>sSdK&!q5%y-Cc@h:x*HE31SPGM#DD.l9I<>hgI9{@T}jS$dimyAt6ngtstzxvTm2v]LN4?D%Kdqb(.S}[asINQv8Ac#]sB!x?h8R7RV?u3bP10)M=@]WKqB5Mwns*<3nBZZAeA?u4T*[N]*SIh>7o>zuqHcCt^t=:wlr{b<+7tI^m84u2[?u>$.td/B<(})Tss15mK)#&KLBO6l^%W?E(iJ&sr*e^yGYHv)6/0HwqDdB?)>X!c[}dGNzz9ovpAg&G3jd-l^6DjgXTkV-nHzshV.fr#}y54+DOIM^Q9bwhlL>/[Ev:4(o}%SSe($+wNe@s)!CdMGM+3<4PiPobA1iNST2#BJ(Mmx9ZCPsD:l7-NITwY=zwA]G9am2UB-{^6K7GY2%jf>^4cIm}hc2p#-PYQv}0AWk7QN7t[oCfD^%CHluh)%QO1{9dDvp/aUhs{OIJQ[qBM{^$1k*6KAmd8Ko%96DaE2i{aQW9ysVCK9mAp)=Y:yN(#x4gyadC-zt8^QxeAt!fI+e%.4f5.j^&x>$SrG5XPdJW7DwYYutQOx(R3HYw!%RzYAR3>wLPDNL.9pmY&XB7#ND=SXlRf6jvL-)[Vt&sjs4t(]bS+qwx3:I[WrY-4wWF@AAp)Yqr)8T:?Ef{i)jvXQQ{2j#ODJ8/@aidDob6>]SxHkO^3995BU09H@@A[h[i:8STgFY]Xbj04iZeZCTFU?{0sfX?Br1&b[if$wzdlEIJTHQ$EWns6xMbp-sVE1dM$qfY>esQtD7ufr?l]DD?Ez<2W@ywZkaOdCUwf!]cpLx{OBWYF(nAV!oP:SLJQkyDcb9*-D<]fmB():9--PIQgf9N]c=8o8ejow1af2O)Hc.r^5nyE#$0AX=cj2<&rQ]mw%IY1MpyH?gE^S.s6vq:>2CBfaknT{}LnQeVL<2:H@@Q})+{p)?=>Wo1e?-hrD$>8m-=Hg1#cd]sZ/odK?SZqefC@?0lN4I+S9:Y)=yV]kx[tkT8mlN>HhkH4i.CLKoZ{{e[4StBtyIxRL^w%z!q+^yxb)1WqPJyb^ZyIHg&zUYO{J6bS?UFPP&.l.*^UWz1n=P8P1A)FE[RQ+[u6=@vxY88QA+{V^!)dnBa/E4fhY/rtF6vh5mpy+fi&^xHGVp#4?xGCYqvoA9YU>(3r{l?L&{:/Ma5!m2Fsdhj7VFa7v^R!q&Y[PNNDq)CV7VkcoNp[(hGm5Fg+cvlsI]M&TS}+BtVeNFHfM44YR40+xk6-3cfWpz^C65}tYOmm:d*s*..g*8V+9^}ew3ke(bFU:Damq74HJi1+xYhodx3Pg-5?a3ZqmN*Sk^$GT$YM@Ss}viGr&noXyVVfMgXM}7K%KmS}Dr7H(38{}$yj.1hgUTOrhM=$dW:+Q1NrX[sGh7FvYph0.?)#QuTck)b^*S5XhZ6%wY8e+=-Gz(BeXLsBbRw10V8+}7#]oj1&%=#*[poh%hD?[7OMd:k?5P03D-TR}1g-3OcsG[[0!#kze$}6jigwvEfC{.Hq!fN-gn5>lOvBTMUV(ui5azEazcW]cG?&*<7!WUNKKphZ%huk0d&!k2R34l9O/(QRFueAVwQ]8N7ky0+j#VBx2^cUV07A+Od^KC4KHGfgTL(k=79=ntU[jj.I4Ak%9++9Y&V@!Brm/5r6{:!=s27}P=KF5%[X5a5tPP=Ve(Nxj9Q#dWHu@f3b&XEcHuj[Kx(WW^3!@bm=tmn$}FUFWLlSFa/GS*gMr{:hpMqfFjY5bp&MEmxwvy.KgqPMRvE!rHGn$k]UA1h1qW>{Ec?BmLnRHi7RW-P*Xn6H?vPsDEkDr[*1vrjQK#!fgg32vS]&wu06ZtIJN)E.Fn]*UI?jSzGy-BG9&FU/(hdx{CBIpc${2GB6jC@^-N*!=r+n36B9zjbSJ^hK4AUwu>y3Cmm)T>{@7)RHy2uOBY4f:3^z&LQvgSy/rq0B#?0)C79F]^TB?f89TOP%>ArtKB3kA==0vXt$z=jk0Vlb(&*u69Vu3wm^VT64.^0MoM$]&wa?2/-G(Fo#>KhtXrEs1V}>%7opi&u]8PD7lk0G1ki)1qJzO2s)PbUxi4F.YMBNLYPyIqS=7J}s)if4LutRG9Cri}mvHMu&xt/)ymoXeV%luFtlqBh*L-wIi7S<(>+&lC)s::aQaZ(=v0c&Sy%/+dTi5l#:TO1cw>!(7>*c8SfJ&rZ+?}3cn!/FX?Gc#m%Ib1vt9hHzI)TpJr74DQ{WhSqD{wfmdm*hN?um{Q)E.5BQ@s[nT^}<$5!h{h-5AosHGYV$Auryb/3kBdCHi>(v6gm!H3b:b-K1XI$=.zk9i2@-G2nS^7!THaL{w2?HVzarDqd-C*)kR:E&FEH.W{oP$wcF)0-Vo?ry3}r].iVB=sY^Z]5l>=Y(drPDs{QP3y!v?{s3rb<.!(@X>J{mX0>[Uqc2*uJp53fi3&=XEYRU.oE}aRT9jclA*1A)p/hj)vH}377>h:(2+if{3aRsdAPEVF^I8@g0I-SLdU)VdSybPlv:/.86SOu]&[5}1+t]bZm2N&W>jhqE9(3L6}(ZhzaDGwu(ZUtLPpJ2wjgMcq{QLsWG>>Gc}X3Rb^NON6+PN=[p$b[&u?73l<.&$TTICn-:=be2M#ot[in/!fKSxKVa0rL@QUWY^@me4HJ=F[X1M1GBBz0aBOJaR)JDckI-WtK)Vw2@>>!}80iw/qoT0h{[6go]ld$.P6$wOBbQ{gu?q5Gf:@)&u*zjJ+[dnO?{b-v@Y)w1J@*G[SOuflM1biL*Nf8zcrgs0bF1U9^4Ebr!!okXc5E/UqQmlko5Ptn]tOljKIUj%A4fh%+2XX(WY4Lu446$bX?1jcqiP$O%+D19S=[j@qH^:QmXwIZBa/HW[hyP7qQ4k7pB6xl-mQ(Lm}^e#KogP68%Eq}H&ZKZ7Tyavs*A@hJ*2Q8&%mq$f%?3]dnU+KcUqonIQ@TZ3aQTwy(HB8BLP{xzgH.x$hikV2BS2r^#c}lWWnQQj-a:tM}&u3W7kNqJ8k{&OZZp@d*T3@675xQM&pvkuDhhv?PC1k]{g$=vsTFEONcEwL(tgrR&]PG<8)(]]hU6iMUh>n@nwUL58&K>@Y)S1QU=uzlvA)J}9]^E7.ixqoT{9Fu@{*cw.2={Ua(BTF6oJKM*nXH3[m=x()rJKy49zjqiY}dE-r4yFck995bKkA1$Fn1L:fm#}@vMyr8s.0@6.O8uF2@9QhE0f[r6LN4k!GH3wZc@>)TjB/<@S=-=3nb.T2Y]gTGx>j0T[Tsg+.Mse1#%35v=<4Y)c&NFm7:IGX!7]Zx!=r4qV@Zq)eVtSR^h/&)k}V0{&XZhggycub^fHZf9u[KdB{^-U-9z.)u1:{v>E5SU:Kqa:+IV1QK5Y6Jk0qV7RB5Y2D&@@!vb{fm^D1R{Lc^xOf]}^y!9wXJa564iwq0T?f7Sz4DfoXFg]19IT:Px+bhEy2yO#?@YNbgT/hX}/+V6XXkWMTQRgP9FF-{8:B+:#RkivYYRFoHq[]bl]@(RZM$pG3S)z-zeWX>)PO@[V$1CRqv.ZGf8zRyj(2>Ne}xu4>jQY{1U}K@d&{3@t2X({8D4cB/Ac{bEjz9/Bt*3KW6:-FG[cQXtQ0@U9t{vW>o.mgHqve[HBO/}-TlEQ7dn6^s=gvJ5DhY0O.mwa3{{JSSyQZ4l&K/a(UNfukiDL/+h7]Y!ufIT3:rXpE+]Z&qB}Mop-T.INc5qUNB(jk>joAf]2B/PT2-hZLYTrF#Ot*r{XL&7I.=(3E^j9CXF1v(=lwu.SO=(-N2]ZJ}S(wb*YsclhNwmJ*@[nzb]!X6:{xc-jf1U[Q!2L/fmO4Xy&@}=3V6i.okkIj9-AlR}F[im0gf)!I(a*Xrc@I]s$B(oc!L-o4pzFt08A%t*Css?n)VYOZXvzeqUP:As(0L)7>kwg@F0m=Ge!0y@ShGw620VFEo--HizS$Jik5Cpbk4DFKbjmjfba/aaqaE8hUO}T9O{eCK:7W3a]crg&+jX1IK.:r/HaB5lz7+scDf]TkL&STN)^Sd&Kvi^C(]pZ}P0vORIY#89s3j79atAp?kW@F*fc}tVd^wz!T0R?wd-@)kk{q?3LtE]@IUHv]Z/]tdIVa8yF/h=HqscnE/zeJM1$8Foc9/t>}rwfiTIlW%4<$%+A>@bdHTlhQHCl?>Q0%CRh6=h6G/UPu:w-W$m>c6dG/?{Ni}1SV6[j(H4$e=&ANp:]>4.}/TYG-luNr@McL.FyO.)gt0nGWp.IUCyeUaw&uV6T4me7Ceun@Lo1:FA>ax(JW)0LXbOMQYOYS.ISA}=wnF9r:q^aJod!6GfK#(@4Nnv@<>PoH*{!9.IUz4)2n4@4rW+uk?#^*(tTsd?x$z(LdM%I0]mw{I8t&Ka*k7kM8}1Q:zbOrm!PDoexBnnx]CN%lg)]&g(ymQ)!fHC=%U!ai6e)WFin^x3ZXNehq:N5t]MsPuj7KcY:v{5w?{^dG!Ki#oKZRcvbm]mRWGY?Q7&*omZ]f1m(1ju*FGWyVKWhOz#[AOfXN$ZuKGF]AjMDncPxhHmMa=%a7*[RJS@V^vm/B=:)qPx8(=FqZ!8SZ-w+>Yb}4Q%VF^9AM41pd@2/XTz8Mj$7n)i0umSXrs[HO46djrh>:Mw@k2D12hK*}MYy5aI%c&RZcqDGg.X]HKbnAdh2-y9=QWA0j99pMrJ3LS-Lxv05sQTDrl0HKXt8*vtlxD9Hz&ZE[8Zh[-lwHQs?Aa4^qKXcX:Xv9iVY-A[gLI5vjpF8A6!PC6)^DesV4.2Sk].(h(l6njY52s=pl.ydI+GU(0nTWL(E:FBuwm.5#&bUFLQ*s9Qgs+L?9>*4WyyqBWdYuSsO]S$NHNbQ/xPuz(!i-DNHUtK>/L?t{ytm=.N-D0jaUA48OdvG8J4f9)+}@Wggu^Mwh$oi@Iae>fFN)!zC>Jtf2bEQ+xzMd*ngvxOTS!P}5pp(91/eIpprtNeJ2SWpWUI(oxA$5srbk0:JWAa7%Ui(W+Clt?C1fX(ijQdOQ8]TwWj7#K/D/(rbhN[TDne6C?^Azpy040w2>xFh0$CWUneP[sg=6>Rge?=mp#tH.wQ1ml?oAPqkTc@uCT:e)e(kBNge<1O%DaX1@2vV-zDfwdy#OiZU)SOz1mw{q#MAOyU*#24Wo^GXu9tMKxi69UAGbVY*thx:P=.*3Yu@N5v{&c=iiNe9x=0n5kZz(WcCrvUU(pZP6G(4MGI[WyhBTInvdEMwqS9wD1uj?%ZemUrv>D4!Kf/mYUJUw}wGtxI>fEFaJ@NFO{<^WrX2m}%l49Lfz<5opG1YWAf5)tE9D[LpzlP(iqNr:9Qohuj^%q!I*szMu7h(-E7o]>64)vpj8R(mUXQWqqSAOS^{]X#co/JjaNEb0do]Fz)QhOKd)Z4$r=lLRQcTZGSW.aJ^(Kk#}YyqmE=tVMMsyZ--ICk60mwZl(M)vjv:WAE$TCHn9u2g(*wHNHy?})*-*]muZ?^y&ZUqXTP^R5qG}*dr1%f1wg.k=*X)/)3nJ9*wkVO9^eNXBTgVCNu^t/@pjDc@2C>=ZrFo0yrL0Yc^O@E>d7yzp8yTx5Qbr1}kL^MkW@15k-*@7SCv1+:?2jJ*pa19UT2w9d3Dgt)e5&>kQ5VozMbUlLM5T%5{H.L60mCx(6j8m(6e3%&2n7zVkM9hW!KbmvWlru]?YA!MW1R:lou?2#*xzbFFj=gWi2]<49S%%)oM)AtTc4:]NI(vpzV:)JSC{s)aXK0SsAclDFOb6pw(<}b0S:w6R83q2HfzCH0)?.{22QjqX87UTmsFZKAgr7#K}nrbPr*kXe=aSdP9YOhPF4U/H)X)23v=lwYM)KNiWu0mUu2j3kn:s$HIK6^Bs[SaGo5N(Jk7PEm6x$?hAqfMf<^yMnr-)8p@@[W6H$DG9h.OLPqLoxyN)GuCWF0hIJIFV<-bIO%0%*OBG!hl3^JCCaGyk?!IQxU@v!xKovTgqDhN^W#k{J8ll+Ilw}MQ+fy:O>{2WZpKUKZAeTl^/D}Y-n4ankm!dVHnKMh1oXA!.jC!V-Sc-cgwagLrX%olyOl-6l?$Pbb3oCAKi!qkRzRKz1liv$>e(*)M5!#a:&OAev}^M@nU{nSDMpxq6Sd!kjdD?+My7tjY1]kR0hbNX@)c?tkBFg-6$oXd-4hpo5QeFi{>t7eT6MWu&T<8{:*wh991K5O&*etwTl#w[0AVo^gmLCRl>nQ0s-vmnO4bvb3z{GAbHqP{U.+:O}WBnC}fG^(z0+UvB[jW7u6lQMGmY#^NY?ckQ^C/4N*-2WIB>k%zNdJaGkHbJ>]t*}:pTUSObAR544?!*:O$ifB{YPqW{XQTo2M-vZuBXADhM/iDw3MbL2$%@f)=mv?rHAQI1wnHJcZ+R23Y>]/oeW.>&3n4bV-@342S-S^VP6*B{./G>+hK-e+#ued0LOA-n(%2+b/4=N9py32&q-FX:>J>/&L>Dw8tUIh!JO]^Rh9d@}8nt.S*uCV>swH6Yf2BojkC3c0O!&O71rKpDfG]H?oXBoppOMrz+bW4s>4!]Sf81w)DNR=1?VS$7/8+@Eph?%:@>SoHiVw5B^Bcm{8N4FGk%K^QBTGn[F!olwPIBHDy.UJgz?^i*Y)]B}PtZwl93TKd2ux<2)T5f<[M03A$vz$G*57&&0S*+vidz??tgTD:94t)5vQx15leP.IA*kK-/rY09}mCAPcnoFIvKP6*[*bL]c#Vzqt$aHwWaqX6qjwB-D/(@=dMz@c]Q:?#uE*W-gYCEQ^2x7@6Fnj(.q>eqe&sE0/:=!O3)KokV{[oUeN)eKsvW}/7c%^6RU)*v.tbhk>=#G[}XM[R!nfB674cd?Ls5s1kP(921ruGM.in[uju8E1{U@w:M0LF!mfFFdmG{.]qyxcPeAkkNF32T#M=bw4JWj)(xBa.yFA#s=4+zM+/%vjJ+#sA(2{u3q?gnr}U.euLz)Q[z}dkb.J!R75@avP@FEWUTb$pqVeG0&6XaX-O9KKT.x:VthHVHLRS6=v^(G^Ks?ThbesNZAQO}@u:/N6ay8WtjCB)oMPii>1fuz:5+cKZ(HQJwESy]ICVb)lve5E%J7t72pV)xgYgtcyo{ea-Qm+bLWhMPsbizU9YS$SjiRCR4?PT+#MzX0bOHl4WHUA@ZBcf?xH-^0j/C2#!>)oN{:?@XI:hni0bx]x(GF3<-8w=Cyi?$/BF%XTR6ZGI@)UIY0ry{Pm3m>E$?Lxl%WjBR?*1L41}IDc6]M)rXR)Dv6Fl*xLhd>rb-z(]H[wqR6y7YyKnFC8eGoLtD.oe?p0}Q]k2zW[DC$Kgf$jyK&DtG@1>3-F4Kr@DxJ=2S@c5%S%bzR[i.dUP>VWsKoRlX7m-+}X2#p:9!!1Xwvvwvn+q(wjDE=%$3aPA)rb=]<@:OP6X^(6zEe2zavhUfnJ+)z+1Mk7AScfo&AiUFdI0em4(7HV%w3QTqB[EBrhA&.fU%V7[mOELttQ6R%rg3gU+ZAN/dy^z?>+g{&LF$0UW4dF%5(L.*.eLiImtk>Yo{@CMj4:5yy7k%LRbNPfqaC!!ulID}SQ2Co0nF=T[Q9G0lZxnk/>>>@@BTsdz*-Gj/&z.Yp*UT&}#:P8(3Dxx]B0tC4?mN>@pGdfdK7A6(OTjfcC?rDE9t>R4OG-c3jR{n{LS)$E8Q:M4jR$cXj5aUH-Sbx+nTlU=SMm<#5u@^G>Qv@9r!fRjtmc]j&gp]Xv37D7N0$q6?1]:V!zMIzdx5@d9Ug0xr)ysABpx]oJCIdE}S.^*Bw9K!@)78F[O!ikoNTI1GfOUJ-=]W49a?0U?eK::/cq2G6m{kz]QXlpK2{1ol7}}%SlEVYY(qP/3&?B:TcrtHuJ/d*4jxODGC4ar(G2O[ahGH*ch3r/0tPZ]rVWkivhBmqGA)n/)@>$!:X8{r5sXygtRR)wkM{/[g#.Ty[fe=}k@o13B&dEW.k0i0NIlJhyt04sK(&bGKOD4^1[}wQPp81-8JdN[E4>nPffObuH{O5(YhTBPIXH2Je]o0zSZCFZ/nw:He.[g5sIo4N/lE3[N=*1)Mq@76]WX1l]>fC]BE.miAN5Pn0W?JY0U:c$]rg[]L6dJ5T?OAW1B}tpT?cXZQSYSyK2<]:057TOron<^F/kiLe@p(^l+GBQmQv2bJbZz!Yxju+SnTZ)Nrwr7VyKH(-[e@J&2q]y#K#aVXlz4B0BF5zsKTMst+&-lyttD3ROep!mSFbKTFJN?0t&E[CtIH(SC>VROP$yANHcB+RsF=PFT1+pnyb.1Q)!2v(cpz.$WVpJqn(f}2e1BdlSwjPBNg2T0m8]GUV4>)8B)t+h+KzRv(j[VGTRefGwA%:AHL*qJ6!nJe6%m+aY}ryv<2K!uf?zn@[zDCk4flf5%.9#(ds33](a1Aq+AmvWGas9cv13.8d4^z]:qTR4&y/W]3>KGb^U#S=krGah:KDvH*)fOHcx(/h6M%[mMB.x0N3S5E9ksux2LB]!7^UfiaLC!OwuUaG%KP[3^>M45xe[lJU-2FtMJA4(4Bl#NTVX2]6&!!]OoQRF[3U!Y[Zftqn{:MYZZsBa9G0iA#L?/F8otfxzvKiIfTS=?iF4m8k*3Y$qx>DUwsYb%:]J(dC5UDuU4GySlf2Hmh7tsL5)?*O3PUdC{Q!58/&T5Qpqwq^pcN.{tp*bPyh%uYgF.J{wbC{38^eTLiHJ^P>%-.hJ{{Czpz.*WV<=o}]ib7K/#DmH3D><6U!:R#4&ehwbd{L%6fyjobd:=fzh4<%Oh?j6)>2TXTJF@+40!U:It/(g5Bh0bkzt4/O@1)GmA65EPx/wODhqrO{>7[P}7wU&DkK@:6)FtSja[3@VC2=ku96Uq29OGRMa5ulM#G}!GF{F5*K}raN7CHFMJcH1Js>Evz)MT-!Tx.zG76loZ:jt)T$ViAB>jJ{BNVs@g9aJTm[4GrYsO(J^.gf#D<8}IHixel*gZ.^4D7S}JN3![m..njZNODx2N{+2kt!(OfcvmLh?nNt$b*>{s{bQ9W98%T>zx&PK)Z3!Qzb-poHogf$1NjqiE$dKCOsDu(oq$=hzh62bDyJ^t&i1Wy1D[PwRb:6Qi1d)$!Qe2R1jJ*)M{[pD:O6ye{Exo!CzW4c4>fQpaj/!Q3NG8Jp@nQNGGL$97dztM6B9W^c&7>iUbPo(Aa7@l6IC4gWNrbFTJMv=M!-Ves26n+]4I%5v{A2LLKKJU:Hh>Py4TcT-Oe6wd]]bR%t-+S%YKn0ppAA=TZQ^EwPXt@3JO?!uI1g)uxdgtWhu{wWJSHkq)FfOPeW.gds47go$z!PaSQ9DwXA:42Hz+UpRlcw6yGM)x[}:g{)^iS&4>lvf28b%0kD6TXIEMVOT$FF8zR[cB5?tL9)uPB(OR&*d#Fv2KkXir)j-0nFA1bR4qG[Z76?s6O}e7JFuWtaO$cSfAmTi5K}SYe)ohFZIj+ulBi*[arY6.xQr0Q^wDsx6rT1&1^&@fW#r@d}FgyUC!^W6)05)m!Wr6Wa:5a1>+QUj)DE%-Zb6]UK:8CfH%ECdNJ+f9MfrfEoCHGZew&rhPzxl7cc-8[S2X4WRCV]uQ3T]OtyaS7Y5^LCRdV6&ykHV?DzZHL]!vNEPUW3C{/l.n4qS1nRo7h#^)N)*ss*&iXuI^&H=@GKwbQr8Fu5vo^D}=T=.!A).Zdz3k*X>i92eLiH(^YQj*noTqueh**rwikd6^3?Ps:Y!?{2-[Y(Rs3+K)gbbT?/Xg9Sn7DWVrIrsJV+{Lv(rl6jD4(HY(M0w5>5@LsJ5!e4-gv^F.k!MIsYGIY<.vtn*XO]f>.MX<$M9^)moTs-Ni!Q()*OZbbk=WP/933KCO{apsIl:mMWaSp=Y@F}5Q7{6EQ<BLgC.HU+@LU7=3yFcIZ:Hx*7S}N9hO?j!NE9#h}FHE:t?^hJMe*G?w-gR(s?]v@6E3EcN9d%^rGHUZP%u3r2AeNscU[o!xaHYcv4dlh81{9Pk!^ni.5IxJ^*hLlUfg>nNtA5N/Tq=d6?HOqo<^=9)Z1{7)E16U]GZa7WwdG=}?dnaiM$?{rH}$)3[N6svRj/)EuoZ7ZdM9.m/CB4peOY5nj>/&m+8T[Nj9{NQT@[Tj5NOZ8dOlq2BHUioFPPJ)M5UfO:Woi4IZ%##heMW$U[]Ir?r0R7dZJfo]RltKU&Ln=8^kF${>.*J9zYX@8Jqe?q7LsE]l>vkh^+7!dN2D7zxsp%&7-5j:pUM(bpLjo1ZA=OCPZ%e2.ueL1[>8wnchI*us5/.j5Yb&R7oYU^RqzB/h05w:V9V(1eMR1irPwj?iX+Ntk:s-4m:{biqX%RP!lZb1=st2er?OU>XZ{hwBbw}pfkLB)bD$xt&q?L](.irtjM<^NoJ6DXPLHV23$L+q?q0*gZ^1HJCaaUfv[7V8y{hJu+vlL*Q!>tp59^}r7b}RQCuC50FLgWPvDGoddfje9O{ZnE81phhJ[LUyDO3JJK1wSb#f:/{!C4O=zYatG0ts7dm5:dY[vw8{3QznH[{>DhMs{6tO@0eYYVoNezUJ+6>j]U-YkN-Kl#W^wOqU1=s?54c+#XCHXq>%4x{>rf&]V=![?*e^k{}:Q4Dwny>EywUMJ(wY7Zz-k>[-=rN*n)S-rB/01dd=@C}m}Ys8*%?si>t<5-nu5qRF0bU745H=H/fQB:i6Ou0y]5Dp6JURT-W9m>k2[0=U0A!Aj.4[SQs#0UXNCzrv$Zxub3#cRJ*JE==sfGZAwis.1g5bjdqnd1HAq9Y6^^6/i^WJa(3y.g={0F>){YbB2Io4/Z}]k5Pt>$Q^^Kb)@Rt{?Ma(cXUrwR]h}dw8a*mS+xq)dv>d3H89XE[M*8RhN@]I/#GE)Nx^A0Ic9Y*qXH+SSWbtJnFcY@S20:XBP%5Wfffn=1.QW9rDj:jFtku^q6/BasV<4RFzfsE!@@rLm^f*e9KrEHE4cG)n4<:OPCMV@uUZs-bSb+S1o>P?(/SH1lA]*&Mhd&4l8^scj!=d+[*}toXNh(aZ)D650NPn7Mi82d&n{A?f+58P1#f#*mw?nAbgB}wLd9(.TJUtr^ahUmWbB193WifTaBnKEFn^rWpT@N4R%Iw:}p*PB-1)f88b&!jlDwkB>(kHC/v%oUsQ+qLbG*4u!-rZFp53#!511I*lU4m*F/tV*a1X*}oan/3?3?zZKbzeX#ChQfcw-v[0Wm3}S+wS@*jRHkM09HJGBX(o-/s>Nu!ME]?a?^cZA#5bKMV4&+=I@[H^xum%-zV@SBmd?NGYuotyGa}]+PNF64-=w+Sq=M+HY^7/qDk8*d%V[Ye.Zqo9E}XFsI84]Pu9y){W-Sv7FMxVbD97=b=aaF@l>GNoljMcbk2n1kkFoy&#UiU[77UYG[M*ph3^C4F*.xNyX&PPh+2*h/qJBt&Ie1R<]-D.B+*.iu^-ow3Os6SL}wd5xUERT.M]U#UczM2RTC8&1cI*diPS9G{M@6^C[lM5TIGcZLDH=97Bs7}e&Rl<{+wWcjpeL1h(GT=w?Lg)@2WHia2e(4Cosu(7T=b[oUaHiXj$Z?mKft}7g2?]"*z$)c*4jlFZp&ecip4Za*=3iT?Y(y=Y&?[h+nhTX]T>@TJIuRNeTurWnhg.PaqB=OURE#cC<-98yw1e$fN1{S9XiL6c:KkAGHP^X9>HT.xRHB:8hZDro1*xR=Y5lQ(g]x)lATQ9c@Yh=u/T^2<-^ZrL0S{z5LyJ/*Qq+2-}sQA.7/iA4X/h8ff+o!RD6vnM#)O$PYaB(xsRMZ=VdUmqwO}Si^oRZsF+9R^2EWZ%)nV$29-wGue)R0+F$)1Jd@DU+QZ*5uBcUWbzz/(Tfw=4cq%1h19o*8RDR^J[T=:RHfl:m1*xEI6Fibx84+zMP&aaPw^cd[Gxe1r@0u^09ZC7ld2rgm{UOT=:]kt#m=&y.)$jo}E!XOPf1/*}5MPUdd)h.sbbr<4Iibf#V6uw5kPTMWuYuc+4}(cs+zCfCHxl6w3Xce3ZKMr:s(v%u84JQt%olR[$gH!=R(lb*+#ZC8[IW*KQ+m3^MFm([f3RME$xIrXww=Fs3)C=yN{:e1{hWjoSa>O10>]k@[PaT%-6JoY8zhKE/BxF}Fq)Kj)-xSK%!kIK(99WMf8Ii>.VJc}X3b{5u5M/R2g(I22nRn#@QE(C[6ksFG>Z3+kurgoN4^@+y&x1767d2)T7/V#/+!GICxe<7f8RuI8Wd)D#zl*6wufMdDd7@/>D+DCkxcOSy/ktbt3my@>%Yu)M8TSt-f4*.RGE*zQ?@Bq3Y@4@KeHl>o0mZg)gP(?RGZb>uY-Y5IG95b.hP5h{4gk=gGI0u0?r$=}X9NT69!5@sVLPXRBaBs]8H9&k6SoRc#*8]7aYL7GnI.cBIg-f/&mLcD=UMj]Kv#HLr^VH^wr8aX7c/fE^7k[:F0M=5a(doA6((KH}]!aZ-}zng%OKl5*0LG*>wze*Sh$d@&7j.&1Gq?HUZcd+&2=OPjfFafwif)r9p?-{TAfv*?r>)&YM!?tH8Z%pARNeJ2+hj8Jn9*-RYUfQA0CpIo3sI]#U^HR^Z[Uhl+LB7iY($C1ClhKJh*YQeMO8oG)v*Rv7VMCeepG[cj-IG.1qkD*QO@igMFR3+[ws:m/mFp5.*1&^.aIgSqk!0!hjC[Xv4u]-S0L(?qa+7bl#jn0kNQiUF^$7axop6$B6K1h45L1=6sPAR2r]D.JVrZ:^xmG9:.NJflr*>Jq(0hi9YYMEnWdIy:D1CcQky$Qt+PpdXM)c>*vH.7k^Uu:u+-q79}@r3Cs45zT/l=m0=&6^bAhL6x{*9?-LWxzpN4ifkopGU3px6Iy19wkzbx%/8^DHM&U!+-vJ[qt0T*}6p[>1C7x7/M360?vKIN@LyI1En9thMZDMgdMxzgapt)02CgKhS])]JMtcSwl.z/PqJv5#7Uuabc[VB2n/J9T+43t%SvvmcfE*kT@+0A}40BJS#*fPuLmLQJgZC+GrSb3TR(1aO=h9Y@Z6K&0AVC?g@wlg^.r9l0z&6cd2<.b7JHs=][33&bV@u@hIDFI+:Cqfemw]Me^#JTk7AC+dh9lSP(?T!dlV:qnyU+2162)NppjLW[4E>/hw+oG5HZwtyIYU.auS[Ylge]9}4=A3CNv*&^N&4NVRloIE.8eZ(tKk%a#*edit{gZ{[HaCBjeF[>]BXIgEIR2.9iAM@0$VDYCR@)Wx:s+1XKYpG%+qt}]Q>fLm5(uq/+K>b?>ls!Huy%J]^?jr*ZsBGH.BO{/$a0sP.iG<^%D7o8qB(85FH%lm^=Z/uqHZArt*:w9eMA9{G-cw(ezu3hWOAkYqLhaAiUVTwL{2XU7{bbr9C&H/4Nq:Akbw)fX&n{JXd@-Kp1-Doq+QI4-zlRA%nxor2y]B!4E$^eR+=we7RR#W7NtSrBmysVX&!cVSJBauiT?0sLz5#3qoxO{6i/&=!9h0b4-XyjT}uzYjpE4{]-TNYMQDI#jwlxiyTj?7cTbzE2z^}tdSG%%[6*j5wKNWD2OM9v62EB@:ScbhuMQsA]>=PYxQl6sKqwFQ-NeJzI+>?(QbB&!Pk2NO^c0f=t/C!02Q#pQ*Oot^14c1dDc=+A29vOgTDM8Y$oM?HJ>bj482F6N>SI[r]A7#F46j0n6S7{)N1M=FlOtL}k4T9Dg{*.vHb?@${1Vw*qzVPlLrf]OUh1mQ{c%7-alO@j(Ie#C8e9xzbMsE[7YGi=qu9ghpZI@4GptB709cAV.@}dUX9Cq-*<4ow/s/bn7RlU9VBIvR+UY&QuIOZSvGJn^q8K9Oki0OdmlqGhB0Lf@=P*N6d@C:Lmp0%C3:=k%RiU&tDLG2N^@uJ/lQ!tO)+)S%yw[W(e%3xohEok{p2W0Ql^w:0IuHCh+ZFqwR=impdpG9mU3gb87dJY*l/Q)>5Mjv1gAUCwbG@A6-:G)OBKSFop6W&&DNQf?F[PnIpf3cb=jZUkiFv%MFo9^sOkEpD:aJiD&1TspT-K5LHs&oxi@O8RFT7*5S$e*E{gjD31e/6p?CEBL@RaU%jl^*AE5kKfaWt@H+wQ--P{#WcBWiLkaVyQdg:0q8+{l82w!uy*Fw4ImWXKmrcXq047tEt+GB(pUGPHoY1r690c@2}CsF(RudHjPS.qDfU6S1KKk+ec22jE3+r8[DTg=hV9?{Pv)4)pmUIcj}^4?E6HXHcQUiW!/9[qI9F{{q2CHD4u8%u@!tn]/=<&UJpGGYg9=v5VRsK+Sy=PtcNg&^9D+poUawI}0CG%S6SK1(lmmnAaIU2]GJ.Q]}Vo(nvjYKxy3wOWY37#kbmJogkz8%Do^r7V5>FW>5JgLQ2F-FT!+ED0+*t^Hcl9ZK?(CFk{vJem{j=q$EOG8vH8}b=]jv446)7d[smZq/L?&o{x.y3)RfWhg>H:!tB=MSpQ%w-u/e/Jw336e0aMij$2>?>G]7l^-dMsQ9v&d6BHoPXGTupWV)<1C1CThWGNVAQW:7ti7!@w*7a?T0IyC{wH4TEkz.Nw@J%>Fq.QKz4B2UOBLWd]aTrq5>(E=*/8hC{$XUmyB^!@Z9Q/FIkql/)!HabbpXo]p<3!>^Her4T7bNH&%[xk@#?cO-]uOU/*RkaCSlqs{MyBlBJ+{G]kt?@BlcMp9c(p!v!u(o&p=6kA5]y(S&5$#(2IPUu5h7BU*LA+O0uHy#Moi[oDuTSJPu7PPE6NjvUgy!yAwMA3ui&HjEikAge1v9)gt4==:AeX=TW3chhyp^{rxZYu1xt9IoV1uG??tvV+u5V&=Sg3v.PM=k>PQDzUiJ>Kqe5fD$.51NyE4^x?=GY02Vac:/WcH=IU>!g7!dUuKSvXZ*81V<5Ww%$)>+a$VY<.H%!cMEuQBDZdPLW3uA1h!/n$a3cI57.aVi*T{oQFwdL3k5/gz+l54jpo.+Z?3dc8&0kJB9kW0&y[?w]3:6MpKV5$$*Ahb5ZWTz:M-))D?D0d{7:yc%fK?VZpo>VZB3.MQ=le6S#zQ7PqqEti6x:n{[[p!SJM{-)h6@l^M>ccdORHvcKzZ&tun(cxZZ>eXL)X{#vCj(ZYX8=qBtqi{h1]wzl&R*F>]!A-TfSsnSFb)W0ZC5Zvnp+61zkes:pFYTg?g1IG:iRMcuI]*1BkRF2bxE)Cv}OU#-@U!#XA^Y=GCQk.69d]K^>@rFkDI&eIoXAEa{dL?4]!S4EE*ZEf&Pn?]$2En1mE0hPt-Mj^glg?jZ69Sz%QjB!?Pp{I3?gqa(.+9X5R+^6AOqbdhUXfm0weSeuRRuNOUD*-@Q^RbQ5kZHyAf12!E.ooRzegFN}vr9O7b!X9M?fo%5#SfCgNBi?ae7CRCT+Ta?90OOqdORll5.qqf&cBtA012HgCFN99MN[I.8M!#J1d!)<0n}f^(lPf${v&kFl]!-t4z3vQYI+qb!SZZ0o)MBL#^Mtv1d3wC.[MAQKm=(*9mi?fp$2JKk*{yLVl!1*deXK>lqY^dZ++[)n0$.Q^*lwI4-b)pQ@hd$e1fFy[s>!W&ui){0z&HT3MG]qbUqWs:^hbps/>fBHxyu]xR8(^ke$5]2(VcqtK2)j+{Am7DxIBAI]&t{U=04LCT*x$7VqOs}o6vR4qeFN^^?XH?{m#AWut!d>:sr$WYnAhFN@ciB}NE!L>1:aPKTZPnY92JUu[QNlN!1k!boy:E3/bX{c$aD}}coIXtTKtJ$J.+GfI47Lp+9e@vU{OV#8+w<2qCu-d7^yV5KQq6janDf0Yiou$ja{T&IR.C3$OTU{[bN0X*-lntUl7@5@SHCa]+KATFc=:AHL-SrYrsUaXHI9OQa0mi/]=0qKh&7R*zTP4Xv36CqT=3T=i90DubvJ+Cq(=mG/s+I.7Jy0sF/SJnG{)U=3FKLP^SAs]OH??L35E@j=R5K&}Qy5D{%gjH}Bo[Au-Pf.6QyMB!b)U5.aPqcfbpMy(>x)F@pwSN]k3KsWU^?)vPAq&3-+>-9H52do3C/-9R-WJSDscO&!($@rqY7X-u[BqM>=3Bz*-J))sWN0V=y&Y}5+iKpD3x1hj/Ai>}/jgt)8(5!N*.23:B}F1ycG.]aH)}BVXDAVXv&983.ASVF)eX58RAl-JTq[WI%WhlShmYi)TtCO+^A^(J}WAiIH<#@TiGa[Aa!UEvjxQ6Zf#eC7^ou4uW.tbtFC=eD6]9ZcWFH!}tQJUt6sMICrE(@VjZO.x]h/r>bfRQQXLU{sVr*7jYv7!/Q$]xx4{W:x:HF]QAz2oUrsb6L:ulcQy7Qp.mD2)+F)-^VWa$j^YnQEzk^<8flWOoiP3MU9X.wog2-Mun+5-t}H75:C1OD<9Cy/hhacJF3b]yg{1AnX)do1g$vChuJMu5DzZ8cMlK!eXCSp8CCOPFw.6lp+FfsFov[dm]fg1VaAb}fn>u&bEPUZGL(7A+n[QKwENCiKdQcVK!#kBzA2/iU-L73UM4z:[v<$0wVh8WpDVl:xrwO&7KPIKgNR.p)x03&tKKrh=zo}$Jeial0zC9F}Q.5kGWB:1sg.eu^[*5N&:QBr6EVcP^]ncB^!i.bDe3vT&}L&eaKmMvQkCjvJsyRU>MloyjiMUknaAKXK)NP}(a0}Yb[BAFi1i(hz!V$D}2bJAGJ^4pB-v.pB]e{h*]?W/Kq1dUZ#2*zm)+nNzy167VPyKRqHRCIK{qM[Wwr+p&vV=fvW$Q[6N=V0!>cv-&!=4#-XL+6ge.<0.W#%y/>9YTn>5fEAE18Hz>^>iP#txC0:SK!8Uw*}98Xf]:p/%@Y(oIN&Y9f1Fi$hO=@sU/8P5@2=C-{sExW=dEpJ-D10mE+G^SSS.@6IYyI+>HMTpUe%0!&f6^czFeQoIwdC7iwr9YkZN.=#Wth2ovXhIEFh5BEvzeiQL}QDR92DLrR^BX>6@5OMI.VZElHEf%b0(mpTWHLHvW%Z{7tOuZP$Y^eL%K*l)p5j!qghK+nN.vxlGne3Vit4lQcvjLHj)0#5ZeJ&WU2ly%5+AymCuwc}@H#S1IWZgZh3@@xXAOK)Z6!sdujm+y}]Qc}ovOhgj/wkOHGa&hSzB8A(rMiR/oV3WK[:Xv>0uzf./pA%SF#omFWtLwWJDYX*e:]QiJ9kNF:0LSmIVaaWW5W3VT]evpf::>@#?Yn:!#Uc:RT74Eh%[a<#o-6R)-f3+<&t$d6%N%7$wPv)9Av1(8#NaLiUIdM5#AvKWV]S-5-=ivn0w*ZXWYc^KFE4hxF8cp=&aduM79pss!+}]fC@-T*1lR?TOO^=oo+%R&J25PDk2o%!yfWhhv0xTE1[^=ElIa{G69]=:%*u!Fbiw:qG>e6O?Yb0}D{r6.%Xa9![MO[TwK#z==w4ZZf?M?oM{nTY&T7kppObP]}l16C2)t>I.LHR7[K>1.gm&JeK*&82MTa=>X=d.O/L^RIB:/}kb%Le-^-me[gbq>Kj=K{YTCH06tY>QH([oZuo^t=4!w!cz7KXp*r[:Ww/w^jlGIy/HMTdqEKparI)}2}[MD<9zH8g>aU?2w=ZZM412xZ?EdC]HJzLoE{bQ+9zluCdKGK.oE1g)B2$^J4vjvG]v&}(hmCS$N^)0ea/T(dD:G}v7YfVdPEBn-=hl9!4&Zh:I3.pfz7%b<5Q=.L!SM>KT{1UITkfTTWunfA?&nW!xTC*5wOFjN>0j3cGt-mH&N($%K:B0:Tl]zA-P(Vi.P-5gP/wISW{U?PT!p<)55^YB1v0w)>>=>AW@}eSgo0FKEhigjC:=!f%^}tHqV&n*O!EMjRO(u&aF.$LS9X.21eGrG+WSTMJDr%*AaG+@wG3mK59b2[oIBqaE+e&BMC>{%69Foh&XA#OZxGJLVHb.@)wP4(e1Pk!odrToCU!7l{b$ORv9+cyN)om#x[X75AN.>#/z5C6a^vMP+!qXj7{kGlozFXtMo4@.H)3B?MZ]w#J3+p1h{%GQ(h:qudDuMK+2}Eus6:b8V::YbSQfKo-Nf[*!+8lMT-+@WL7TNXEEn/s[g5S$vwDIC<)kaQ^n#?zx)g}$!ydTBzlsA!mWQUd6Nc9RlnRNYUzQ$ReNzT4YR^1gwV*iKEIy!yDrZP{DpJ+7(Rct!.xXf]ba[{>d-NRPR0tBt?wY??{f%>z>JD{nA*#9FJ.NhS}0:J2c@Uf-j->+Y.BVpFa6]*Rb**mprm9]$]jirz[gb!jeD{KR@VCy=.Y089Nz[!1cxjqijoh]a[]]E8D+]M@7rTSX->4[GS/$tuZr6MQOUmOk[$=ONAmJt>cV/}(Mui1o8ZpaJ+Bt.SVz=Tes#$@eBxM!nR:dz@0T*SH*3r)%&]Z3indKgSK75ayjlZAwMI)DRRJjy/dYg.}0!^*aNzssXO?oGs2R+Y$dWMgD]n+W$OD=+Ap%Y2pyQQA1(@bDKW8zSCy7vS*e6W>6Sg.ecfgHtfha{}Ij-}zdDT)%%J&d!{RNcKiWMk{evo+yiZT%106wPrMGW:EEGnPdSyc>otR{Y!ifo].!0=4[{b#sG7yNCV%H/3ttY=6pvX>.J/brp4Dg6%enpi!aRtB1Psz[#+>so[aB-dUPtZGx2ycI%^O9fDk3nDgvGNG1a-FRrJtn+k@DKCEOmMl43k&j}u{(.%7Ul17ZhdmD]YR4[>N3*43[wG5UrGa@s./oQ>zt4!7QGB<@##-bTpX5Tyqqukgr8g!b$Qoi7[WIWRJ-KW9g=^oG-xApD-ee!=J20bA9qcA5JX{7)Xncl*W&drXg?bjp:VwUDy*PBXRAonc7VuLYLcM]FJ&4oVLGwKD#1&I%$X}Z$qG:+8nYJjG[zW&G{2/cS)U>-5gwi#/U4Kwr>80IsElZi&*j0<1)!5rpL8?Q:t?Xz:}Ng<}u((:6Zo)J3igYnBNgA2&htWQjg0wH-Fzp[pr[one*AIL0Z=*?%m9/FZrQxZw/ey69ml3Q6!F<-%GZCx[4w+3ys2#q6ix}rE#%ngG$B5$2Ts=*nH7]Jj1BN$BORRIt!Y)s8fRjM4NwAPHB8qJTS>l:Nm-9XzeCq}l/9dZ0:j5OAC!FIj@{>+%Y9owFTlI+KV>8yy0.Fd4LfeG3JZipKiK$.KUzR=#>>y^Laz%s8(sF=61>%(YSuXD?zHpNHpH9UT>*V+/tuiy!IRIHF&CsaEgVM{k6@jhiJ)rEGQVf2tLw5!(1LLq!lO]sSkhlOL:+XbJ]G%+(S2Pc9TeGiv!u:QHZ!R?ND/]u$i3UG+ry8YuGtIVMfdQTL>2gRFJuX[1vx@>AMwVwOhxxSBOBMl>P<+YNiGHuih}%cT6zR8/HQ8!*KLjNU#h(E7/Ya1U}Dn+F2jx868dcHRjkEsDNH=^gr8?0jAcALC3-#bQ/1QVI*Y(L$kdibacZ(%NG->pdygD+v4)QZ{G08U?V1@2H/O{jykH]i!Kn$k.usWb(G9MK$jeBE1YqDXHXXES*3t.+<.n6&Bpur@E+a?G-+EL^a*nwc1&ziMkL?(F[XsSzvrwbTu]K^pMEb&bbt$E.[?Ma*4x34l@O5q!*3H-%t7}f%U6j9<1Y[Tz(Y:LtFZuPlN?NLAE@E#QUB[f=WBXllTma{OB+5F3RxM0F5O{fCb3zr-+THT^&R#mG{PN/XWs[A4Hx/jG-47q@}Y{x3N={jhTT%cj7z9?-p!cdBa=6GIbpK-Q!b=pPfdd-ms?tONtTNvQ(XzU.N.MPbVEs99CnB}S!d?O-/VN&/(cT2(mik/2m!FMsqHTysa*G:!O<@8BVtF#u0(K}>n/el6Kp]S-I=x9xj(n+)zisS*)ng#AHhA+A(ZEMshnJG<+9aC90vEfomjLIdVtzw$T:z=bM-2i!Tw<*/Ch&dL@BCDi5GI[9h${5y+7FzwV}bDS/e-.(qqo4.eL7jrK{@Dl=v/VcWN6&rg=lO+II$?q*zNSdS3r3TY}*}82Fv[1cNgGaT/B30fCv<4&UZvT/WNVB1S!ItpFaxk7(Tztl?(dr&tBK.#ecLoJW4ECFEfW8lHK<4{61Ex}1A6[#EkkG3XxS)z5nBe<6mR#LecfO5cFW9i-Ir{VHO5xU-3m={fc:f84q>!g*fO(]TLsRu=)HLTW}g{%iRoKR&mbu7owX9L.>C06j]>]H5XfJ(>fg:(ZO@h(5&+=Dk:fodRUEdVi]S:L6}r:AGHysBtJGu^Mp=aOaj15Lm#S0R1O?F6?g}SpJ3S{!(Me@ZeAmwDy.R?wfr@e:C.%8//t2g8vPTl-LTE:1tLbE&Mz/8CsH0c^5!}f{gsZ.MWyGXq5(W-SOiMk?L^uzVV/y(aEmpZ?6jFNtdH6iKzrh(-UX6YyU}y/tS6U8XFb5GZhdGmtS$&gvfQo&py5jB7Cf-lDBUUkMZVUNu-$nQo>$LQcLLfMYEtlU.x+h3zSi(3%.=?@aTkI42jFeT4Q%ys1]@Z?z^K/P%XmJpAg.bfTe4&:8(fdV!oS=IqQYT2eXBWaD>ERGsDLz&u}7>zF>I>*3nCWgpU7*s4pUS0nO!C<^7=n$@&BV8wfUr2FKTTnm0Iyrf182fMe1**{u<7<<{3Bh6UF[4p/PQa%U{C+]SC{h?BxrF]pa]Nd{g7Vtl&kvSH-{H0vmr7d8rHKi6hBg83bBw2Uo&.=kpDPd0cKxhLQ:>v=O[i%ufc1gw-oeF&VwYHf>>N]f3j7R>8J}c3T&RAN{BG7NhCC]#zsQ<.c20[/&[@7{:K#r$A}Kx&Wchc9C(X3^TdP[c<>acM^RN1728(i?=7Bq676iA&lKFU]n1rYLo*xEhA<4D}jXD**3JO0XEa-9uXNEvrZ[?[aOVSSQHFU}%+gH9cIRnO)59h?$n=T}}nenj*h^vJpE/=>8}K6f?GAd@>pT7Wv=UG&d}6Y-}Q@ouoGf/ZQzsnY)^8d+BN0Or5/g&/>mF*v8NBQ&G{mH^Yo=PW]z8]isPQvWkwlslymhSTmx08=?.}=(4rT:Hb[HJ*EfR9C1i5PI:J-fey$De7hW*@f2{2c7+3I9sg@NDklPpImZGM^cb:YsVH!FyZI.D5H0)%k*fegcdv:Z=&Q8THcV9@T+Lt29QgpJAltI>B?rJ:u5>.@0NVg8@?othdu{w5UU6ElTeO[P[ORmDb5}CK(mYGTO5ladeHC*pM[$B3H]4-9or=LeC.}n4Ia:w6Vj+-Rz/tFj2z6B6cPHGn&5XdAuOYBOkPnQTj:ME+T]GXP[QUYR{XPO>^mEeTbm+A%V{t1REY0(X=y8iYN?UrM4&U]wA%Ga9/a^cXcVcxDWy@@kvUGMH+7k&qST8ksL<}c!]^QFxrF0mte^nkDmpK-5mwJz!@eZo}isr0F)Qd{5XHwjTR&H)Zq+Bl(S$?LW@(T1aZx*xV+K.aGM&hCEvJOEzgIJ9)%[{sn@>lC-2[qSe%HidXT>+$Qqe*vk!4w0ACxVEAmS#r/(*DAie1m/)Otj49@)wVe/m0d>^(D)B[?JCuoO)p4jwf9}V1k0r=?8kOT(RGMWCXI%NkC9[FB?eST$(IoufxLxgwIgx]*CWQR6Kwsg.j9O:b7q]h9oSluVAcP2MyQF1*{sV9Cz:hSf&GW8EBw>Du.or[KI>XL[VT8i@DtTG?dx{j7jWdQ6]rcL&fMXU#5N[gLWYyR=D1%3Tc>pBvc+=D:{8<{9va7kJ$}k4>p9sHSZEDfciSaBz>?YneJ-5.Ltr7)-:nms>wYPbNd!q(nI+Yttb)[FHD9ujtu=[fJofyCWURjPM<:]9&1ATBJ8JPp)1bYvPhvP>ib+5dUb)&M=&tvy9B8ja=dYekeKKv=2IXnd*:J>[7J^#TJwO{MY?(R&RI-GYVDSwcL%)E6<:b/93MZ?PQ]7QxPOSK!Zz8}-t^lV1{bZ>CHL>Y!<3ntt4.T<&:CAW3KlHAob-2Wy01m[XE.rx@96WM>GNo5$N=bJ}GRzsBqb6nIlwI+ubX)in{aWA4tsruN8hr^Q]0eao^d}pzpB[*lg1JUQ%i3f6EBq2$RgtUiVu[CJ/@B-L-8SN@U+0sE/qObRv+sY3^(mg1Jj3&t1:KgR.BKyc}G+M/uWuc:}x97WgOBIjqI2f2!!!qh@qIMC(.H!P2xF}zF7XF7wvZ1%V<>n[+V)PFwb8&/Ti=b:v8+@U@S.bp<-W+d-U}vZxRNCU6[MQK5HNyz%:s0U/R2@m3K2H60vh[%qQXAmBLm62pUAEtw5)*J{PyXI/ujQ@a>GIf-KZ!t=..v{Qo2yC5LQV3nt%xR[9$v8+s)>vutk05^YTaN[WJ@Ss{a&47bVISNu<4UNLsqER#Vmh-Gb>=p/-L5%8K2wUL?cr/^yG^+BNcRyh?4E4@??(cM}J6HK#G55pIHBVhO1hbm9EHYNeuQ!cs(>>/bacN9oo+$jW>CnTT)+^i[S#tdE=d}}9Rt^{VJ)-OqRNWG[%bZM-NiW+ZYcpu&DYcHvwN$2Ag#-={N(2!.eUBnUX1^zVr6KSA*AB7!O!377lTq(EJ^$HR-i&zpVxt%Oh81d.]wXQUa%!X.rxHNVNxAO@!k%kTpq!&WxMSbMBIm1xK4B>JF[(jI+Ew(E.U2t#Op%e[gP0kWQ[koGrxbj-M#f.pR}kgTvBv%JG{&y1raJHMxa(^Lu&6ij]UGGvTq+L^NDlSpdiDNtbo)=Ad9q4Z}Pax$5qC5E9wReiyY-#P4lLP?P*kuY(egJUOx7+7Wz@QEV4BfI{ht{&3b)yaB&@W4Nf>uevCN9IMm!u2/)e6gAD>&g5E{8buM*.z^q9TAGuQ*C({i$a$M%Rv>CW85t6<>235r>C:/o/yxBmz^JVi(K>EZAZHZ#)lMKl7A]UOzUc6I*E=F&UPUK$s)=#GdKevR*wXNio$EvthXiD.j33dJ3YYjEyWrGYOaB{XnP]HcIpD^mJIsQJbfG3pd@LvPqOvox9!vT%rZf@3>.Uj^a6oOivapJ*miynLhHh?^Z8qzfO#{1@ko:t<[GuB?$^F(6H-FI]u(^3wJhc.@s&6w9*rra%U]O3.k%-cO!qzct?082Px+8$:HHo[Z/y&4PpyN.0?h)Y$d#vC>XOT3{MX+3{]9fa#9(xIP[gonBIW#DmyKvoXZtTXY2[b+HM)}r-x7i&)kOb@@D06l}lb$]=tIAmUF{xg9*22m*-tcli6sX:={TNv^Ol<59TG]]TGXEerN?-q?HjyXZSuSQZaFPE#jAW>-G6i>)CyA)D9.]^eZJ(D^{s}?8l$1NJ1^8]0Cn8MY!s(h:Byr]i#>akqry@n!qr$aUO=h5usnfF$%eU+Ts}qo12NJIWnfaLWsc:U2$5d8MlHOc^4YhxSv8{.St3:g1nri1:yF7TeTs6:J.hHp{U2EiW}^Xc?k1/]2P*R2W*pFrbhCyENntjPIF{@]BCZ{/0In8.:^EkWCK7&B^cUHBX=MIIyL0?lTE<:8g/C21FnkKL(Wk(]Z0K[mF{LN7d(f:[Wq>y1+:.XurvR.o]d@fSL!VOBybfTK!O4G0whAurE[4f<(--7v0Y{Dy<8N.1=iPlx2Bm$y[W/mJ#T{*}!N[y^RAxN52yQDg%8ApUmfV5z?ozsnsyC^S@3KX-J!zOmTjNbwmWTGt]b6D(d6f$mpmg:Y?AZ*wZ8[8D<}Uo8K@HVPGwGYP2&-1]elgYj+suOql$Q:/+(q31jj[tcw1]7bD@><&8&+olA5F)Va7h]nP{JsZQMq@DDO!rc/?rr}kN1v0a9%KtR5D%*%.pnyZ9D]v1z6]1y(kRxh=ueY^.Ol5rbV0BE>LK2omW-2>YvsiNqxs0ZMIx?(P4qKcyn=BJV0]0&F39qX4A:o:QE}@XH>&EJ[BXia.[u%&pQ9VDCvNtW*j-rtFcn{hY2aO1s*jyR96/856X#p@DjulskQdUHwtoj}N5ZGQGH)&dq^T>bzJ}lKLcx&B8XZ.gr!QK!U@k)bkC^^M/p-vpcsc5@c/G]*]NAOeq5F#=E]*$.?kyz}Rz4^uti%!)E}Jdix6*+z5=gz00zp)OG{+u#>^]lJ1:{:}p@mM*Wz.::{R!6PcfMvmD9I{sG:14DzSKQ2AWTP+oQQP:M5{FYGhPhh7=Gwt5uql=6@yq*f2s(>hTBWpiKtg+jcCbrsiLXDq7g9.Nt&ShT(q{y:RG.LSXPwDxw3o5H6llU*byX$Cu9rF&uMNg2W.TOr#bZ#7P3^mDYvM:u5bFxdve{3&Dd?&NLzjEC]1j>xl9CuE%4O=^GNbOlc$Ew]s(1Lt]L@2PPP5CQuK/V9@ki->fL^8Kcu-}oVt1r1IKoUhfW$#IlpK6GQF]Nx%4puUClUG6dj(q6uRM2KVeO1=%DNE}iczcv}RK4B>aX)3frh7P:E>+qcn1uG0t%HYirC%fhp<0S3pJ1=3kT&z!fVIE{Z5W9fa[}K>O.qcm[>/L$lTudbl4DL%18RXz-[!iQ?&wJcMa1mJiGN^PfyxAE)nj>p4:U{?o]U:*l20JAjl<>wx0d!f=JPj{F#2PK)0FI$L%K)10h.cVzi[pr]0RFcIIcn1i!K$f8#Q)5G75sWL5]uFH$2Ytap+oKqXW6T:tOGYSmw@$#p*{%0(k@Hl.@T(cv*wm1T^A/&xMNU)h#f}WsuUu7F9b8](^M>^HhPE8&(oU%({lfdC}^q}LxPwnw}A^.ujf:#Ff?H!YkalD9fYwg7ILsIs>Y@(AQlye[WT=aLxnn6pVd7@6=@HEPtUWx+pnZ)iyfRfGB](Pv-L7W]biGdWX{^SCBSn2?0A[{mQ=1kgw37FwN=9}Pe-D]=GT<&FjmT[W0rM{-FIh-32-X<9tJqXhs8(YN)KjoB&6o%[>y>4894SZDD#i)3JJP>CH?OSl$CqvUkT{1zwt0o7Bh+!29N+4Qv--sFHJU0jr/@rWx6:F*?X^PIEwx%k42n)3]xjLIRawZne(ETjwS$Kp?Hw}M{*h9rG^(p-eTvrHy{$5)zpxGGAt{vnKwb%m5JYm7a3%=M.>egiGfd%*}}{K]=l6[9}Yg8Kv1oZI>u7/RLh{x3:Fn$C4CyA?oy+Kz0e?wVc^>4nXnJJqwrBMxuDz]hIqAA&gau=BHxG/CAyq%J@z49u0?[slu)J)u4UBWmRC9Y3y0=R{5QgoGrh@Vo:v13){ve9nUOA$ts4N1j*<4aBT-0o^LRrgit6EYzM1IP--{J.*P[W^:S(KgcbNxH)}Eaw(U^Q&Hhk5P[kRP0j{y=3HtYNAtr$t$MyqWI2n5-%rqluk]i)FkZG3bPolO=lwUk$PPV]nS-Pf?^VVW9ir0q>(5+l%{{maSwR]1Fy=y4]&wEQ!Fih(nWC+8m7TkSZQ2Jc&L*QTbYt*J@wCFjVg}EF#GmXAKfp[EhmLsIS##SfC1l&V3h:NEbw#qGEo?*6^2U3[.-TzHz9GQUtpf5%9ANB@}HWVidq$6zCAZ:u[a)V8zQ@Q4#BzkwkM$r4JZ>?mtAT8Uvh1qZ@/t1o+Ebc=)HR&8a/VtZb+]J&iFsnMPc9^OD{gmSc)F]99C7syDn0JlFM<}7JZ-?R6nAQ%rX/xcvDK=$1=lnUEI[(TP]jzji.)/yW={8Z{Ks*>z0H#kwr{0/^BFQ9Y?u!hk4y}[Yloz9hNbup$[{)c8R%+=wwoj1naQi*DDQJI4DWMVmnE[N*Wa1YO1==1ExTcVrU%P9nmWHj)40M+KgVvRu(Wk-$blW:+C)Zlo.n&S-Ru6bWsS[Lo>$78fqUpg:EdQnGb[CL[&0rX{=.X!?EuV>Qat1+6Z.!Z+(}h[8mZ$A$7(C}LOrqs{2yGH)@&w/GeHNlUSIEkbU#UL=ZLtgF+XDD-tD//^)TF.c6MZ3{S-fUI>}a4]I80Rz:HBpUvvPa>j&*14nOqq:VW0%ySGa=JI{N=n2%gXeZ(^LQslNMT)3[YriwY1S[D4Pk$9XqbrC.619*^}yWB?!Rz(03okZ52(A6vfO7E+Rqf8t?efFMOQ@FE5Uh+>Xo:QuxIpCio[+?e2/pE&6{>sv1XKn]d]?Lg5OIY0>.-Xqg}#B=rQ.kt$^M{9@o8iMC}QWeCS)xh6w%pyAl(<3bUx<8QSIdWddVhJ-j=ET&o%ICy5QSQcUAQ]2vz43%*:Qn=fw:+DDM=d0Jq<3ax^^d4=!BO2O?aoHRIOwdC<76uTMkelNCz{YH8R&ojcX}8{y44b/0)*e={*M(t?4T[EbK}a#5@^Zyfa(Q0kELZF#xIYX}hkUK@yzbx:YT)GsByV@g!Ymxq4xh7*yTM}jxXkl{j@X-7M=1P<5k[wtKi3ab#dSjnpc0NNYfXFO%:#eo.@GSRbYREwyErJS+q^@B/G{B/rOCXJ[6}n[DKU.[:AV&I3rL^}o/Fr8N5F@Tyj7uBG&R4)ZWhF=U.&dq#d>USopJ^6.AG9dszx>Sj[wQ4Z-73{xy[)$ODl&m)pJ[#Mi&h.lO+quz&^nQluZnWgsk8x.q:vHVM8o2k}C!RpkqN7kvN]-4DdNkgG]@4::Tw!YWl?YTO{gC^[IAClFFBTaA{&g!@D^o!A@UTjJRt2frPofuqMn8b68YElo%Ddo@hvg:p{Bb#P<^4{]G/)/je@]NIK?+K)M)=&c}o&bKirsW:M&3^3=O}wv#mauf/T-q7..u[+YqbTEt-]M2h0(-WuP{kHS)S?km?2adk:{*SP(&.bcC22wygU)<(QGG%>RqqytfUY7T1cfgcW^G-t8A[^N]O{1n5pWuXV5>cYJ^Z%%ws#r]xPkhSL9.1XrihaaM+11XHl{8?+XemtsK?KccM?wBGVRj}G%!J+J4{Jaz9o6uktky/SR>6y00JNm4gWsXpy8Ly7Zu-T6%.mg6V0Fg2DIn@y>j7*3Rfa?g^zp/.uk2)PwP@/FQ]/45j#bB2bao@FRG{ic<:EVAI%e/m:1TD*jBHx@PC7VK6o}NBq)wg[6D0GlYBXje=EQb:dbgCZq}9HgN(M)ZuG[R]4i.J}XPdY})Vwu-FrU?{9GAHCfna.iON1q=C+=.yUXeV7Rv)GzG7J*?U)Cm&i*ic??Fi3Gznqc+z*[aD?X:G<*UesE@H5IlpvgNg!llXs5-)l!x{(oEgd<4/G-yHWzU{+rcwQVnVVsedpRunufAjG4f)MCyRAHKC6hoDXD0cY>W}jzz)!?Gv94C4jKlQl)lr+-.7##e[7!o0J93Si@h)0K/mx7NnSR8inIg/mu08jpg4$B%8KFmDPwd:.:I3h)ZEj-ngvYfSQH8?l#f}UwL)!&=$a/3Ec6[lU>!@TmocvMhERo3k6Iw]gotZM/@:%v66kWz]sR]PU=x&D+VV>}^@vNOGC@Bi=dlN0W9sjP[I8y){sP[wrk.F-XOk{szDp]p-KZslD6+:[W$OC5=xDJ)q+modSJ%9O4lbp2>k!9ty*C6%43ITuSmMCE2=*V1H76:]Nd#J-aoNZPVlf9T7C@B:kV?xVG#64lHt$>I&:&C540{f5D6T9HGjQuqMpWyeee#>Yr.c/1&Ctt44{9gfA/}fDCtW-kb]D#Wdix?8G=>LJ.=qtoJx##%RAa{01Yx]VTm7ajuP.j5OZ:Wmwy*^M6drnJiGeSkM8-25kkE}8j9dwR?9iVhy:*mX#?JJci@qLflawOHm7r28KOoP)x2ppwpKM/T/uZkCPyq](sNn]Xz+V5A9Nj2Z@x!YYnZ7uM7*lTGnka7cSa+t}WH8eLJZo/o/{O<6l-TGwMx!&)aP(L#%?{1nZ:RPRq:Tw/vTnhsJhTkU(kWbnESa1=qRF?9{QtmA6q!ylKMOl4r?ot#6{Uq/l.b>3}7nrtwKKt+v&1^+2XZP#OyyeI48ri/mS:zopNS*AMI@Izpg.uQ7uMZxn37DQofVQ?T3v#8]lEmvG7w4$gmMYX]mpLiQCu7OiD-OQ&7%?(&{rSIFvwSED[p{B^@W!?uOo}GX:E.1Y}wCz[Bv1AuEWrIdMiJ{9Dw&)G&%RTav7i%bGc(lpErM9>])FZA85Kn4NeO)VJ?oWGtmHrzO&u0]D#mIOSo@=aeYoo+CmvX7yS-7TUnh3*e5+2%=eHwIK[+$V)&3{eAAB8hIii:.iIVtnYlA*E<4*lnIatLh#1@s^{r!oBMf#vTvv{n1DIi{.i>#?uavj=CAsQZ-UdkfXlH3ak?yBH5olpLmreX[Em!lplO6zc{Kr]8hLJVd4#>[A/LwDEzpiCe((u]%vW>F6GLkx*IzwFpM3Cp-1{eN0)vovADO4&h<[zaXJEY65q=BzKf0+K-J*P[#zp)>DHII%%A^r.=s4xS1oEBN).5[aB#w@Pti@yQda5L*OF<4EdxY39.*i:Z#hxN]H0C7>J])rqx-)$H6j5]B5RixS4DYMa3odS)V$vu=(]EkC3m2UM}6nQAu9vLfvkNFNSrEiGg-+lxxJ!Sq#UuFP/l57@WgHgcya96P(?xPc]p6zp@bA2tJuh?C[QP=V<)8%f?2S4qEUH>pvIhC{0W/[bP3yfa%#xGBVCf&0pAQTq5sF+UiQsM8{52KhK}oYG-3(ZZ-[Vd7?2BJ/*oEtVo>Hx/MUbwCOcF=#U=u*d?T}/i0hVg:Qy?Vuy.{vys5vc:Jf0uXo6!+P(+&JhDjiw?B+7{s$[9PHd69i#(p{yCQ4eD!^Ai!@6E/xKkGHj%%BOo06mAOT19:dAa@)T6nYEcMI3oZzr33s:A>z2!u!Fl!YQOPyHynVIA62#4M4a/@){JmU0{$llssF)2J49orW!mU20>A)IxR}6Ky+7Sq4w{+J5=]K4MK9@>nvI*.qNtqFt0mqF$Z4co9UX(bM}QHgkpmL+(Pp]Z?/E8-iJwc&G*]$/Ek.Nl.Ts4dGlhsfmk$2c##8UXX>ShEOtqzD]pLR!jcFyqH%@W9Z4oZ6P:DRd2bCZpqlIn<-z2bubmh]O9:#8QRu]7>H1IUX-3Y[&dm%S>(4ugyx=4&?-4oAlVR&907>v?]Q&:]N:Z:kOcjkR}4Z.O:jyc9Je]pyP?}jQtK2&-G!!-giFy+v6{vL8I>}Y:APLzUK$LFCgGOm9WPx#!B{qpU]suTVtB/#Q^oJ+gQjJoHj@aw&fOihvrR&0P?@&R==*N@PZLS:h94G&^WCC.rG7e)Li8]58E7soNu$v4NHVZpUvkSUJrWQIBQiWk$UG%N(:is+./<2xk}iJm2OUA)Nd)4P.{))]LA7w(^fzaeX<6.Rl3qce&PFVU6@Nf<&=imqCS[WiWuF=ny]d%%1tM07qGWSXrc&3ZsW=7@J(aICNkC[1W^[OC-p4DM*Z5y$5y5jv]DcWqV7WiC{Obqanl&og0vJT4QC.XC9E#mLvGy7HKB*>DsR@h/qG-S9:Lm:S=d+ci9h%a&CY>Zr4/I2AG9Ixiauwt%a74M9Y$Y@/r9@RQ5)Z4p5FHNS3[.xyU$Jm]yUs9}H(/fd!:!=:d%-#N++yG{8*CQxLhv}63C*LSf8D3?mfB{NvlZJ75EpM>rw!O$aRIx#x^}7y!p9%>E]HjM+EB3(K$le^&k-!(7K]Z+{gLm9>-ALsn/Y+*N5ijk(JVNI9Z}R&Sf+j82.DTG:}4OaCT5J9y?KJyi:3z(xpY06W0!5wL}d5IicAV19Ilc3R7Kv?%R5KPgcjHz9GLdD#?!&3f2{S:k(>An%V6F?-$-A#LAKU7]d:EFO$JK@.U*Irmc=sMmvK/UGJp-7s7*)KZP3D^[YH65eV}58rA3PzC^5.fuNc3DpFv!CXl8q2CXP3JNxO5oviTg/@d/RKIU84-G6z-YktA{Y.G7Kl?W!pPk)=Iwg%+s6@nXZHbSAY&@0e*eKsXOu(Fo:vXcE5<]*-QA!$[>r+uYsri?[^oou^5d)7XP6}?nA^}mr:HBpXt0Q*7u9rH]fsC6-0zMCEpzT>>%{gXCM4.}7}q]IoUdL=89fvxI&-pv[it8uhYc][qE58r3zYlMq4i.s:SzKU7L9RJ3lCGS!UOK([]&VWo}*0gRHk%KUA[Mq7RSLI+}[BZ*Zp5i6q$DK4HlN]wuR8jR5QF!9hA8ns8C2^gQRBf#}!Y!vBrON*+M%78l4mZF>HEMo>zF>oE?rFo-MQ0.G?HPzd(si1ThnM-er95RdPU1=WCV/@@Z&FE{q55[k1f$yv]PZ[=@T6QA=Zgw13Q.RmR(I0{=7R05JuvAi7LrrGuT8AGj1U5FcdtGxSL&SlX.oE42nB+^9h+uM]%SIL>KO@S4Wz+1O(qM3.^jZp&yBW}DY.Af9}Fl!MudSgP[.n/[6[a(y)YBG{X/v@))!VF({D!aq@Olbt]>8!.RmCfnDq<0yYP8HE]vsay3(FUs9[P53@.TuWZ(!.!2R>5yiYouT-1!rWdU7DM:Py/Ce#SBZA%7ByJYj*9y%Rg7UK&?.U%Wem1Hgg*HM&)S)pu&Gor=y&Di]AUajk7e)FeUHV8tqhFcMaLEtW#r}vWr=AI8)j}Xn#T9k}T{Yd%%mju-q1^P7k+!3Sa%cg!-guwrtl(U/RzkO@QbvFT+-@t>g%HuPxKW6-4RrnQvsUFFVQR=NT8]SLk&w$/-A/(4=A>%599r/FHKa2/B4/z<{Vhq!4qS}1=lLx@if9H[ax{lhlPGMRA^>HHA-jSjY=^)9orZ^O$A&7xxf{&9g.[7cqz&1YdOW9)Q-a+52)2&+pwPy$vrS>p0+ZMkk&HP=%sG+r3RLssAy)ck/yHexWNViRgzi}oJhMPCNU(Qb}3&TOTL$ICusl!efO}.pK%mxmnN>HKK(q:cO(TLm*xY(fBVaUsoLA&S(XNF}fxHTJ-Y(qXvZ72<=Z:TZrH@^J-:H*8x9*G/E#DboWIVRz2fr)P{mts0TIPo(MCyQz>)oG-{N/od2nE@-ULc}bdS)YzNg-0u)U={&B(s2cLqGrIjjvnWxE%[HZ:eC?s&$5VPli8f1oFNx[)8jNo%7SH5A+kqFf0Cg8G?tmt[O=)niWh$ajr9$72{6yPRukVYV/t%INx%hKzW>V[uyI5=3Kzhg(BQvNDWNiZpTTz3qb=IW0EI$PGwk7aNjHMT5x@UO9{idm]x>gkDuCN?TTl6-iuzYGS(ckLmiqd3qt4Dn/$.vg}-BF&L:pUDBd&oqDP}#)iT#fKJ=q{k*0VvuF>@SWZrBUhwc]Og+-DXfd%[G!hEIcXbtKKWo14VRE[RQOViKN3>zr1#*nerCkLovykRz2=krg2MkDu#af:6:1CzABmL)h2d&{Ulj<($g(::!ltSZ4Edu3&?>#UCXIn?8602.V}XPbNbnlO!-3-+}u?+=36L[@:*N}t/QnSabP9D*U>D@m15y+]Rw?kEGe(Mj2Ow.X.KmH@zJA%V-=sNpxErL-2ynjCxRMDTwl2i:QP1LZf{XH^7OoR=OUAzL*=5i5fqA36?$c5G<0m3C?llZs/%4&XlHUQG?4XExAVRWWcWjAdyjjRR@}}xcUh.N%3?fN2930-U=!w3hc#HNiks{de7x$=s0YeX5s4+xW@%+-+qXR[zxH>LU%EI&:n+@r18ugau>Ay}2IEwDi++%zeIdvC.BZmCEFM]H}.OHu*frs-Ovx?)SE0r$5S&<}COb/0w$r}$1+@[(Bpef1YtnKiIczr1iygxq8Q*DlLh)x0PDTVOx2@gw!yPrPqj1G}S}m@kMa@wM@>PGJb^a3DQVdP.2!NNk2iG@f-@hMWzUPm9x^&)B8-{{0GzN+}!qMhTCzWXc]K&bAalSK!o(cGJNK+-C4^sCp&25-D):eO6E2^Am[YTsW[NozgE64?NqckMK-%N&bG#V&H02vLWHEx&=j11/K:DG}cg*oH.8(XvUyypWe6ZFG)n^nv$NaFZh-i7DYoL7!Zkv1}haEpUj%n:MV6@o20}DZj6Bm/FyX26&09Y!f^aC:y7-AsfhAwSlZkn${uapL^k=f{1YBZ-IYL:wWxBYeui}HbI3RMve)AfkOy82(FCh&^LP43$+lD<@Y(VoGH:2KhW.pCOzHpiz{[yF#V.)vtqr=a6lVwjE(JAA@7a4n>txD[t{zcREQ35lhn^FZfzEl?Sfpi>qpkY]v[]dmy[CkJl:2w{WH}zo=TBxe.{ZX]Rl)7:W9)UZzh@xK/LtP=yVPU(u1@iHJM!wBxC$J)uJ@aXkmhGL:x?iKJ()%a8bpQ.hTebRF*(zmtL<2+&Erv%3IpWWg/RFEYz?rHG]?Wql[qdn=j{8)(d$*[C6P7nTv/REGZ*S>Nyn$K{m!xJp2gct!V@kS[vAR+1vYmPMDctp5zh%#H0xwqs9UXj3@*n]gGg(&j?u=d!a-jfCW#DR&EOBMu1yNq!hsYs}JY)FmqF=1%U-zmlYDAMyL)3VQ3=kWI387T*]j4[/T$G=:qe-k!F.oj[mZJ@xKWiGkz+:l@({+i}.11^Jx}ky1pmLj%a7#}>g{emy[hzrYkNv4#d0lVvm}eGnc79wQT14*Egm@Wu!voZl6Zr*%PK!Y]mi56m4FjCSBfz9C:c}#6qArIHT)T&((N}w+VB^BEx$.ium2Qo^nJQv?pY0WlU{G1MoAu&bflhW*&XtZnS7kb?-$46FH)XNJTn0!Io&H}g:7J1w5LtD5IjDRHb{4cK7O1rmhHObheqaRfdJLh3TA1D=7}cZ}C-Ti![IB1la.Vb#srRyehxz0=mZBAhLAB-UrEYl8qFZ[t8evlpweFua#2t6EWPvjb.Z<7s-AELi&egB(X[pXG$Q3M26R7b5?4z25%NT5=AbtuU6lV2oI{JHI?A/$83EwMwz-OX7azS[>7f{u{W+&nyru.:/.djauhISNCI9O&ZqeP}O-O6/?N&*C&IjDbpO6:%@]i4u/kGJWD&J6+R{w.:{vS}j@]rgB?*+U8}(!N:B:yeX2>0=@d@bkZ17J6T.b/A{{-Drm!D2V]y7saaYF@/YQojOuQB]bcTbUX9q>Bak(.wVp-<11Lu8u/<[uH:I]om-De2.m3zu&x[Q3N5Z?Y7nNMtKo:gT:PSK6?y:ZBx!0DdnlMmbWBlGUsO8uJn#SUXDdh-6(Vj{9V!Jz*+x/(R0N6Uf//KCx!7/av0JL4letPr}xVMi+i2*9LL(FEZVJ>ieMto0g&q#/S86ECl(pwrKzvlu-6*NxQiR6Vw^]fW6dSVsOJS8-W=b?*Qp9?Zaur/=$V3qZ89Ra4yu6jP->qJacc]E)cY=aQ(tVY}e@@p8dArJM.tKK&5h&7?B?R=yBJK}1%qGI:.m?s.KdL!clteNZXq7{{y1QR017dV&}^NDQ-iG75Dy&>3+qUKv.QRXusBR<))WXqS8JyF}GGCa57l=F^sLJ/OyzG=Umu%IKBDd=4[[vSyoMkFH9zfUk*a3erbU!)SM/V^aKp>!{30u5gAX#F8Xe%(}ug7*I?Cl)UY-9kgxm3:dPQ{s-!K:Cdt:n0&HO?c8rT%3))))B]0z-g$)0>xC!V@2wF!<)$]pKwd?=GHN)s2vpesy@ym8PwJ89.(l8BaT1![?x:+lwpBAv%rq3Ys^SFK&lmxHA=%Zx%YB=k6sj{Ltn*4es/?zZIp/<+nz/ih{[^H<:sw[2!uuPs>h4Bzm[fA/iTAzul{Nealo[.yAe/Pj6)$U+VKn{[L{MKnN$lxpoa74j)RXQmR&poHc4KZ6>T(o{HsbM30RP/; + + /// One element of the host tree. Trees are shipped as a flat, + /// document-ordered `list` plus a parallel `list` of parent + /// indices; `0xffffffff` (u32::MAX) marks a root with no parent. Sibling + /// relationships are derived from index contiguity. + record node { + tag: string, + id: option, + classes: list, + attributes: list, + state: node-state, + /// Layout width in CSS px, if known. Satisfies container/media queries. + width: option, + /// Layout height in CSS px, if known. + height: option, + /// Inline style declarations, as authored in the element's `style` + /// attribute (e.g. `color: red; --x: 1`). Parsed by the cascade: author + /// origin, above every stylesheet declaration of the same importance, + /// below author-`!important` rules. + style: option, + } + + /// Rendering environment consulted by `@media` evaluation. Unknown + /// dimensions are `None`; queries referencing unknown dimensions never + /// match. + record environment { + viewport-width: option, + viewport-height: option, + color-scheme: color-scheme, + /// `true` when the user prefers reduced motion. + reduced-motion: bool, + /// Device pixel ratio (1.0 default). + resolution: f32, + } + + /// Computed declaration name/value pair. + type computed-property = tuple; +} + +/// The CSS compiler/runtime boundary. +interface stylesheet { + use types.{diagnostic, origin, node, environment, computed-property}; + + /// Compiled stylesheet IR plus diagnostics. With error recovery the IR is + /// present and diagnostics may carry warnings; on fatal parse errors the + /// IR is absent. + record compiled-sheet { + ir: option>, + diagnostics: list, + } + + /// Compile CSS into versioned IR bytes. The IR is opaque to the host; + /// pass it to `prepare` to style against it. + compile: func(css: string, origin: origin) -> compiled-sheet; + + /// Decode and parse a compiled stylesheet once. Returns a handle to use + /// with `compute`; `None` when the IR is malformed or carries an + /// unsupported version. The handle stays valid until `release`; passing a + /// released or unknown handle to `compute` yields an empty result. + prepare: func(ir: list) -> option; + + /// Resolve the computed style for the node at `target`. The host supplies + /// the prepared sheets in cascade order (later wins at equal weight) plus + /// the full flat tree snapshot (nodes in document order plus parent + /// indices) and the environment. Ancestors are cascaded automatically for + /// inheritance, custom properties, and container lookups. Designed for + /// per-frame use: the parsed stylesheets are reused across calls. + compute: func( + sheets: list, + nodes: list, + parents: list, + target: u32, + env: environment, + ) -> list; + + /// Resolve computed styles for every node of the tree in one pass: nodes + /// are processed in document order, each node's cascade runs exactly once, + /// and descendants inherit computed values. Returns one entry per node, + /// index-aligned with `nodes`. This is the per-frame entry point. + compute-tree: func( + sheets: list, + nodes: list, + parents: list, + env: environment, + ) -> list>; + + /// Drop a prepared stylesheet. `sheet` may then be reused by a later + /// `prepare`. + release: func(sheet: u32); +} + +world css { + export stylesheet; +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4fc4ce0..79b38a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -228,6 +228,7 @@ importers: vitest: specifier: ^4.1.2 version: 4.1.9(@types/node@22.20.1)(vite@8.1.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)) + experiments/css: {} experiments/ghostwright: dependencies: @@ -303,7 +304,7 @@ packages: engines: {node: '>= 20.12.0'} '@clack/ui@https://pkg.pr.new/bombshell-dev/ui/@clack/ui@a60ac12': - resolution: {tarball: https://pkg.pr.new/bombshell-dev/ui/@clack/ui@a60ac12} + resolution: {tarball: https://pkg.pr.new/bombshell-dev/ui/@clack/ui@a60ac12, integrity: sha512-RuGTYiIwK+nsC7WxBdPm3636wUJtfyvzPoPWpzXkeV3KgCASLlsF3Y5ZG/UN2yWviceDHFu9Ou15JUBs3VJEjw==} version: 0.0.0 '@emnapi/core@1.10.0':