Parse has
This commit is contained in:
parent
3c4f063d08
commit
6e0a7375c0
|
|
@ -89,7 +89,7 @@ pub fn has(out: &mut String, f: &Has, value: &dyn Value, arena: &AstArena) {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(value) = value.has() {
|
if let Some(value) = value.has() {
|
||||||
let nodes = arena.deref_many(&f.body);
|
let nodes = arena.deref_many(&f.then);
|
||||||
execute_(out, nodes, value, arena);
|
execute_(out, nodes, value, arena);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ pub struct For {
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct Has {
|
pub struct Has {
|
||||||
pub path: Path,
|
pub path: Path,
|
||||||
pub body: Vec<AstNodeKind>,
|
pub then: Vec<AstNodeKind>,
|
||||||
|
pub else_: Option<Vec<AstNodeKind>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
@ -78,6 +79,8 @@ fn parse_block(rest: &str) -> ParseResult<Option<AstNodeKind>> {
|
||||||
parse_for(rest).map(|v| v.map(AstNodeKind::For))
|
parse_for(rest).map(|v| v.map(AstNodeKind::For))
|
||||||
} else if rest_.starts_with("if ") {
|
} else if rest_.starts_with("if ") {
|
||||||
parse_if(rest).map(|v| v.map(AstNodeKind::If))
|
parse_if(rest).map(|v| v.map(AstNodeKind::If))
|
||||||
|
} else if rest_.starts_with("has ") {
|
||||||
|
parse_has(rest).map(|v| v.map(AstNodeKind::Has))
|
||||||
} else if rest_.starts_with("with ") {
|
} else if rest_.starts_with("with ") {
|
||||||
parse_with(rest).map(|v| v.map(AstNodeKind::With))
|
parse_with(rest).map(|v| v.map(AstNodeKind::With))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -310,6 +313,57 @@ fn test_parse_if_else_basic() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_has(rest: &str) -> ParseResult<Option<Has>> {
|
||||||
|
let rest = match rest.strip_prefix('{') {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return ParseResult(rest, None),
|
||||||
|
};
|
||||||
|
let rest = rest.trim_start();
|
||||||
|
|
||||||
|
let rest = match rest.strip_prefix("has ") {
|
||||||
|
Some(r) => r,
|
||||||
|
None => return ParseResult(rest, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ParseResult(rest, path) = parse_path(rest);
|
||||||
|
let path = match path {
|
||||||
|
Some(p) => p,
|
||||||
|
None => return ParseResult(rest, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let rest = rest.trim_start();
|
||||||
|
if let Some(rest) = rest.strip_prefix('}') {
|
||||||
|
let ParseResult(rest, body) = parse_many_until(rest, |s| {
|
||||||
|
s.starts_with("{/has}") || s.starts_with("{else}")
|
||||||
|
});
|
||||||
|
let then = match body {
|
||||||
|
Some(b) => b,
|
||||||
|
None => return ParseResult(rest, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ParseResult(rest, else_) =
|
||||||
|
if let Some(rest) = rest.strip_prefix("{else}") {
|
||||||
|
let ParseResult(rest, else_) =
|
||||||
|
parse_many_until(rest, |s| s.starts_with("{/has}"));
|
||||||
|
let else_ = match else_ {
|
||||||
|
Some(b) => b,
|
||||||
|
None => return ParseResult(rest, None),
|
||||||
|
};
|
||||||
|
let rest = rest.strip_prefix("{/has}").unwrap();
|
||||||
|
|
||||||
|
ParseResult(rest, Some(else_))
|
||||||
|
} else {
|
||||||
|
let rest = rest.strip_prefix("{/has}").unwrap();
|
||||||
|
|
||||||
|
ParseResult(rest, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
ParseResult(rest, Some(Has { path, then, else_ }))
|
||||||
|
} else {
|
||||||
|
ParseResult(rest, None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_path(rest: &str) -> ParseResult<Option<Path>> {
|
fn parse_path(rest: &str) -> ParseResult<Option<Path>> {
|
||||||
if !rest.starts_with('.') {
|
if !rest.starts_with('.') {
|
||||||
return ParseResult(rest, None);
|
return ParseResult(rest, None);
|
||||||
|
|
@ -468,7 +522,9 @@ fn test_parse_many_until() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_complex() {
|
fn test_parse_complex() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse("{for .}{if .}{with .}{.}{/with}{else}Yo{/if}{/for}"),
|
parse(
|
||||||
|
"{for .}{if .}{with .}{.}{/with}{else}{has .}Yo{else}{/has}{/if}{/for}"
|
||||||
|
),
|
||||||
vec![AstNodeKind::For(For {
|
vec![AstNodeKind::For(For {
|
||||||
path: Path(vec![]),
|
path: Path(vec![]),
|
||||||
body: vec![AstNodeKind::If(If {
|
body: vec![AstNodeKind::If(If {
|
||||||
|
|
@ -479,7 +535,11 @@ fn test_parse_complex() {
|
||||||
path: Path(vec![])
|
path: Path(vec![])
|
||||||
})]
|
})]
|
||||||
})],
|
})],
|
||||||
else_: Some(vec![AstNodeKind::Text("Yo".to_string())])
|
else_: Some(vec![AstNodeKind::Has(Has {
|
||||||
|
path: Path(vec![]),
|
||||||
|
then: vec![AstNodeKind::Text("Yo".to_string())],
|
||||||
|
else_: Some(vec![]),
|
||||||
|
})])
|
||||||
})]
|
})]
|
||||||
})]
|
})]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
188
src/internal/parse_backup.rs
Normal file
188
src/internal/parse_backup.rs
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
/*
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::{
|
||||||
|
parse, AstMany, AstNodeKind, AstNodeRef, For, Has, If, Path, Print,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn go(input: &str, expected: Vec<AstNodeKind>) {
|
||||||
|
assert_eq!(parse(input).arena.0, expected)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_text() {
|
||||||
|
go(
|
||||||
|
"Hello, world!",
|
||||||
|
vec![AstNodeKind::Text("Hello, world!".to_string())],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_print() {
|
||||||
|
go(
|
||||||
|
"{ .test }",
|
||||||
|
vec![AstNodeKind::Print(Print {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
})],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_print_just_dot() {
|
||||||
|
go(
|
||||||
|
"{ . }",
|
||||||
|
vec![AstNodeKind::Print(Print { path: Path(vec![]) })],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_print_nested_path() {
|
||||||
|
go(
|
||||||
|
"{ .foo.bar }",
|
||||||
|
vec![AstNodeKind::Print(Print {
|
||||||
|
path: Path(vec!["foo".to_string(), "bar".to_string()]),
|
||||||
|
})],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_has() {
|
||||||
|
go(
|
||||||
|
"{ has .test }{.}{/has}",
|
||||||
|
vec![
|
||||||
|
AstNodeKind::Print(Print { path: Path(vec![]) }),
|
||||||
|
AstNodeKind::Has(Has {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
body: AstMany {
|
||||||
|
start: AstNodeRef(0),
|
||||||
|
end: AstNodeRef(1),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_for() {
|
||||||
|
go(
|
||||||
|
"{ for .test }{.}{/for}",
|
||||||
|
vec![
|
||||||
|
AstNodeKind::Print(Print { path: Path(vec![]) }),
|
||||||
|
AstNodeKind::For(For {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
body: AstMany {
|
||||||
|
start: AstNodeRef(0),
|
||||||
|
end: AstNodeRef(1),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_if() {
|
||||||
|
go(
|
||||||
|
"{ if .test }{.test}{/if}",
|
||||||
|
vec![
|
||||||
|
AstNodeKind::Print(Print {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
}),
|
||||||
|
AstNodeKind::If(If {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
then: AstMany {
|
||||||
|
start: AstNodeRef(0),
|
||||||
|
end: AstNodeRef(1),
|
||||||
|
},
|
||||||
|
else_: None,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn parse_if_else() {
|
||||||
|
go(
|
||||||
|
"{ if .test }{.test}{else}Hello{/if}",
|
||||||
|
vec![
|
||||||
|
AstNodeKind::Print(Print {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
}),
|
||||||
|
AstNodeKind::If(If {
|
||||||
|
path: Path(vec!["test".to_string()]),
|
||||||
|
then: AstMany {
|
||||||
|
start: AstNodeRef(0),
|
||||||
|
end: AstNodeRef(1),
|
||||||
|
},
|
||||||
|
else_: Some(AstMany {
|
||||||
|
start: AstNodeRef(0),
|
||||||
|
end: AstNodeRef(1),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
use super::parse::AstNodeKind;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
pub struct AstArena(Vec<AstNodeKind>);
|
||||||
|
impl AstArena {
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_id(&self) -> AstNodeRef {
|
||||||
|
AstNodeRef(
|
||||||
|
self.0
|
||||||
|
.len()
|
||||||
|
.try_into()
|
||||||
|
.expect("Tried to store too many AST nodes"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(&mut self, n: AstNodeKind) -> AstNodeRef {
|
||||||
|
let id = self.next_id();
|
||||||
|
self.0.push(n);
|
||||||
|
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_many(&mut self, mut many: Vec<AstNodeKind>) -> AstMany {
|
||||||
|
let start = self.next_id();
|
||||||
|
let end = AstNodeRef(
|
||||||
|
(start.0 as usize + many.len())
|
||||||
|
.try_into()
|
||||||
|
.expect("Tried to store too many AST nodes"),
|
||||||
|
);
|
||||||
|
self.0.append(&mut many);
|
||||||
|
|
||||||
|
AstMany { start, end }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deref(&self, rf: AstNodeRef) -> &AstNodeKind {
|
||||||
|
&self.0[rf.0 as usize]
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn deref_many(&self, rf: AstMany) -> &[AstNodeKind] {
|
||||||
|
&self.0[rf.start.0 as usize..rf.end.0 as usize]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
pub fn deref_many(&self, rf: &Vec<AstNodeKind>) -> &[AstNodeKind] {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
|
||||||
|
pub struct AstNodeRef(u32);
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Clone)]
|
||||||
|
pub struct AstMany {
|
||||||
|
start: AstNodeRef,
|
||||||
|
end: AstNodeRef,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Ast {
|
||||||
|
pub(crate) arena: AstArena,
|
||||||
|
pub(crate) root: Vec<AstNodeKind>,
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue