mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-07 04:06:48 +01:00
core, input, output, dsl: factor away 'flexi' traits
This commit is contained in:
parent
8cbd7dd8e8
commit
9f7d0efda5
11 changed files with 355 additions and 339 deletions
183
dsl/src/dsl_parse.rs
Normal file
183
dsl/src/dsl_parse.rs
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
use crate::*;
|
||||
|
||||
macro_rules! iter_chars(($source:expr => |$i:ident, $c:ident|$val:expr)=>{
|
||||
while let Some((($i, $c), next)) = char_indices($source).next() {
|
||||
$source = next.as_str(); $val } });
|
||||
|
||||
macro_rules! def_peek_seek(($peek:ident, $seek:ident, $seek_start:ident, $seek_length:ident)=>{
|
||||
/// Find a slice corrensponding to a syntax token.
|
||||
pub const fn $peek (source: &str) -> DslPerhaps<&str> {
|
||||
match $seek(source) {
|
||||
Ok(Some((start, length))) => Ok(Some(str_range(source, start, start + length))),
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e) } }
|
||||
/// Find a start and length corresponding to a syntax token.
|
||||
pub const fn $seek (source: &str) -> DslPerhaps<(usize, usize)> {
|
||||
match $seek_start(source) {
|
||||
Ok(Some(start)) => match $seek_length(str_range(source, start, source.len() - start)) {
|
||||
Ok(Some(length)) => Ok(Some((start, length))),
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e),
|
||||
},
|
||||
Ok(None) => Ok(None),
|
||||
Err(e) => Err(e) } } });
|
||||
|
||||
def_peek_seek!(exp_peek, exp_seek, exp_seek_start, exp_seek_length);
|
||||
pub const fn is_exp_start (c: char) -> bool { matches!(c, '(') }
|
||||
pub const fn is_exp_end (c: char) -> bool { matches!(c, ')') }
|
||||
pub const fn exp_seek_start (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_exp_start(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
pub const fn exp_seek_length (mut source: &str) -> DslPerhaps<usize> {
|
||||
let mut depth = 0;
|
||||
iter_chars!(source => |i, c| if is_exp_start(c) {
|
||||
depth += 1;
|
||||
} else if is_exp_end(c) {
|
||||
if depth == 0 {
|
||||
return Err(Unexpected(c))
|
||||
} else if depth == 1 {
|
||||
return Ok(Some(i))
|
||||
} else {
|
||||
depth -= 1;
|
||||
}
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
def_peek_seek!(sym_peek, sym_seek, sym_seek_start, sym_seek_length);
|
||||
pub const fn is_sym_start (c: char) -> bool { matches!(c, ':'|'@') }
|
||||
pub const fn is_sym_char (c: char) -> bool { matches!(c, 'a'..='z'|'A'..='Z'|'0'..='9'|'-') }
|
||||
pub const fn is_sym_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') }
|
||||
pub const fn sym_seek_start (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_sym_start(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
pub const fn sym_seek_length (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_sym_end(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_sym_char(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
def_peek_seek!(key_peek, key_seek, key_seek_start, key_seek_length);
|
||||
pub const fn is_key_start (c: char) -> bool { matches!(c, '/'|'a'..='z') }
|
||||
pub const fn is_key_char (c: char) -> bool { matches!(c, 'a'..='z'|'0'..='9'|'-'|'/') }
|
||||
pub const fn is_key_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') }
|
||||
pub const fn key_seek_start (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_key_start(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
pub const fn key_seek_length (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_key_end(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_key_char(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
def_peek_seek!(text_peek, text_seek, text_seek_start, text_seek_length);
|
||||
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 text_seek_start (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_text_start(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
pub const fn text_seek_length (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_text_end(c) { return Ok(Some(i)) });
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
def_peek_seek!(num_peek, num_seek, num_seek_start, num_seek_length);
|
||||
pub const fn num_seek_start (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_digit(c) {
|
||||
return Ok(Some(i));
|
||||
} else if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
pub const fn num_seek_length (mut source: &str) -> DslPerhaps<usize> {
|
||||
iter_chars!(source => |i, c| if is_num_end(c) {
|
||||
return Ok(Some(i))
|
||||
} else if !is_digit(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
pub const fn is_digit (c: char) -> bool { matches!(c, '0'..='9') }
|
||||
pub const fn is_num_end (c: char) -> bool { matches!(c, ' '|'\n'|'\r'|'\t'|')') }
|
||||
pub const fn to_number <D: Dsl> (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))
|
||||
})
|
||||
}
|
||||
|
||||
pub const fn peek (mut src: &str) -> DslPerhaps<&str> {
|
||||
Ok(Some(match () {
|
||||
_ if let Ok(Some(exp)) = exp_peek(src) => exp,
|
||||
_ if let Ok(Some(sym)) = sym_peek(src) => sym,
|
||||
_ if let Ok(Some(key)) = key_peek(src) => key,
|
||||
_ if let Ok(Some(num)) = num_peek(src) => num,
|
||||
_ if let Ok(Some(text)) = text_peek(src) => text,
|
||||
_ => {
|
||||
iter_chars!(src => |_i, c| if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
return Ok(None)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
pub const fn seek (mut src: &str) -> DslPerhaps<(usize, usize)> {
|
||||
Ok(Some(match () {
|
||||
_ if let Ok(Some(exp)) = exp_seek(src) => exp,
|
||||
_ if let Ok(Some(sym)) = sym_seek(src) => sym,
|
||||
_ if let Ok(Some(key)) = key_seek(src) => key,
|
||||
_ if let Ok(Some(num)) = num_seek(src) => num,
|
||||
_ if let Ok(Some(text)) = text_seek(src) => text,
|
||||
_ => {
|
||||
iter_chars!(src => |_i, c| if !is_whitespace(c) {
|
||||
return Err(Unexpected(c))
|
||||
});
|
||||
return Ok(None)
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
pub const fn is_whitespace (c: char) -> bool {
|
||||
matches!(c, ' '|'\n'|'\r'|'\t')
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue