mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 03:36:42 +01:00
wip: mrr
This commit is contained in:
parent
6c3a0964ec
commit
7271081fc9
10 changed files with 119 additions and 296 deletions
200
]
200
]
|
|
@ -1,200 +0,0 @@
|
||||||
use crate::*;
|
|
||||||
/// A collection of input bind.
|
|
||||||
///
|
|
||||||
/// Each contained layer defines a mapping from input event to command invocation
|
|
||||||
/// over a given state. Furthermore, each layer may have an associated cond,
|
|
||||||
/// so that only certain layers are active at a given time depending on state.
|
|
||||||
#[derive(Debug, Default)] pub struct InputMap<I, T: Dsl>(std::collections::BTreeMap<I, T>);
|
|
||||||
impl<I, T: Dsl> InputMap<I, T> {
|
|
||||||
/// Create input layer collection from path to text file.
|
|
||||||
pub fn from_path <P: Debug + AsRef<Path>> (path: P) -> Usually<Self> {
|
|
||||||
if !exists(path.as_ref())? {
|
|
||||||
return Err(format!("(e5) not found: {path:?}").into())
|
|
||||||
}
|
|
||||||
Self::from_source(read_and_leak(path)?)
|
|
||||||
}
|
|
||||||
/// Create input layer collection from string.
|
|
||||||
pub fn from_source <S: AsRef<str>> (source: S) -> Usually<Self> {
|
|
||||||
Self::from_dsl(CstIter::from(source.as_ref()))
|
|
||||||
}
|
|
||||||
/// Create input layer collection from DSL.
|
|
||||||
pub fn from_dsl (dsl: impl Dsl) -> Usually<Self> {
|
|
||||||
use DslVal::*;
|
|
||||||
let mut input_map: Self = Self(Default::default());
|
|
||||||
while let Exp(_, mut exp) = dsl.val() {
|
|
||||||
match exp.nth(0).map(|x|x.val()) {
|
|
||||||
Some(Str(path)) => {
|
|
||||||
let path = PathBuf::from(path.as_ref());
|
|
||||||
let module = InputMap::<I, T>::from_path(&path)?;
|
|
||||||
for (key, val) in module.0.into_iter() {
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(Exp(_, expr)) if let Some(Sym(sym)) = expr.nth(0) => {
|
|
||||||
//input_map.unconditional.push(expr);
|
|
||||||
todo!("binding");
|
|
||||||
},
|
|
||||||
Some(Exp(_, expr)) if expr.nth(0).map(|x|x.val()) == Some(Key("if")) => {
|
|
||||||
todo!("conditional binding");
|
|
||||||
},
|
|
||||||
_ => return Result::Err("invalid token in keymap".into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(input_map)
|
|
||||||
}
|
|
||||||
/// Evaluate the active layers for a given state,
|
|
||||||
/// returning the command to be executed, if any.
|
|
||||||
pub fn handle <S, O> (&self, state: &mut S, input: I) -> Perhaps<O> where
|
|
||||||
S: DslInto<bool> + DslInto<O>,
|
|
||||||
O: Command<S>
|
|
||||||
{
|
|
||||||
todo!();
|
|
||||||
//let layers = self.0.as_slice();
|
|
||||||
//for InputLayer { cond, bind } in layers.iter() {
|
|
||||||
//let mut matches = true;
|
|
||||||
//if let Some(cond) = cond {
|
|
||||||
//matches = state.dsl_into(cond, ||format!("input: no cond").into())?;
|
|
||||||
//}
|
|
||||||
//if matches
|
|
||||||
//&& let Some(exp) = bind.val().exp_head()
|
|
||||||
//&& input.dsl_into(exp, ||format!("InputMap: input.eval(binding) failed").into())?
|
|
||||||
//&& let Some(command) = state.try_dsl_into(exp)? {
|
|
||||||
//return Ok(Some(command))
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
/// Create an input map with a single non-condal layer.
|
|
||||||
/// (Use [Default::default] to get an empty map.)
|
|
||||||
pub fn new (layer: DslVal<T::Str, T::Exp>) -> Self {
|
|
||||||
Self::default().layer(layer)
|
|
||||||
}
|
|
||||||
/// Add layer, return `Self`.
|
|
||||||
pub fn layer (mut self, layer: DslVal<T::Str, T::Exp>) -> Self {
|
|
||||||
self.add_layer(layer); self
|
|
||||||
}
|
|
||||||
/// Add condal layer, return `Self`.
|
|
||||||
pub fn layer_if (mut self, cond: DslVal<T::Str, T::Exp>, layer: DslVal<T::Str, T::Exp>) -> Self {
|
|
||||||
self.add_layer_if(Some(cond), layer); self
|
|
||||||
}
|
|
||||||
/// Add layer, return `&mut Self`.
|
|
||||||
pub fn add_layer (&mut self, layer: DslVal<T::Str, T::Exp>) -> &mut Self {
|
|
||||||
self.add_layer_if(None, layer.into()); self
|
|
||||||
}
|
|
||||||
/// Add condal layer, return `&mut Self`.
|
|
||||||
pub fn add_layer_if (&mut self, cond: Option<DslVal<T::Str, T::Exp>>, bind: DslVal<T::Str, T::Exp>) -> &mut Self {
|
|
||||||
self.0.push(InputLayer { cond, bind });
|
|
||||||
self
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//let mut keys = iter.unwrap();
|
|
||||||
//let mut map = InputMap::default();
|
|
||||||
//while let Some(token) = keys.next() {
|
|
||||||
//if let Value::Exp(_, mut exp) = token.value {
|
|
||||||
//let next = exp.next();
|
|
||||||
//if let Some(Token { value: Value::Key(sym), .. }) = next {
|
|
||||||
//match sym {
|
|
||||||
//"layer" => {
|
|
||||||
//if let Some(Token { value: Value::Str(path), .. }) = exp.peek() {
|
|
||||||
//let path = base.as_ref().parent().unwrap().join(unquote(path));
|
|
||||||
//if !std::fs::exists(&path)? {
|
|
||||||
//return Err(format!("(e5) not found: {path:?}").into())
|
|
||||||
//}
|
|
||||||
//map.add_layer(read_and_leak(path)?.into());
|
|
||||||
//print!("layer:\n path: {:?}...", exp.0.0.trim());
|
|
||||||
//println!("ok");
|
|
||||||
//} else {
|
|
||||||
//return Err(format!("(e4) unexpected non-string {next:?}").into())
|
|
||||||
//}
|
|
||||||
//},
|
|
||||||
|
|
||||||
//"layer-if" => {
|
|
||||||
//let mut cond = None;
|
|
||||||
|
|
||||||
//if let Some(Token { value: Value::Sym(sym), .. }) = exp.next() {
|
|
||||||
//cond = Some(leak(sym));
|
|
||||||
//} else {
|
|
||||||
//return Err(format!("(e4) unexpected non-symbol {next:?}").into())
|
|
||||||
//};
|
|
||||||
|
|
||||||
//if let Some(Token { value: Value::Str(path), .. }) = exp.peek() {
|
|
||||||
//let path = base.as_ref().parent().unwrap().join(unquote(path));
|
|
||||||
//if !std::fs::exists(&path)? {
|
|
||||||
//return Err(format!("(e5) not found: {path:?}").into())
|
|
||||||
//}
|
|
||||||
//print!("layer-if:\n cond: {}\n path: {path:?}...",
|
|
||||||
//cond.unwrap_or_default());
|
|
||||||
//let keys = read_and_leak(path)?.into();
|
|
||||||
//let cond = cond.unwrap();
|
|
||||||
//println!("ok");
|
|
||||||
//map.add_layer_if(
|
|
||||||
//Box::new(move |state: &App|Take::take_or_fail(
|
|
||||||
//state, exp, ||"missing input layer conditional"
|
|
||||||
//)), keys
|
|
||||||
//);
|
|
||||||
//} else {
|
|
||||||
//return Err(format!("(e4) unexpected non-symbol {next:?}").into())
|
|
||||||
//}
|
|
||||||
//},
|
|
||||||
|
|
||||||
//_ => return Err(format!("(e3) unexpected symbol {sym:?}").into())
|
|
||||||
//}
|
|
||||||
//} else {
|
|
||||||
//return Err(format!("(e2) unexpected exp {:?}", next.map(|x|x.value)).into())
|
|
||||||
//}
|
|
||||||
//} else {
|
|
||||||
//return Err(format!("(e1) unexpected token {token:?}").into())
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
//Ok(map)
|
|
||||||
//}
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
//fn from (source: &'s str) -> Self {
|
|
||||||
//// this should be for single layer:
|
|
||||||
//use DslVal::*;
|
|
||||||
//let mut layers = vec![];
|
|
||||||
//let mut source = CstIter::from(source);
|
|
||||||
//while let Some(Exp(_, mut iter)) = source.next().map(|x|x.value) {
|
|
||||||
//let mut iter = iter.clone();
|
|
||||||
//layers.push(match iter.next().map(|x|x.value) {
|
|
||||||
//Some(Sym(sym)) if sym.starts_with("@") => InputLayer {
|
|
||||||
//cond: None,
|
|
||||||
//bind: vec![[
|
|
||||||
//dsl_val(source.nth(1).unwrap()),
|
|
||||||
//dsl_val(source.nth(2).unwrap()),
|
|
||||||
//]],
|
|
||||||
//},
|
|
||||||
//Some(Str(layer)) => InputLayer {
|
|
||||||
//cond: None,
|
|
||||||
//bind: dsl_val(source.nth(1).unwrap()),
|
|
||||||
//},
|
|
||||||
//Some(Key("if")) => InputLayer {
|
|
||||||
//cond: Some(dsl_val(source.nth(1).unwrap())),
|
|
||||||
//bind: dsl_val(source.nth(2).unwrap()),
|
|
||||||
//},
|
|
||||||
//_ => panic!("invalid token in keymap"),
|
|
||||||
//})
|
|
||||||
//}
|
|
||||||
//Self(layers)
|
|
||||||
//}
|
|
||||||
//}
|
|
||||||
|
|
||||||
fn unquote (x: &str) -> &str {
|
|
||||||
let mut chars = x.chars();
|
|
||||||
chars.next();
|
|
||||||
//chars.next_back();
|
|
||||||
chars.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_and_leak (path: impl AsRef<Path>) -> Usually<&'static str> {
|
|
||||||
Ok(leak(String::from_utf8(std::fs::read(path.as_ref())?)?))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn leak (x: impl AsRef<str>) -> &'static str {
|
|
||||||
Box::leak(x.as_ref().into())
|
|
||||||
}
|
|
||||||
115
dsl/src/cst.rs
115
dsl/src/cst.rs
|
|
@ -5,10 +5,10 @@ use crate::*;
|
||||||
|
|
||||||
/// CST stores strings as source references and expressions as [CstIter] instances.
|
/// CST stores strings as source references and expressions as [CstIter] instances.
|
||||||
#[derive(Debug, Clone, Default, PartialEq)]
|
#[derive(Debug, Clone, Default, PartialEq)]
|
||||||
pub struct Cst<'src>(pub CstIter<'src>);
|
pub struct Cst<'s>(pub CstIter<'s>);
|
||||||
impl<'src> Dsl for Cst<'src> {
|
impl<'s> Dsl for Cst<'s> {
|
||||||
type Str = &'src str;
|
type Str = &'s str;
|
||||||
type Exp = CstIter<'src>;
|
type Exp = CstIter<'s>;
|
||||||
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
||||||
self.0.nth(index)
|
self.0.nth(index)
|
||||||
}
|
}
|
||||||
|
|
@ -16,49 +16,49 @@ impl<'src> Dsl for Cst<'src> {
|
||||||
|
|
||||||
/// Parsed substring with range and value.
|
/// Parsed substring with range and value.
|
||||||
#[derive(Debug, Copy, Clone, Default, PartialEq)]
|
#[derive(Debug, Copy, Clone, Default, PartialEq)]
|
||||||
pub struct CstVal<'src> {
|
pub struct CstVal<'s> {
|
||||||
/// Meaning of token.
|
/// Meaning of token.
|
||||||
pub value: DslVal<&'src str, CstIter<'src>>,
|
pub value: DslVal<&'s str, CstIter<'s>>,
|
||||||
/// Reference to source text.
|
/// Reference to source text.
|
||||||
pub source: &'src str,
|
pub source: &'s str,
|
||||||
/// Index of 1st character of token.
|
/// Index of 1st character of token.
|
||||||
pub start: usize,
|
pub start: usize,
|
||||||
/// Length of token.
|
/// Length of token.
|
||||||
pub length: usize,
|
pub length: usize,
|
||||||
}
|
}
|
||||||
impl<'src> Dsl for CstVal<'src> {
|
impl<'s> Dsl for CstVal<'s> {
|
||||||
type Str = &'src str;
|
type Str = &'s str;
|
||||||
type Exp = CstIter<'src>;
|
type Exp = CstIter<'s>;
|
||||||
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> CstVal<'src> {
|
impl<'s> CstVal<'s> {
|
||||||
pub const fn new (
|
pub const fn new (
|
||||||
source: &'src str,
|
source: &'s str,
|
||||||
start: usize,
|
start: usize,
|
||||||
length: usize,
|
length: usize,
|
||||||
value: DslVal<&'src str, CstIter<'src>>
|
value: DslVal<&'s str, CstIter<'s>>
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self { source, start, length, value }
|
Self { source, start, length, value }
|
||||||
}
|
}
|
||||||
pub const fn end (&self) -> usize {
|
pub const fn end (&self) -> usize {
|
||||||
self.start.saturating_add(self.length)
|
self.start.saturating_add(self.length)
|
||||||
}
|
}
|
||||||
pub const fn slice (&'src self) -> &'src str {
|
pub const fn slice (&'s self) -> &'s str {
|
||||||
self.slice_source(self.source)
|
self.slice_source(self.source)
|
||||||
}
|
}
|
||||||
pub const fn slice_source <'range> (&'src self, source: &'range str) -> &'range str {
|
pub const fn slice_source <'range> (&'s self, source: &'range str) -> &'range str {
|
||||||
str_range(source, self.start, self.end())
|
str_range(source, self.start, self.end())
|
||||||
}
|
}
|
||||||
pub const fn slice_source_exp <'range> (&'src self, source: &'range str) -> &'range str {
|
pub const fn slice_source_exp <'range> (&'s self, source: &'range str) -> &'range str {
|
||||||
str_range(source, self.start.saturating_add(1), self.end())
|
str_range(source, self.start.saturating_add(1), self.end())
|
||||||
}
|
}
|
||||||
pub const fn with_value (self, value: DslVal<&'src str, CstIter<'src>>) -> Self {
|
pub const fn with_value (self, value: DslVal<&'s str, CstIter<'s>>) -> Self {
|
||||||
Self { value, ..self }
|
Self { value, ..self }
|
||||||
}
|
}
|
||||||
pub const fn value (&self) -> DslVal<&'src str, CstIter<'src>> {
|
pub const fn value (&self) -> DslVal<&'s str, CstIter<'s>> {
|
||||||
self.value
|
self.value
|
||||||
}
|
}
|
||||||
pub const fn error (self, error: DslErr) -> Self {
|
pub const fn error (self, error: DslErr) -> Self {
|
||||||
|
|
@ -121,46 +121,37 @@ impl<'src> CstVal<'src> {
|
||||||
/// [Cst::next] returns just the [Cst] and mutates `self`,
|
/// [Cst::next] returns just the [Cst] and mutates `self`,
|
||||||
/// instead of returning an updated version of the struct as [CstConstIter::next] does.
|
/// instead of returning an updated version of the struct as [CstConstIter::next] does.
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||||
pub struct CstIter<'src>(pub CstConstIter<'src>);
|
pub struct CstIter<'s>(pub CstConstIter<'s>);
|
||||||
impl<'src> Dsl for CstIter<'src> {
|
impl<'s> Dsl for CstIter<'s> {
|
||||||
type Str = &'src str;
|
type Str = &'s str;
|
||||||
type Exp = Self;
|
type Exp = Self;
|
||||||
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
||||||
use DslVal::*;
|
self.0.nth(index).map(|x|dsl_val(x))
|
||||||
self.0.nth(index).map(|x|match x {
|
|
||||||
Nil => Nil,
|
|
||||||
Err(e) => Err(e),
|
|
||||||
Num(u) => Num(u),
|
|
||||||
Sym(s) => Sym(s),
|
|
||||||
Key(s) => Sym(s),
|
|
||||||
Str(s) => Sym(s),
|
|
||||||
Exp(d, x) => DslVal::Exp(d, CstIter(x)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'src> CstIter<'src> {
|
impl<'s> CstIter<'s> {
|
||||||
pub const fn new (source: &'src str) -> Self {
|
pub const fn new (source: &'s str) -> Self {
|
||||||
Self(CstConstIter::new(source))
|
Self(CstConstIter::new(source))
|
||||||
}
|
}
|
||||||
pub const fn peek (&self) -> Option<CstVal<'src>> {
|
pub const fn peek (&self) -> Option<CstVal<'s>> {
|
||||||
self.0.peek()
|
self.0.peek()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'src> Iterator for CstIter<'src> {
|
impl<'s> Iterator for CstIter<'s> {
|
||||||
type Item = CstVal<'src>;
|
type Item = CstVal<'s>;
|
||||||
fn next (&mut self) -> Option<CstVal<'src>> {
|
fn next (&mut self) -> Option<CstVal<'s>> {
|
||||||
self.0.next().map(|(item, rest)|{
|
self.0.next().map(|(item, rest)|{
|
||||||
self.0 = rest;
|
self.0 = rest;
|
||||||
item
|
item
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'src> Into<Vec<CstVal<'src>>> for CstIter<'src> {
|
impl<'s> Into<Vec<CstVal<'s>>> for CstIter<'s> {
|
||||||
fn into (self) -> Vec<CstVal<'src>> {
|
fn into (self) -> Vec<CstVal<'s>> {
|
||||||
self.collect()
|
self.collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'src> Into<Vec<Ast>> for CstIter<'src> {
|
impl<'s> Into<Vec<Ast>> for CstIter<'s> {
|
||||||
fn into (self) -> Vec<Ast> {
|
fn into (self) -> Vec<Ast> {
|
||||||
self.map(Into::into).collect()
|
self.map(Into::into).collect()
|
||||||
}
|
}
|
||||||
|
|
@ -172,9 +163,9 @@ impl<'src> Into<Vec<Ast>> for CstIter<'src> {
|
||||||
/// * the source text remaining
|
/// * the source text remaining
|
||||||
/// * [ ] TODO: maybe [CstConstIter::next] should wrap the remaining source in `Self` ?
|
/// * [ ] TODO: maybe [CstConstIter::next] should wrap the remaining source in `Self` ?
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq)]
|
||||||
pub struct CstConstIter<'src>(pub &'src str);
|
pub struct CstConstIter<'s>(pub &'s str);
|
||||||
impl<'src> Dsl for CstConstIter<'src> {
|
impl<'s> Dsl for CstConstIter<'s> {
|
||||||
type Str = &'src str;
|
type Str = &'s str;
|
||||||
type Exp = Self;
|
type Exp = Self;
|
||||||
fn nth (&self, mut index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
fn nth (&self, mut index: usize) -> Option<DslVal<Self::Str, Self::Exp>> {
|
||||||
use DslVal::*;
|
use DslVal::*;
|
||||||
|
|
@ -182,37 +173,39 @@ impl<'src> Dsl for CstConstIter<'src> {
|
||||||
for i in 0..index {
|
for i in 0..index {
|
||||||
iter = iter.next()?.1
|
iter = iter.next()?.1
|
||||||
}
|
}
|
||||||
iter.next().map(|(x, _)|match x.value {
|
iter.next().map(|(x, _)|dsl_val(x.value))
|
||||||
Nil => Nil,
|
|
||||||
Err(e) => Err(e),
|
|
||||||
Num(u) => Num(u),
|
|
||||||
Sym(s) => Sym(s),
|
|
||||||
Key(s) => Sym(s),
|
|
||||||
Str(s) => Sym(s),
|
|
||||||
Exp(d, x) => DslVal::Exp(d, x.0),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<'src> CstConstIter<'src> {
|
impl<'s> CstConstIter<'s> {
|
||||||
pub const fn new (source: &'src str) -> Self {
|
pub const fn new (source: &'s str) -> Self {
|
||||||
Self(source)
|
Self(source)
|
||||||
}
|
}
|
||||||
pub const fn chomp (&self, index: usize) -> Self {
|
pub const fn chomp (&self, index: usize) -> Self {
|
||||||
Self(split_at(self.0, index).1)
|
Self(split_at(self.0, index).1)
|
||||||
}
|
}
|
||||||
pub const fn next (mut self) -> Option<(CstVal<'src>, Self)> {
|
pub const fn next (mut self) -> Option<(CstVal<'s>, Self)> {
|
||||||
Self::next_mut(&mut self)
|
Self::next_mut(&mut self)
|
||||||
}
|
}
|
||||||
pub const fn peek (&self) -> Option<CstVal<'src>> {
|
pub const fn peek (&self) -> Option<CstVal<'s>> {
|
||||||
peek_src(self.0)
|
peek_src(self.0)
|
||||||
}
|
}
|
||||||
pub const fn next_mut (&mut self) -> Option<(CstVal<'src>, Self)> {
|
pub const fn next_mut (&mut self) -> Option<(CstVal<'s>, Self)> {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(token) => Some((token, self.chomp(token.end()))),
|
Some(token) => Some((token, self.chomp(token.end()))),
|
||||||
None => None
|
None => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl<'s> From<CstConstIter<'s>> for CstIter<'s> {
|
||||||
|
fn from (iter: CstConstIter<'s>) -> Self {
|
||||||
|
Self(iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl<'s> From<CstIter<'s>> for CstConstIter<'s> {
|
||||||
|
fn from (iter: CstIter<'s>) -> Self {
|
||||||
|
iter.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implement the const iterator pattern.
|
/// Implement the const iterator pattern.
|
||||||
macro_rules! const_iter {
|
macro_rules! const_iter {
|
||||||
|
|
@ -229,8 +222,8 @@ macro_rules! const_iter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iter!(<'src>|self: CstConstIter<'src>|
|
const_iter!(<'s>|self: CstConstIter<'s>|
|
||||||
=> CstVal<'src>
|
=> CstVal<'s>
|
||||||
=> self.next_mut().map(|(result, _)|result));
|
=> self.next_mut().map(|(result, _)|result));
|
||||||
|
|
||||||
/// Static iteration helper used by [cst].
|
/// Static iteration helper used by [cst].
|
||||||
|
|
@ -244,9 +237,9 @@ macro_rules! iterate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn peek_src <'src> (source: &'src str) -> Option<CstVal<'src>> {
|
pub const fn peek_src <'s> (source: &'s str) -> Option<CstVal<'s>> {
|
||||||
use DslVal::*;
|
use DslVal::*;
|
||||||
let mut token: CstVal<'src> = CstVal::new(source, 0, 0, Nil);
|
let mut token: CstVal<'s> = CstVal::new(source, 0, 0, Nil);
|
||||||
iterate!(char_indices(source) => (start, c) => token = match token.value() {
|
iterate!(char_indices(source) => (start, c) => token = match token.value() {
|
||||||
Err(_) => return Some(token),
|
Err(_) => return Some(token),
|
||||||
Nil => match c {
|
Nil => match c {
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,20 @@ pub enum DslVal<Str, Exp> {
|
||||||
Exp(usize, Exp),
|
Exp(usize, Exp),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Dsl {
|
pub fn dsl_val <A: Into<X>, B: Into<Y>, X, Y> (val: DslVal<A, B>) -> DslVal<X, Y> {
|
||||||
|
use DslVal::*;
|
||||||
|
match val {
|
||||||
|
Nil => Nil,
|
||||||
|
Err(e) => Err(e),
|
||||||
|
Num(u) => Num(u),
|
||||||
|
Sym(s) => Sym(s.into()),
|
||||||
|
Key(s) => Key(s.into()),
|
||||||
|
Str(s) => Str(s.into()),
|
||||||
|
Exp(d, x) => Exp(d, x.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Dsl: Debug {
|
||||||
type Str: PartialEq + Clone + Default + Debug + AsRef<str>;
|
type Str: PartialEq + Clone + Default + Debug + AsRef<str>;
|
||||||
type Exp: PartialEq + Clone + Default + Debug + Dsl;
|
type Exp: PartialEq + Clone + Default + Debug + Dsl;
|
||||||
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>>;
|
fn nth (&self, index: usize) -> Option<DslVal<Self::Str, Self::Exp>>;
|
||||||
|
|
@ -61,7 +74,7 @@ impl<
|
||||||
fn val (&self) -> DslVal<Str, Exp> {
|
fn val (&self) -> DslVal<Str, Exp> {
|
||||||
self.clone()
|
self.clone()
|
||||||
}
|
}
|
||||||
fn nth (&self, index: usize) -> Option<DslVal<Str, Exp>> {
|
fn nth (&self, _index: usize) -> Option<DslVal<Str, Exp>> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -163,16 +176,3 @@ from_str!(Ast|source|Self::from(CstIter::from(source)));
|
||||||
from_str!(Cst<'s>|source|Self(CstIter(CstConstIter(source))));
|
from_str!(Cst<'s>|source|Self(CstIter(CstConstIter(source))));
|
||||||
from_str!(CstIter<'s>|source|Self(CstConstIter(source)));
|
from_str!(CstIter<'s>|source|Self(CstConstIter(source)));
|
||||||
from_str!(CstConstIter<'s>|source|Self::new(source));
|
from_str!(CstConstIter<'s>|source|Self::new(source));
|
||||||
|
|
||||||
pub fn dsl_val <A: Into<X>, B: Into<Y>, X, Y> (val: DslVal<A, B>) -> DslVal<X, Y> {
|
|
||||||
use DslVal::*;
|
|
||||||
match val {
|
|
||||||
Nil => Nil,
|
|
||||||
Err(e) => Err(e),
|
|
||||||
Num(u) => Num(u),
|
|
||||||
Sym(s) => Sym(s.into()),
|
|
||||||
Key(s) => Key(s.into()),
|
|
||||||
Str(s) => Str(s.into()),
|
|
||||||
Exp(d, x) => Exp(d, x.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,6 @@ pub(crate) use ::tengri_core::*;
|
||||||
pub(crate) use std::fmt::Debug;
|
pub(crate) use std::fmt::Debug;
|
||||||
pub(crate) use std::sync::Arc;
|
pub(crate) use std::sync::Arc;
|
||||||
pub(crate) use std::collections::VecDeque;
|
pub(crate) use std::collections::VecDeque;
|
||||||
pub(crate) use std::path::Path;
|
|
||||||
pub(crate) use std::fs::exists;
|
|
||||||
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
pub(crate) use konst::iter::{ConstIntoIter, IsIteratorKind};
|
||||||
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
pub(crate) use konst::string::{split_at, str_range, char_indices};
|
||||||
pub(crate) use thiserror::Error;
|
pub(crate) use thiserror::Error;
|
||||||
|
|
|
||||||
5
editor/Cargo.toml
Normal file
5
editor/Cargo.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
[package]
|
||||||
|
name = "tengri_editor"
|
||||||
|
description = "Embeddable editor for Tengri DSL."
|
||||||
|
version = { workspace = true }
|
||||||
|
edition = { workspace = true }
|
||||||
|
|
@ -1,11 +1,22 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
/// A collection of input bind.
|
/// A collection of input bindings.
|
||||||
///
|
///
|
||||||
/// Each contained layer defines a mapping from input event to command invocation
|
/// Each contained layer defines a mapping from input event to command invocation
|
||||||
/// over a given state. Furthermore, each layer may have an associated cond,
|
/// over a given state. Furthermore, each layer may have an associated cond,
|
||||||
/// so that only certain layers are active at a given time depending on state.
|
/// so that only certain layers are active at a given time depending on state.
|
||||||
#[derive(Debug, Default)] pub struct InputMap<I, T: Dsl>(std::collections::BTreeMap<I, T>);
|
#[derive(Debug, Default)] pub struct InputMap<I, T: Dsl>(
|
||||||
impl<I, T: Dsl> InputMap<I, T> {
|
/// Map of input event (key combination) to
|
||||||
|
/// all command expressions bound to it by
|
||||||
|
/// all loaded input layers.
|
||||||
|
pub BTreeMap<I, Vec<InputBinding<T>>>
|
||||||
|
);
|
||||||
|
#[derive(Debug, Default)] pub struct InputBinding<T: Dsl> {
|
||||||
|
condition: Option<T>,
|
||||||
|
command: T,
|
||||||
|
description: Option<Arc<str>>,
|
||||||
|
source: Option<Arc<PathBuf>>,
|
||||||
|
}
|
||||||
|
impl<I: Debug + Ord, T: Dsl> InputMap<I, T> {
|
||||||
/// Create input layer collection from path to text file.
|
/// Create input layer collection from path to text file.
|
||||||
pub fn from_path <P: Debug + AsRef<Path>> (path: P) -> Usually<Self> {
|
pub fn from_path <P: Debug + AsRef<Path>> (path: P) -> Usually<Self> {
|
||||||
if !exists(path.as_ref())? {
|
if !exists(path.as_ref())? {
|
||||||
|
|
@ -18,29 +29,38 @@ impl<I, T: Dsl> InputMap<I, T> {
|
||||||
Self::from_dsl(CstIter::from(source.as_ref()))
|
Self::from_dsl(CstIter::from(source.as_ref()))
|
||||||
}
|
}
|
||||||
/// Create input layer collection from DSL.
|
/// Create input layer collection from DSL.
|
||||||
pub fn from_dsl (dsl: impl Dsl) -> Usually<Self> {
|
pub fn from_dsl <D: Dsl> (dsl: D) -> Usually<Self> {
|
||||||
use DslVal::*;
|
use DslVal::*;
|
||||||
let mut input_map: Self = Self(Default::default());
|
let mut input_map: BTreeMap<I, Vec<InputBinding<T>>> = Default::default();
|
||||||
while let Exp(_, mut exp) = dsl.val() {
|
let mut index = 0;
|
||||||
|
while let Some(Exp(_, mut exp)) = dsl.nth(index) {
|
||||||
let val = exp.nth(0).map(|x|x.val());
|
let val = exp.nth(0).map(|x|x.val());
|
||||||
match val {
|
match val {
|
||||||
Some(Str(path)) => {
|
Some(Str(path)) => {
|
||||||
let path = PathBuf::from(path.as_ref());
|
let path = PathBuf::from(path.as_ref());
|
||||||
let module = InputMap::<I, T>::from_path(&path)?;
|
let module = InputMap::<I, T>::from_path(&path)?;
|
||||||
for (key, val) in module.0.into_iter() {
|
for (key, val) in module.0.into_iter() {
|
||||||
|
todo!("import {exp:?} {key:?} {val:?} {path:?}");
|
||||||
|
if !input_map.contains_key(&key) {
|
||||||
|
input_map.insert(key, vec![]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Some(Exp(_, expr)) if let Some(Sym(sym)) = expr.nth(0) => {
|
Some(Sym(sym)) => {
|
||||||
//input_map.unconditional.push(expr);
|
//let key: I = sym.into();
|
||||||
todo!("binding");
|
//if !input_map.contains_key(&key) {
|
||||||
|
//input_map.insert(key, vec![]);
|
||||||
|
//}
|
||||||
|
todo!("binding {exp:?} {sym:?}");
|
||||||
},
|
},
|
||||||
Some(Exp(_, expr)) if let Some(Key(key)) = expr.nth(0) && key.as_ref() == "if" => {
|
Some(Key(key)) if key.as_ref() == "if" => {
|
||||||
todo!("conditional binding");
|
todo!("conditional binding {exp:?} {key:?}");
|
||||||
},
|
},
|
||||||
_ => return Result::Err(format!("invalid token in keymap: {val:?}").into()),
|
_ => return Result::Err(format!("invalid token in keymap: {val:?}").into()),
|
||||||
}
|
}
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
Ok(input_map)
|
Ok(Self(input_map))
|
||||||
}
|
}
|
||||||
/// Evaluate the active layers for a given state,
|
/// Evaluate the active layers for a given state,
|
||||||
/// returning the command to be executed, if any.
|
/// returning the command to be executed, if any.
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@
|
||||||
#![feature(if_let_guard)]
|
#![feature(if_let_guard)]
|
||||||
|
|
||||||
pub(crate) use std::fmt::Debug;
|
pub(crate) use std::fmt::Debug;
|
||||||
pub(crate) use std::collections::BTreeMap;
|
pub(crate) use std::sync::Arc;
|
||||||
|
pub(crate) use std::collections::{BTreeMap, HashMap};
|
||||||
pub(crate) use std::path::{Path, PathBuf};
|
pub(crate) use std::path::{Path, PathBuf};
|
||||||
pub(crate) use std::fs::exists;
|
pub(crate) use std::fs::exists;
|
||||||
pub(crate) use tengri_core::*;
|
pub(crate) use tengri_core::*;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use crate::{dsl::*, input::*, tui::TuiIn};
|
use crate::{dsl::*, input::*, tui::TuiIn};
|
||||||
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
|
use crossterm::event::{Event, KeyEvent, KeyCode, KeyModifiers, KeyEventKind, KeyEventState};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
#[test] fn test_subcommand () -> Usually<()> {
|
#[test] fn test_subcommand () -> Usually<()> {
|
||||||
struct Test { keys: InputMap<(), Ast> }
|
#[derive(Debug)] struct Event(crossterm::event::Event);
|
||||||
|
impl Eq for Event {}
|
||||||
|
impl PartialEq for Event { fn eq (&self, other: &Self) -> bool { todo!() } }
|
||||||
|
impl Ord for Event { fn cmp (&self, other: &Self) -> Ordering { todo!() } }
|
||||||
|
impl PartialOrd for Event { fn partial_cmp (&self, other: &Self) -> Option<Ordering> { None } }
|
||||||
|
struct Test { keys: InputMap<Event, Ast> }
|
||||||
|
|
||||||
handle!(TuiIn: |self: Test, input|Ok(None));/*if let Some(command) = self.keys.command(self, input) {
|
handle!(TuiIn: |self: Test, input|Ok(None));/*if let Some(command) = self.keys.command(self, input) {
|
||||||
Ok(Some(true))
|
Ok(Some(true))
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ pub struct TuiIn(
|
||||||
/// Exit flag
|
/// Exit flag
|
||||||
pub Arc<AtomicBool>,
|
pub Arc<AtomicBool>,
|
||||||
/// Input event
|
/// Input event
|
||||||
pub Event,
|
pub crossterm::event::Event,
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Input for TuiIn {
|
impl Input for TuiIn {
|
||||||
type Event = Event;
|
type Event = crossterm::event::Event;
|
||||||
type Handled = bool;
|
type Handled = bool;
|
||||||
fn event (&self) -> &Event { &self.1 }
|
fn event (&self) -> &crossterm::event::Event { &self.1 }
|
||||||
fn is_done (&self) -> bool { self.0.fetch_and(true, Relaxed) }
|
fn is_done (&self) -> bool { self.0.fetch_and(true, Relaxed) }
|
||||||
fn done (&self) { self.0.store(true, Relaxed); }
|
fn done (&self) { self.0.store(true, Relaxed); }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue