mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
This commit is contained in:
parent
1ef898ac32
commit
2557a0d253
7 changed files with 605 additions and 342 deletions
85
Cargo.lock
generated
85
Cargo.lock
generated
|
|
@ -86,9 +86,9 @@ checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.1"
|
version = "2.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
|
|
@ -119,9 +119,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.1"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compact_str"
|
name = "compact_str"
|
||||||
|
|
@ -151,9 +151,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const_panic"
|
name = "const_panic"
|
||||||
version = "0.2.12"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2459fc9262a1aa204eb4b5764ad4f189caec88aea9634389c0a25f8be7f6265e"
|
checksum = "bb8a602185c3c95b52f86dc78e55a6df9a287a7a93ddbcf012509930880cf879"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const_panic_proc_macros",
|
"const_panic_proc_macros",
|
||||||
"typewit",
|
"typewit",
|
||||||
|
|
@ -377,9 +377,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.4"
|
version = "0.15.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"equivalent",
|
"equivalent",
|
||||||
|
|
@ -486,9 +486,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.174"
|
version = "0.2.175"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
|
|
@ -504,9 +504,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litrs"
|
name = "litrs"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
|
|
@ -691,9 +691,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.95"
|
version = "1.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
@ -709,7 +709,7 @@ dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand 0.9.1",
|
"rand 0.9.2",
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"rand_xorshift",
|
"rand_xorshift",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
|
|
@ -778,9 +778,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.1"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha 0.9.0",
|
"rand_chacha 0.9.0",
|
||||||
"rand_core 0.9.3",
|
"rand_core 0.9.3",
|
||||||
|
|
@ -865,9 +865,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.13"
|
version = "0.5.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
@ -880,9 +880,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.25"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
|
|
@ -912,9 +912,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.21"
|
version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rusty-fork"
|
name = "rusty-fork"
|
||||||
|
|
@ -963,9 +963,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.5"
|
version = "1.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
@ -1018,9 +1018,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.104"
|
version = "2.0.106"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1029,15 +1029,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.20.0"
|
version = "3.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom 0.3.3",
|
"getrandom 0.3.3",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.0.8",
|
"rustix 1.0.8",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1126,18 +1126,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.12"
|
version = "2.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.12"
|
version = "2.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
@ -1146,9 +1146,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typewit"
|
name = "typewit"
|
||||||
version = "1.11.0"
|
version = "1.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb77c29baba9e4d3a6182d51fa75e3215c7fd1dab8f4ea9d107c716878e55fc0"
|
checksum = "97e72ba082eeb9da9dc68ff5a2bf727ef6ce362556e8d29ec1aed3bd05e7d86a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typewit_proc_macros",
|
"typewit_proc_macros",
|
||||||
]
|
]
|
||||||
|
|
@ -1319,6 +1319,12 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
|
|
@ -1334,7 +1340,7 @@ version = "0.60.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.53.2",
|
"windows-targets 0.53.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1355,10 +1361,11 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.53.2"
|
version = "0.53.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
"windows_aarch64_gnullvm 0.53.0",
|
"windows_aarch64_gnullvm 0.53.0",
|
||||||
"windows_aarch64_msvc 0.53.0",
|
"windows_aarch64_msvc 0.53.0",
|
||||||
"windows_i686_gnu 0.53.0",
|
"windows_i686_gnu 0.53.0",
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@
|
||||||
|
|
||||||
/// Define a trait an implement it for read-only wrapper types. */
|
/// Define a trait an implement it for read-only wrapper types. */
|
||||||
#[macro_export] macro_rules! flex_trait (
|
#[macro_export] macro_rules! flex_trait (
|
||||||
($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(+$dep2:ident)*)? {
|
($Trait:ident $(<$($A:ident:$T:ident),+>)? $(:$dep:ident $(<$dtt:tt>)? $(+$dep2:ident $(<$dtt2:tt>)?)*)? {
|
||||||
$(fn $fn:ident (&$self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)*
|
$(fn $fn:ident (&$self:ident $(, $arg:ident:$ty:ty)*) -> $ret:ty $body:block)*
|
||||||
}) => {
|
}) => {
|
||||||
pub trait $Trait $(<$($A: $T),+>)? $(:$dep$(+$dep2)*)? {
|
pub trait $Trait $(<$($A: $T),+>)? $(:$dep $(<$dtt>)? $(+$dep2 $(<$dtt2>)?)*)? {
|
||||||
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret $body)*
|
$(fn $fn (&$self $(,$arg:$ty)*) -> $ret $body)*
|
||||||
}
|
}
|
||||||
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ {
|
impl<$($($A: $T,)+)? _T_: $Trait $(<$($A),+>)?> $Trait $(<$($A),+>)? for &_T_ {
|
||||||
|
|
|
||||||
406
dsl/src/dsl.rs
406
dsl/src/dsl.rs
|
|
@ -16,9 +16,23 @@ pub(crate) use ::{
|
||||||
};
|
};
|
||||||
pub(crate) use self::DslError::*;
|
pub(crate) use self::DslError::*;
|
||||||
mod dsl_conv; pub use self::dsl_conv::*;
|
mod dsl_conv; pub use self::dsl_conv::*;
|
||||||
mod dsl_ns; pub use self::dsl_ns::*;
|
|
||||||
mod dsl_src; pub use self::dsl_src::*;
|
|
||||||
#[cfg(test)] mod dsl_test;
|
#[cfg(test)] mod dsl_test;
|
||||||
|
// Trait that designates any string-like as potentially parsable DSL.
|
||||||
|
flex_trait!(Dsl: Debug + Send + Sync + Sized {
|
||||||
|
fn src (&self) -> DslPerhaps<&str> { unreachable!("Dsl::src default impl") }
|
||||||
|
});
|
||||||
|
impl<'x> Dsl for &'x str {
|
||||||
|
fn src (&self) -> DslPerhaps<&str> { Ok(Some(self)) }
|
||||||
|
}
|
||||||
|
impl Dsl for Arc<str> {
|
||||||
|
fn src (&self) -> DslPerhaps<&str> { Ok(Some(self.as_ref())) }
|
||||||
|
}
|
||||||
|
impl<D: Dsl> Dsl for Option<D> {
|
||||||
|
fn src (&self) -> DslPerhaps<&str> {Ok(if let Some(dsl) = self { dsl.src()? } else { None })}
|
||||||
|
}
|
||||||
|
impl<D: Dsl> Dsl for Result<D, DslError> {
|
||||||
|
fn src (&self) -> DslPerhaps<&str> {match self {Ok(dsl) => Ok(dsl.src()?), Err(e) => Err(*e)}}
|
||||||
|
}
|
||||||
/// DSL-specific result type.
|
/// DSL-specific result type.
|
||||||
pub type DslResult<T> = Result<T, DslError>;
|
pub type DslResult<T> = Result<T, DslError>;
|
||||||
/// DSL-specific optional result type.
|
/// DSL-specific optional result type.
|
||||||
|
|
@ -39,27 +53,10 @@ pub enum DslError {
|
||||||
#[error("end reached")]
|
#[error("end reached")]
|
||||||
End
|
End
|
||||||
}
|
}
|
||||||
fn ok_flat <T> (x: Option<DslPerhaps<T>>) -> DslPerhaps<T> {
|
|
||||||
Ok(x.transpose()?.flatten())
|
|
||||||
}
|
|
||||||
pub const fn is_space (c: char) -> bool {
|
|
||||||
matches!(c, ' '|'\n'|'\r'|'\t')
|
|
||||||
}
|
|
||||||
pub const fn no_trailing_non_space (
|
|
||||||
src: &str, offset: usize, context: Option<&'static str>
|
|
||||||
) -> DslResult<()> {
|
|
||||||
Ok(for_each!((i, c) in char_indices(str_range(src, offset, src.len())) => if !is_space(c) {
|
|
||||||
return Err(Unexpected(c, Some(offset + i), if let Some(context) = context {
|
|
||||||
Some(context)
|
|
||||||
} else {
|
|
||||||
Some("trailing non-space")
|
|
||||||
}))
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
pub const fn peek (src: &str) -> DslPerhaps<&str> {
|
pub const fn peek (src: &str) -> DslPerhaps<&str> {
|
||||||
Ok(Some(if let Ok(Some(expr)) = expr_peek(src) { expr } else
|
Ok(Some(if let Ok(Some(expr)) = expr_peek(src) { expr } else
|
||||||
if let Ok(Some(word)) = word_peek(src) { word } else
|
if let Ok(Some(word)) = word_peek(src) { word } else
|
||||||
if let Ok(Some(num)) = num_peek(src) { num } else
|
//if let Ok(Some(num)) = num_peek(src) { num } else
|
||||||
if let Ok(Some(text)) = text_peek(src) { text } else
|
if let Ok(Some(text)) = text_peek(src) { text } else
|
||||||
if let Err(e) = no_trailing_non_space(src, 0, Some("peek")) { return Err(e) }
|
if let Err(e) = no_trailing_non_space(src, 0, Some("peek")) { return Err(e) }
|
||||||
else { return Ok(None) }))
|
else { return Ok(None) }))
|
||||||
|
|
@ -67,7 +64,7 @@ pub const fn peek (src: &str) -> DslPerhaps<&str> {
|
||||||
pub const fn seek (src: &str) -> DslPerhaps<(usize, usize)> {
|
pub const fn seek (src: &str) -> DslPerhaps<(usize, usize)> {
|
||||||
Ok(Some(if let Ok(Some(expr)) = expr_seek(src) { expr } else
|
Ok(Some(if let Ok(Some(expr)) = expr_seek(src) { expr } else
|
||||||
if let Ok(Some(word)) = word_seek(src) { word } else
|
if let Ok(Some(word)) = word_seek(src) { word } else
|
||||||
if let Ok(Some(num)) = num_seek(src) { num } else
|
//if let Ok(Some(num)) = num_seek(src) { num } else
|
||||||
if let Ok(Some(text)) = text_seek(src) { text } else
|
if let Ok(Some(text)) = text_seek(src) { text } else
|
||||||
if let Err(e) = no_trailing_non_space(src, 0, Some("seek")) { return Err(e) }
|
if let Err(e) = no_trailing_non_space(src, 0, Some("seek")) { return Err(e) }
|
||||||
else { return Ok(None) }))
|
else { return Ok(None) }))
|
||||||
|
|
@ -83,7 +80,74 @@ pub const fn peek_tail (src: &str) -> DslPerhaps<&str> {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub const fn expr_peek_inner (src: &str) -> DslPerhaps<&str> {
|
||||||
|
match expr_peek(src) {
|
||||||
|
Ok(Some(peeked)) => {
|
||||||
|
let len = peeked.len();
|
||||||
|
let start = if len > 0 { 1 } else { 0 };
|
||||||
|
Ok(Some(str_range(src, start, start + len.saturating_sub(2))))
|
||||||
|
},
|
||||||
|
e => e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn expr_peek_inner_only (src: &str) -> DslPerhaps<&str> {
|
||||||
|
match expr_seek(src) {
|
||||||
|
Err(e) => Err(e),
|
||||||
|
Ok(None) => Ok(None),
|
||||||
|
Ok(Some((start, length))) => {
|
||||||
|
if let Err(e) = no_trailing_non_space(src, start + length, Some("expr_peek_inner_only")) {
|
||||||
|
Err(e)
|
||||||
|
} else {
|
||||||
|
let peeked = str_range(src, start, start + length);
|
||||||
|
let len = peeked.len();
|
||||||
|
let start = if len > 0 { 1 } else { 0 };
|
||||||
|
Ok(Some(str_range(peeked, start, start + len.saturating_sub(2))))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const fn is_space (c: char) -> bool {
|
||||||
|
matches!(c, ' '|'\n'|'\r'|'\t')
|
||||||
|
}
|
||||||
|
pub const fn no_trailing_non_space (
|
||||||
|
src: &str, offset: usize, context: Option<&'static str>
|
||||||
|
) -> DslResult<()> {
|
||||||
|
Ok(for_each!((i, c) in char_indices(str_range(src, offset, src.len())) => if !is_space(c) {
|
||||||
|
return Err(Unexpected(c, Some(offset + i), if let Some(context) = context {
|
||||||
|
Some(context)
|
||||||
|
} else {
|
||||||
|
Some("trailing non-space")
|
||||||
|
}))
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
pub const fn is_word_char (c: char) -> bool {
|
||||||
|
matches!(c, 'a'..='z'|'A'..='Z'|'0'..='9'|'-'|'/'|'@'|':')
|
||||||
|
}
|
||||||
|
pub const fn is_word_end (c: char) -> bool { is_space(c) || is_expr_end(c) }
|
||||||
|
pub const fn is_text_start (c: char) -> bool { matches!(c, '"') }
|
||||||
|
pub const fn is_text_end (c: char) -> bool { matches!(c, '"') }
|
||||||
|
pub const fn is_expr_start (c: char) -> bool { c == '(' }
|
||||||
|
pub const fn is_expr_end (c: char) -> bool { c == ')' }
|
||||||
|
pub const fn is_digit (c: char) -> bool { matches!(c, '0'..='9') }
|
||||||
|
pub const fn to_number (digits: &str) -> Result<usize, DslError> {
|
||||||
|
let mut iter = char_indices(digits);
|
||||||
|
let mut value = 0;
|
||||||
|
while let Some(((_, c), next)) = iter.next() {
|
||||||
|
match to_digit(c) {
|
||||||
|
Ok(digit) => value = 10 * value + digit,
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
iter = next;
|
||||||
|
}
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
pub const fn to_digit (c: char) -> Result<usize, DslError> {
|
||||||
|
Ok(match c {
|
||||||
|
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
||||||
|
'5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
|
||||||
|
_ => return Err(Unexpected(c, None, Some("parse digit")))
|
||||||
|
})
|
||||||
|
}
|
||||||
#[macro_export] macro_rules! dsl_type (($T:ident { $($trait:tt)* } {
|
#[macro_export] macro_rules! dsl_type (($T:ident { $($trait:tt)* } {
|
||||||
pub const fn $peek:ident $($_1:tt)?;
|
pub const fn $peek:ident $($_1:tt)?;
|
||||||
pub const fn $peek_only:ident $($_2:tt)?;
|
pub const fn $peek_only:ident $($_2:tt)?;
|
||||||
|
|
@ -93,6 +157,20 @@ pub const fn peek_tail (src: &str) -> DslPerhaps<&str> {
|
||||||
})=>{
|
})=>{
|
||||||
pub trait $T: Dsl { $($trait)* }
|
pub trait $T: Dsl { $($trait)* }
|
||||||
impl<D: Dsl> $T for D {}
|
impl<D: Dsl> $T for D {}
|
||||||
|
pub const fn $seek_start ($source1: &str) -> DslPerhaps<usize> $body1
|
||||||
|
pub const fn $seek_length ($source2: &str) -> DslPerhaps<usize> $body2
|
||||||
|
/// Find a start and length corresponding to a syntax token.
|
||||||
|
pub const fn $seek (source: &str) -> DslPerhaps<(usize, usize)> {
|
||||||
|
match $seek_start(source) {
|
||||||
|
Err(e) => Err(e),
|
||||||
|
Ok(None) => Ok(None),
|
||||||
|
Ok(Some(start)) => match $seek_length(str_from(source, start)) {
|
||||||
|
Ok(Some(length)) => Ok(Some((start, length))),
|
||||||
|
Ok(None) => Ok(None),
|
||||||
|
Err(e) => Err(e),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Find a slice corrensponding to a syntax token.
|
/// Find a slice corrensponding to a syntax token.
|
||||||
pub const fn $peek (source: &str) -> DslPerhaps<&str> {
|
pub const fn $peek (source: &str) -> DslPerhaps<&str> {
|
||||||
match $seek(source) {
|
match $seek(source) {
|
||||||
|
|
@ -109,29 +187,53 @@ pub const fn peek_tail (src: &str) -> DslPerhaps<&str> {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
Ok(None) => Ok(None),
|
Ok(None) => Ok(None),
|
||||||
Ok(Some((start, length))) => {
|
Ok(Some((start, length))) => {
|
||||||
if let Err(e) = no_trailing_non_space(source, start + length, Some("peek_only")) { return Err(e) }
|
if let Err(e) = no_trailing_non_space(source, start + length, Some("peek_only")) {
|
||||||
Ok(Some(str_range(source, start, start + length)))
|
Err(e)
|
||||||
|
} else {
|
||||||
|
Ok(Some(str_range(source, start, start + length)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Find a start and length corresponding to a syntax token.
|
|
||||||
pub const fn $seek (source: &str) -> DslPerhaps<(usize, usize)> {
|
|
||||||
match $seek_start(source) {
|
|
||||||
Err(e) => Err(e),
|
|
||||||
Ok(None) => Ok(None),
|
|
||||||
Ok(Some(start)) => match $seek_length(str_from(source, start)) {
|
|
||||||
Ok(Some(length)) => Ok(Some((start, length))),
|
|
||||||
Ok(None) => Ok(None),
|
|
||||||
Err(e) => Err(e),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub const fn $seek_start ($source1: &str) -> DslPerhaps<usize> $body1
|
|
||||||
pub const fn $seek_length ($source2: &str) -> DslPerhaps<usize> $body2
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pub const fn is_expr_start (c: char) -> bool { c == '(' }
|
dsl_type!(DslWord {
|
||||||
pub const fn is_expr_end (c: char) -> bool { c == ')' }
|
fn word (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(word_peek_only))}
|
||||||
|
} {
|
||||||
|
pub const fn word_peek [generated];
|
||||||
|
pub const fn word_peek_only [generated];
|
||||||
|
pub const fn word_seek [generated];
|
||||||
|
pub const fn word_seek_start (src) {
|
||||||
|
for_each!((i, c) in char_indices(src) => if
|
||||||
|
is_word_char(c) { return Ok(Some(i)) } else
|
||||||
|
if !is_space(c) { return Err(Unexpected(c, Some(i), Some("word_seek_start"))) });
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
pub const fn word_seek_length (src) {
|
||||||
|
for_each!((i, c) in char_indices(src) => if !is_word_char(c) { return Ok(Some(i)) });
|
||||||
|
Ok(Some(src.len()))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
dsl_type!(DslText {
|
||||||
|
fn text (&self) -> DslPerhaps<&str> { ok_flat(self.src()?.map(text_peek_only)) }
|
||||||
|
} {
|
||||||
|
pub const fn text_peek [generated];
|
||||||
|
pub const fn text_peek_only [generated];
|
||||||
|
pub const fn text_seek [generated];
|
||||||
|
pub const fn text_seek_start (src) {
|
||||||
|
for_each!((i, c) in char_indices(src) =>
|
||||||
|
if is_text_start(c) { return Ok(Some(i)) } else
|
||||||
|
if !is_space(c) { return Err(Unexpected(c, Some(i), None)) });
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
pub const fn text_seek_length (src) {
|
||||||
|
for_each!((i, c) in char_indices(src) =>
|
||||||
|
if is_text_end(c) { return Ok(Some(i)) });
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
dsl_type!(DslExpr {
|
dsl_type!(DslExpr {
|
||||||
fn expr (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(expr_peek_inner_only))}
|
fn expr (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(expr_peek_inner_only))}
|
||||||
fn head (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(peek))}
|
fn head (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(peek))}
|
||||||
|
|
@ -172,113 +274,129 @@ dsl_type!(DslExpr {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
pub const fn expr_peek_inner (src: &str) -> DslPerhaps<&str> {
|
fn ok_flat <T> (x: Option<DslPerhaps<T>>) -> DslPerhaps<T> {
|
||||||
match expr_peek(src) {
|
Ok(x.transpose()?.flatten())
|
||||||
Ok(Some(peeked)) => {
|
|
||||||
let len = peeked.len();
|
|
||||||
let start = if len > 0 { 1 } else { 0 };
|
|
||||||
Ok(Some(str_range(src, start, start + len.saturating_sub(2))))
|
|
||||||
},
|
|
||||||
e => e
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn expr_peek_inner_only (src: &str) -> DslPerhaps<&str> {
|
/// Define a DSL namespace that provides values to words and expressions.
|
||||||
match expr_seek(src) {
|
#[macro_export] macro_rules! dsl_ns (
|
||||||
Err(e) => Err(e),
|
// Special form for numeric types
|
||||||
Ok(None) => Ok(None),
|
(num |$state:ident : $State: ty| $($($num:lifetime)? $Type:ty $(=> { $(
|
||||||
Ok(Some((start, length))) => {
|
$pat:tt => $body:expr
|
||||||
if let Err(e) = no_trailing_non_space(src, start + length, Some("expr_peek_inner_only")) { return Err(e) }
|
),* $(,)? })?;)+) => {
|
||||||
let peeked = str_range(src, start, start + length);
|
$(dsl_ns!(num |$state: $State| -> $($num)? $Type { $( $($pat => $body),* )? });)+
|
||||||
let len = peeked.len();
|
};
|
||||||
let start = if len > 0 { 1 } else { 0 };
|
// Special form for numeric types
|
||||||
Ok(Some(str_range(peeked, start, start + len.saturating_sub(2))))
|
(num |$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => {
|
||||||
},
|
impl<'t> DslNs<'t, $Type> for $State {
|
||||||
}
|
const WORDS: DslNsMap<'t, fn (&'t $State)->Perhaps<$Type>> =
|
||||||
}
|
DslNsMap::new(&[$(dsl_ns!{@word ($state: $State) -> $Type { $pat => $body }}),*]);
|
||||||
|
const EXPRS: DslNsMap<'t, fn (&'t $State, &str)->Perhaps<$Type>> =
|
||||||
pub const fn is_word_char (c: char) -> bool {
|
DslNsMap::new(&[$(dsl_ns!{@exp ($state: $State) -> $Type { $pat => $body }}),*]);
|
||||||
matches!(c, 'a'..='z'|'A'..='Z'|'0'..='9'|'-'|'/'|'@'|':')
|
fn from <D: Dsl> (&'t self, dsl: D) -> Perhaps<$Type> {
|
||||||
}
|
if let Ok(Some(src)) = dsl.src() {
|
||||||
pub const fn is_word_end (c: char) -> bool {
|
if let Ok(num) = to_number(src) {
|
||||||
is_space(c) || is_expr_end(c)
|
Ok(Some(num as $Type))
|
||||||
}
|
} else if let Ok(Some(src)) = src.word() {
|
||||||
dsl_type!(DslWord {
|
self.from_word(src)
|
||||||
fn word (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(word_peek_only))}
|
} else {
|
||||||
} {
|
self.from_expr(src)
|
||||||
pub const fn word_peek [generated];
|
}
|
||||||
pub const fn word_peek_only [generated];
|
} else {
|
||||||
pub const fn word_seek [generated];
|
Ok(None)
|
||||||
pub const fn word_seek_start (src) {
|
}
|
||||||
for_each!((i, c) in char_indices(src) => if
|
}
|
||||||
is_word_char(c) { return Ok(Some(i)) } else
|
}
|
||||||
if !is_space(c) { return Err(Unexpected(c, Some(i), Some("word_seek_start"))) });
|
};
|
||||||
Ok(None)
|
// A namespace may resolve one or more types.
|
||||||
}
|
(|$state:ident : $State: ty| $($Type:ty $(=> { $( $pat:tt => $body:expr ),* $(,)? })? ;)+) => {
|
||||||
pub const fn word_seek_length (src) {
|
$(dsl_ns!(|$state: $State| -> $Type { $( $($pat => $body),* )? });)+
|
||||||
for_each!((i, c) in char_indices(src) => if !is_word_char(c) { return Ok(Some(i)) });
|
};
|
||||||
Ok(Some(src.len()))
|
// Regular form for single type
|
||||||
}
|
(|$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => {
|
||||||
});
|
impl<'t> DslNs<'t, $Type> for $State {
|
||||||
|
const WORDS: DslNsMap<'t, fn (&'t $State)->Perhaps<$Type>> =
|
||||||
pub const fn is_text_start (c: char) -> bool { matches!(c, '"') }
|
DslNsMap::new(&[$(dsl_ns!{@word ($state: $State) -> $Type { $pat => $body }}),*]);
|
||||||
pub const fn is_text_end (c: char) -> bool { matches!(c, '"') }
|
const EXPRS: DslNsMap<'t, fn (&'t $State, &str)->Perhaps<$Type>> =
|
||||||
dsl_type!(DslText {
|
DslNsMap::new(&[$(dsl_ns!{@exp ($state: $State) -> $Type { $pat => $body }}),*]);
|
||||||
fn text (&self) -> DslPerhaps<&str> { ok_flat(self.src()?.map(text_peek_only)) }
|
}
|
||||||
} {
|
};
|
||||||
pub const fn text_peek [generated];
|
// Symbols only.
|
||||||
pub const fn text_peek_only [generated];
|
(@word ($state:ident: $State:ty) -> $Type:ty {
|
||||||
pub const fn text_seek [generated];
|
$word:literal => $body:expr
|
||||||
pub const fn text_seek_start (src) {
|
}) => {
|
||||||
for_each!((i, c) in char_indices(src) =>
|
($word, |$state|Ok(Some($body)))
|
||||||
if is_text_start(c) { return Ok(Some(i)) } else
|
};
|
||||||
if !is_space(c) { return Err(Unexpected(c, Some(i), None)) });
|
// Expression handlers only.
|
||||||
Ok(None)
|
(@exp ($state:ident: $State:ty) -> $Type:ty {
|
||||||
}
|
($head:literal $(,$arg:ident:$ty:ty)* $(,)*) => $body:expr
|
||||||
pub const fn text_seek_length (src) {
|
}) => { ($head, |$state, tail: &str|{
|
||||||
for_each!((i, c) in char_indices(src) =>
|
$(
|
||||||
if is_text_end(c) { return Ok(Some(i)) });
|
let head = tail.head()?.unwrap_or_default();
|
||||||
Ok(None)
|
let tail = tail.tail()?.unwrap_or_default();
|
||||||
}
|
let $arg: $ty = if let Some(arg) = $state.from(&head)? {
|
||||||
});
|
arg
|
||||||
|
} else {
|
||||||
dsl_type!(DslNum {
|
return Err(format!("{}: missing argument: {} ({}); got: {tail}",
|
||||||
fn num (&self) -> DslPerhaps<&str> {ok_flat(self.src()?.map(num_peek_only))}
|
$head,
|
||||||
} {
|
stringify!($arg),
|
||||||
pub const fn num_peek [generated];
|
stringify!($Type),
|
||||||
pub const fn num_peek_only [generated];
|
).into())
|
||||||
pub const fn num_seek [generated];
|
};
|
||||||
pub const fn num_seek_start (src) {
|
)*
|
||||||
for_each!((i, c) in char_indices(src) =>
|
Ok(Some($body))
|
||||||
if is_digit(c) { return Ok(Some(i)); } else
|
}) };
|
||||||
if !is_space(c) { return Err(Unexpected(c, Some(i), None)) });
|
// Nothing else in symbols.
|
||||||
Ok(None)
|
(@word ($state:ident: $State:ty) -> $Type:ty { $pat:tt => $body:expr }) => {
|
||||||
}
|
("", |_|Ok(None)) // FIXME don't emit at all
|
||||||
pub const fn num_seek_length (src) {
|
};
|
||||||
for_each!((i, c) in char_indices(src) =>
|
// Nothing else in expression handlers.
|
||||||
if is_num_end(c) { return Ok(Some(i)) } else
|
(@exp ($state:ident: $State:ty) -> $Type:ty { $pat:tt => $body:expr }) => {
|
||||||
if !is_digit(c) { return Err(Unexpected(c, Some(i), None)) });
|
("", |_, _|Ok(None)) // FIXME don't emit at all
|
||||||
Ok(None)
|
};
|
||||||
}
|
);
|
||||||
});
|
|
||||||
pub const fn is_digit (c: char) -> bool { matches!(c, '0'..='9') }
|
pub trait DslNs<'t, T: 't>: 't {
|
||||||
pub const fn is_num_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') }
|
/// Known symbols.
|
||||||
pub const fn to_number (digits: &str) -> Result<usize, DslError> {
|
const WORDS: DslNsMap<'t, fn (&'t Self)->Perhaps<T>> = DslNsMap::new(&[]);
|
||||||
let mut iter = char_indices(digits);
|
/// Known expressions.
|
||||||
let mut value = 0;
|
const EXPRS: DslNsMap<'t, fn (&'t Self, &str)->Perhaps<T>> = DslNsMap::new(&[]);
|
||||||
while let Some(((_, c), next)) = iter.next() {
|
/// Resolve an expression or symbol.
|
||||||
match to_digit(c) {
|
fn from <D: Dsl> (&'t self, dsl: D) -> Perhaps<T> {
|
||||||
Ok(digit) => value = 10 * value + digit,
|
if let Ok(Some(src)) = dsl.src() {
|
||||||
Err(e) => return Err(e),
|
if let Ok(Some(src)) = src.word() {
|
||||||
|
self.from_word(src)
|
||||||
|
} else {
|
||||||
|
self.from_expr(src)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
iter = next;
|
|
||||||
}
|
}
|
||||||
Ok(value)
|
/// Resolve a symbol if known.
|
||||||
|
fn from_word <D: Dsl> (&'t self, dsl: D) -> Perhaps<T> {
|
||||||
|
if let Some(dsl) = dsl.word()? {
|
||||||
|
for (word, get) in Self::WORDS.0 { if dsl == *word { return get(self) } }
|
||||||
|
}
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
|
/// Resolve an expression if known.
|
||||||
|
fn from_expr <D: Dsl> (&'t self, dsl: D) -> Perhaps<T> {
|
||||||
|
if let Some(head) = dsl.expr().head()? {
|
||||||
|
for (key, value) in Self::EXPRS.0.iter() {
|
||||||
|
if head == *key {
|
||||||
|
return value(self, dsl.expr().tail()?.unwrap_or(""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub const fn to_digit (c: char) -> Result<usize, DslError> {
|
|
||||||
Ok(match c {
|
/// Namespace mapping.
|
||||||
'0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4,
|
#[derive(Debug)]
|
||||||
'5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9,
|
pub struct DslNsMap<'t, T: Debug + 't>(pub &'t [(&'t str, T)]);
|
||||||
_ => return Err(Unexpected(c, None, Some("parse digit")))
|
impl<'t, T: Debug + 't> DslNsMap<'t, T> {
|
||||||
})
|
/// Populate a namespace with pre-existing values.
|
||||||
|
pub const fn new (data: &'t [(&'t str, T)]) -> Self { Self(data) /* TODO a search trie */ }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
/// Define a namespace:
|
|
||||||
#[macro_export] macro_rules! dsl_ns (
|
|
||||||
// Special form for numeric types
|
|
||||||
(num |$state:ident : $State: ty| $($($num:lifetime)? $Type:ty $(=> { $(
|
|
||||||
$pat:tt => $body:expr
|
|
||||||
),* $(,)? })?;)+) => {
|
|
||||||
$(dsl_ns!(num |$state: $State| -> $($num)? $Type { $( $($pat => $body),* )? });)+
|
|
||||||
};
|
|
||||||
// Special form for numeric types
|
|
||||||
(num |$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => {
|
|
||||||
impl<'t> DslNs<'t, $Type> for $State {
|
|
||||||
const WORDS: DslNsMap<'t, fn (&'t $State)->Perhaps<$Type>> =
|
|
||||||
DslNsMap::new(&[$(dsl_ns!{@word ($state: $State) -> $Type { $pat => $body }}),*]);
|
|
||||||
const EXPRS: DslNsMap<'t, fn (&'t $State, &str)->Perhaps<$Type>> =
|
|
||||||
DslNsMap::new(&[$(dsl_ns!{@exp ($state: $State) -> $Type { $pat => $body }}),*]);
|
|
||||||
fn from <D: Dsl> (&'t self, dsl: D) -> Perhaps<$Type> {
|
|
||||||
if let Ok(Some(src)) = dsl.src() {
|
|
||||||
if let Ok(num) = to_number(src) {
|
|
||||||
Ok(Some(num as $Type))
|
|
||||||
} else if let Ok(Some(src)) = src.word() {
|
|
||||||
self.from_word(src)
|
|
||||||
} else {
|
|
||||||
self.from_expr(src)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// A namespace may resolve one or more types.
|
|
||||||
(|$state:ident : $State: ty| $($Type:ty $(=> { $( $pat:tt => $body:expr ),* $(,)? })? ;)+) => {
|
|
||||||
$(dsl_ns!(|$state: $State| -> $Type { $( $($pat => $body),* )? });)+
|
|
||||||
};
|
|
||||||
// Regular form for single type
|
|
||||||
(|$state:ident : $State: ty| -> $Type:ty { $( $pat:tt => $body:expr ),* $(,)? }) => {
|
|
||||||
impl<'t> DslNs<'t, $Type> for $State {
|
|
||||||
const WORDS: DslNsMap<'t, fn (&'t $State)->Perhaps<$Type>> =
|
|
||||||
DslNsMap::new(&[$(dsl_ns!{@word ($state: $State) -> $Type { $pat => $body }}),*]);
|
|
||||||
const EXPRS: DslNsMap<'t, fn (&'t $State, &str)->Perhaps<$Type>> =
|
|
||||||
DslNsMap::new(&[$(dsl_ns!{@exp ($state: $State) -> $Type { $pat => $body }}),*]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Symbols only.
|
|
||||||
(@word ($state:ident: $State:ty) -> $Type:ty {
|
|
||||||
$word:literal => $body:expr
|
|
||||||
}) => {
|
|
||||||
($word, |$state|Ok(Some($body)))
|
|
||||||
};
|
|
||||||
// Expression handlers only.
|
|
||||||
(@exp ($state:ident: $State:ty) -> $Type:ty {
|
|
||||||
($head:literal $(,$arg:ident:$ty:ty)* $(,)*) => $body:expr
|
|
||||||
}) => { ($head, |$state, tail: &str|{
|
|
||||||
$(
|
|
||||||
let head = tail.head()?.unwrap_or_default();
|
|
||||||
let tail = tail.tail()?.unwrap_or_default();
|
|
||||||
let $arg: $ty = if let Some(arg) = $state.from(&head)? {
|
|
||||||
arg
|
|
||||||
} else {
|
|
||||||
return Err(format!("{}: missing argument: {} ({}); got: {tail}",
|
|
||||||
$head,
|
|
||||||
stringify!($arg),
|
|
||||||
stringify!($Type),
|
|
||||||
).into())
|
|
||||||
};
|
|
||||||
)*
|
|
||||||
Ok(Some($body))
|
|
||||||
}) };
|
|
||||||
// Nothing else in symbols.
|
|
||||||
(@word ($state:ident: $State:ty) -> $Type:ty { $pat:tt => $body:expr }) => {
|
|
||||||
("", |_|Ok(None)) // FIXME don't emit at all
|
|
||||||
};
|
|
||||||
// Nothing else in expression handlers.
|
|
||||||
(@exp ($state:ident: $State:ty) -> $Type:ty { $pat:tt => $body:expr }) => {
|
|
||||||
("", |_, _|Ok(None)) // FIXME don't emit at all
|
|
||||||
};
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
pub trait DslNs<'t, T: 't>: 't {
|
|
||||||
/// Resolve an expression or symbol.
|
|
||||||
fn from <D: Dsl> (&'t self, dsl: D) -> Perhaps<T> {
|
|
||||||
if let Ok(Some(src)) = dsl.src() {
|
|
||||||
if let Ok(Some(src)) = src.word() {
|
|
||||||
self.from_word(src)
|
|
||||||
} else {
|
|
||||||
self.from_expr(src)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Resolve a symbol if known.
|
|
||||||
fn from_word <D: Dsl> (&'t self, dsl: D) -> Perhaps<T> {
|
|
||||||
if let Some(dsl) = dsl.word()? {
|
|
||||||
for (word, get) in Self::WORDS.0 { if dsl == *word { return get(self) } }
|
|
||||||
}
|
|
||||||
return Ok(None)
|
|
||||||
}
|
|
||||||
/// Resolve an expression if known.
|
|
||||||
fn from_expr <D: Dsl> (&'t self, dsl: D) -> Perhaps<T> {
|
|
||||||
if let Some(head) = dsl.expr().head()? {
|
|
||||||
for (key, value) in Self::EXPRS.0.iter() {
|
|
||||||
if head == *key {
|
|
||||||
return value(self, dsl.expr().tail()?.unwrap_or(""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(None)
|
|
||||||
}
|
|
||||||
/// Known symbols.
|
|
||||||
const WORDS: DslNsMap<'t, fn (&'t Self)->Perhaps<T>> = DslNsMap::new(&[]);
|
|
||||||
/// Known expressions.
|
|
||||||
const EXPRS: DslNsMap<'t, fn (&'t Self, &str)->Perhaps<T>> = DslNsMap::new(&[]);
|
|
||||||
}
|
|
||||||
/// Namespace mapping.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DslNsMap<'t, T: Debug + 't>(pub &'t [(&'t str, T)]);
|
|
||||||
impl<'t, T: Debug + 't> DslNsMap<'t, T> {
|
|
||||||
/// Populate a namespace.
|
|
||||||
pub const fn new (data: &'t [(&'t str, T)]) -> Self {
|
|
||||||
Self(data) // TODO build search index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
// Designates a string as parsable DSL.
|
|
||||||
flex_trait!(Dsl: Debug + Send + Sync + Sized {
|
|
||||||
fn src (&self) -> DslPerhaps<&str> { unreachable!("Dsl::src default impl") }
|
|
||||||
});
|
|
||||||
// Some things that can be DSL source:
|
|
||||||
impl Dsl for String {
|
|
||||||
fn src (&self) -> DslPerhaps<&str> { Ok(Some(self.as_ref())) }
|
|
||||||
}
|
|
||||||
impl Dsl for Arc<str> {
|
|
||||||
fn src (&self) -> DslPerhaps<&str> { Ok(Some(self.as_ref())) }
|
|
||||||
}
|
|
||||||
impl<'s> Dsl for &'s str {
|
|
||||||
fn src (&self) -> DslPerhaps<&str> { Ok(Some(self.as_ref())) }
|
|
||||||
}
|
|
||||||
impl<D: Dsl> Dsl for Option<D> {
|
|
||||||
fn src (&self) -> DslPerhaps<&str> {Ok(if let Some(dsl) = self { dsl.src()? } else { None })}
|
|
||||||
}
|
|
||||||
impl<D: Dsl> Dsl for Result<D, DslError> {
|
|
||||||
fn src (&self) -> DslPerhaps<&str> {match self {Ok(dsl) => Ok(dsl.src()?), Err(e) => Err(*e)}}
|
|
||||||
}
|
|
||||||
|
|
@ -96,17 +96,18 @@ impl ExposeImpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if is_num(&type_is) {
|
} else if is_num(&type_is) {
|
||||||
quote! {
|
quote! {}
|
||||||
/// Generated by [tengri_proc::expose].
|
//quote! {
|
||||||
impl ::tengri::dsl::FromDsl<#state> for #t {
|
///// Generated by [tengri_proc::expose].
|
||||||
fn from_dsl (state: &#state, dsl: &impl Dsl) -> Perhaps<Self> {
|
//impl ::tengri::dsl::FromDsl<#state> for #t {
|
||||||
match dsl.num()? {
|
//fn from_dsl (state: &#state, dsl: &impl Dsl) -> Perhaps<Self> {
|
||||||
Some(n) => Ok(Some(n.parse::<#t>()?)),
|
//match dsl.num()? {
|
||||||
_ => match dsl.word()? { #(#variants)* _ => Ok(None) }
|
//Some(n) => Ok(Some(n.parse::<#t>()?)),
|
||||||
}
|
//_ => match dsl.word()? { #(#variants)* _ => Ok(None) }
|
||||||
}
|
//}
|
||||||
}
|
//}
|
||||||
}
|
//}
|
||||||
|
//}
|
||||||
} else {
|
} else {
|
||||||
quote! {
|
quote! {
|
||||||
/// Generated by [tengri_proc::expose].
|
/// Generated by [tengri_proc::expose].
|
||||||
|
|
|
||||||
283
tengri.svg
Normal file
283
tengri.svg
Normal file
|
|
@ -0,0 +1,283 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg width="100%" height="100%" viewBox="0 0 1000 600" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||||
|
<stop offset="0%" style="stop-color:#4CAF50;stop-opacity:1" />
|
||||||
|
<stop offset="100%" style="stop-color:#2196F3;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
||||||
|
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-color="#000000" flood-opacity="0.3"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<!-- Background -->
|
||||||
|
<rect width="1000" height="600" fill="#1a1a1a"/>
|
||||||
|
|
||||||
|
<!-- Title -->
|
||||||
|
<text x="500" y="50" text-anchor="middle" font-family="Arial, sans-serif" font-size="28" font-weight="bold" fill="#ffffff">
|
||||||
|
Daily Timestamp Heatmap
|
||||||
|
</text>
|
||||||
|
|
||||||
|
<!-- Chart area -->
|
||||||
|
<rect x="80" y="80" width="840" height="440" fill="#2d2d2d" stroke="#404040" stroke-width="2" rx="8"/>
|
||||||
|
|
||||||
|
<!-- Y-axis (hours) -->
|
||||||
|
<line x1="80" y1="80" x2="80" y2="520" stroke="#666" stroke-width="2"/>
|
||||||
|
|
||||||
|
<!-- X-axis (timeline) -->
|
||||||
|
<line x1="80" y1="520" x2="920" y2="520" stroke="#666" stroke-width="2"/>
|
||||||
|
|
||||||
|
<!-- Monday highlight for 03/03 -->
|
||||||
|
<rect x="84" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="84" y1="80" x2="84" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 03/10 -->
|
||||||
|
<rect x="119" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="119" y1="80" x2="119" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 03/17 -->
|
||||||
|
<rect x="153" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="153" y1="80" x2="153" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 03/24 -->
|
||||||
|
<rect x="187" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="187" y1="80" x2="187" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 03/31 -->
|
||||||
|
<rect x="221" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="221" y1="80" x2="221" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 04/07 -->
|
||||||
|
<rect x="255" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="255" y1="80" x2="255" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 04/14 -->
|
||||||
|
<rect x="290" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="290" y1="80" x2="290" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 04/21 -->
|
||||||
|
<rect x="324" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="324" y1="80" x2="324" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 04/28 -->
|
||||||
|
<rect x="358" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="358" y1="80" x2="358" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 05/05 -->
|
||||||
|
<rect x="392" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="392" y1="80" x2="392" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 05/12 -->
|
||||||
|
<rect x="426" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="426" y1="80" x2="426" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 05/19 -->
|
||||||
|
<rect x="460" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="460" y1="80" x2="460" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 05/26 -->
|
||||||
|
<rect x="495" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="495" y1="80" x2="495" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 06/02 -->
|
||||||
|
<rect x="529" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="529" y1="80" x2="529" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 06/09 -->
|
||||||
|
<rect x="563" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="563" y1="80" x2="563" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 06/16 -->
|
||||||
|
<rect x="597" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="597" y1="80" x2="597" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 06/23 -->
|
||||||
|
<rect x="631" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="631" y1="80" x2="631" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 06/30 -->
|
||||||
|
<rect x="666" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="666" y1="80" x2="666" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 07/07 -->
|
||||||
|
<rect x="700" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="700" y1="80" x2="700" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 07/14 -->
|
||||||
|
<rect x="734" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="734" y1="80" x2="734" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 07/21 -->
|
||||||
|
<rect x="768" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="768" y1="80" x2="768" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 07/28 -->
|
||||||
|
<rect x="802" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="802" y1="80" x2="802" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 08/04 -->
|
||||||
|
<rect x="836" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="836" y1="80" x2="836" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 08/11 -->
|
||||||
|
<rect x="871" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="871" y1="80" x2="871" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<!-- Monday highlight for 08/18 -->
|
||||||
|
<rect x="905" y="80" width="4" height="440" fill="#3a3a3a" opacity="0.3"/>
|
||||||
|
<line x1="905" y1="80" x2="905" y2="520" stroke="#4a9eff" stroke-width="2" opacity="0.8"/>
|
||||||
|
<text x="65" y="89" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">23:00</text>
|
||||||
|
<text x="65" y="107" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">22:00</text>
|
||||||
|
<text x="65" y="125" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">21:00</text>
|
||||||
|
<text x="65" y="144" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">20:00</text>
|
||||||
|
<text x="65" y="162" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">19:00</text>
|
||||||
|
<text x="65" y="180" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">18:00</text>
|
||||||
|
<text x="65" y="199" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">17:00</text>
|
||||||
|
<text x="65" y="217" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">16:00</text>
|
||||||
|
<text x="65" y="235" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">15:00</text>
|
||||||
|
<text x="65" y="254" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">14:00</text>
|
||||||
|
<text x="65" y="272" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">13:00</text>
|
||||||
|
<text x="65" y="290" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">12:00</text>
|
||||||
|
<text x="65" y="309" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">11:00</text>
|
||||||
|
<text x="65" y="327" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">10:00</text>
|
||||||
|
<text x="65" y="345" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">9:00</text>
|
||||||
|
<text x="65" y="364" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">8:00</text>
|
||||||
|
<text x="65" y="382" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">7:00</text>
|
||||||
|
<text x="65" y="400" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">6:00</text>
|
||||||
|
<text x="65" y="419" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">5:00</text>
|
||||||
|
<text x="65" y="437" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">4:00</text>
|
||||||
|
<text x="65" y="455" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">3:00</text>
|
||||||
|
<text x="65" y="474" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">2:00</text>
|
||||||
|
<text x="65" y="492" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">1:00</text>
|
||||||
|
<text x="65" y="510" text-anchor="end" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">0:00</text>
|
||||||
|
<text x="80" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">03/02</text>
|
||||||
|
<text x="114" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">03/09</text>
|
||||||
|
<text x="148" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">03/16</text>
|
||||||
|
<text x="182" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">03/23</text>
|
||||||
|
<text x="216" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">03/30</text>
|
||||||
|
<text x="250" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">04/06</text>
|
||||||
|
<text x="285" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">04/13</text>
|
||||||
|
<text x="319" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">04/20</text>
|
||||||
|
<text x="353" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">04/27</text>
|
||||||
|
<text x="387" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">05/04</text>
|
||||||
|
<text x="421" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">05/11</text>
|
||||||
|
<text x="456" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">05/18</text>
|
||||||
|
<text x="490" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">05/25</text>
|
||||||
|
<text x="524" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">06/01</text>
|
||||||
|
<text x="558" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">06/08</text>
|
||||||
|
<text x="592" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">06/15</text>
|
||||||
|
<text x="626" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">06/22</text>
|
||||||
|
<text x="661" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">06/29</text>
|
||||||
|
<text x="695" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">07/06</text>
|
||||||
|
<text x="729" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">07/13</text>
|
||||||
|
<text x="763" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">07/20</text>
|
||||||
|
<text x="797" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">07/27</text>
|
||||||
|
<text x="832" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">08/03</text>
|
||||||
|
<text x="866" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">08/10</text>
|
||||||
|
<text x="900" y="550" text-anchor="middle" font-family="Arial, sans-serif" font-size="14" fill="#ffffff">08/17</text>
|
||||||
|
<rect x="80" y="391" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="84" y="98" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="89" y="446" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="114" y="300" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="114" y="355" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="138" y="501" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="148" y="80" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="148" y="501" width="4" height="18" fill="#ff6b6b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="153" y="98" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="182" y="135" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="182" y="465" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="236" y="80" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="236" y="98" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="241" y="446" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="246" y="410" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="285" y="446" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="285" y="465" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="290" y="410" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="299" y="116" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="304" y="318" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="309" y="355" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="329" y="355" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="338" y="318" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="338" y="336" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="338" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="338" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="343" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="343" y="465" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="348" y="98" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="348" y="116" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="348" y="373" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="348" y="465" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="353" y="153" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="353" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="358" y="501" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="368" y="465" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="368" y="501" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="377" y="116" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="377" y="391" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="377" y="410" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="377" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="387" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="392" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="397" y="300" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="397" y="336" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="397" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="402" y="318" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="402" y="391" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="402" y="410" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="407" y="98" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="407" y="410" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="407" y="446" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="407" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="412" y="355" width="4" height="18" fill="#ff6b6b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="412" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="412" y="446" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="412" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="412" y="483" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="412" y="501" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="431" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="431" y="336" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="431" y="391" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="431" y="446" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="436" y="483" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="441" y="501" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="446" y="171" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="446" y="263" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="446" y="391" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="451" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="451" y="410" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="451" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="451" y="446" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="451" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="456" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="456" y="116" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="460" y="373" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="460" y="410" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="98" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="116" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="318" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="336" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="355" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="465" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="480" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="480" y="465" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="485" y="281" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="485" y="501" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="490" y="98" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="490" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="495" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="495" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="495" y="501" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="553" y="153" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="578" y="281" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="578" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="578" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="583" y="373" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="617" y="318" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="622" y="245" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="734" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="734" y="501" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="739" y="80" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="744" y="410" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="749" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="753" y="208" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="753" y="226" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="758" y="135" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="758" y="153" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="758" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="802" y="336" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="802" y="391" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="807" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="817" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="817" y="483" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="827" y="98" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="832" y="355" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="832" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="832" y="465" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="861" y="98" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="861" y="336" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="861" y="391" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="866" y="465" width="4" height="18" fill="#ffa726" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="871" y="318" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="890" y="300" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="890" y="373" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="890" y="465" width="4" height="18" fill="#ffeb3b" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="900" y="428" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
<rect x="920" y="135" width="4" height="18" fill="#66bb6a" opacity="0.9" stroke="#404040" stroke-width="0.5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 26 KiB |
Loading…
Add table
Add a link
Reference in a new issue