use super::lex::Kind;
use super::lex::Token;
use crate::lang::error::Error;
use crate::lang::error::ErrorKind;
use crate::lang::label::Label;
use crate::lang::lex::lex;
use crate::lang::node::Node;
use crate::value::span::Span;
pub(crate) fn parse(source: Option<&str>, span: Span, data: &[u8]) -> Result<Node, Error> {
let tokens = lex(source, data).collect::<Result<Vec<_>, _>>()?;
let parse = Parse { source, span, data };
let nodes = parse_children(&parse, &Parent::Pipe, &tokens)?;
Ok(Node::Pipe(span, nodes))
}
#[derive(Debug, PartialEq)]
struct Parse<'source, 'data> {
source: Option<&'source str>,
span: Span,
data: &'data [u8],
}
#[derive(Debug, PartialEq)]
enum Parent {
Pipe,
List,
Map,
}
fn parse_children(
parse: &Parse<'_, '_>,
parent: &Parent,
tokens: &[Token<'_>],
) -> Result<Vec<Node>, Error> {
let mut list = Vec::<Node>::new();
let mut iter = tokens.iter().enumerate();
while let Some((i, token)) = iter.next() {
match token.kind {
_ if token.kind.is_pipe() => {
let rest = tokens.get((i + 1)..).unwrap_or_default();
let end = find_next_pipe(rest);
let children = rest.get(0..end).unwrap_or_default();
list = pipe_root_values(parse, list, token);
list.push(parse_pipe(parse, token, children)?);
(end > 0).then(|| iter.nth(end - 1));
}
Kind::BracketStart if sequence_boundary_at(&list) => {
let rest = tokens.get((i + 1)..).unwrap_or_default();
let end = find_end_token(parse, rest, &token.kind, &Kind::BracketEnd)?;
let children = rest.get(0..end).unwrap_or_default();
list.push(parse_list(parse, token, &rest[end], children)?);
iter.nth(end);
}
Kind::BracketStart => {
let rest = tokens.get((i + 1)..).unwrap_or_default();
let end = find_end_token(parse, rest, &token.kind, &Kind::BracketEnd)?;
let children = rest.get(0..end).unwrap_or_default();
list.push(parse_bracket(parse, token, &rest[end], children)?);
iter.nth(end);
}
Kind::BraceStart if sequence_boundary_at(&list) => {
let rest = tokens.get((i + 1)..).unwrap_or_default();
let end = find_end_token(parse, rest, &token.kind, &Kind::BraceEnd)?;
let children = rest.get(0..end).unwrap_or_default();
list.push(parse_map(parse, token, &rest[end], children)?);
iter.nth(end);
}
Kind::BraceStart => {
return parse_error(parse, parse.span.zoom(token.span));
}
Kind::ParenStart => {
let rest = tokens.get((i + 1)..).unwrap_or_default();
let end = find_end_token(parse, rest, &token.kind, &Kind::ParenEnd)?;
let children = rest.get(0..end).unwrap_or_default();
list.push(parse_paren(parse, token, &rest[end], children)?);
iter.nth(end);
}
Kind::Label if thunk_starts_at(tokens, i) => {
let rest = tokens.get((i + 2)..).unwrap_or_default();
let end = find_end_token(parse, rest, &Kind::ParenStart, &Kind::ParenEnd)?;
let children = rest.get(0..end).unwrap_or_default();
list.push(parse_thunk(parse, token, &rest[end], children)?);
iter.nth(end + 1);
}
Kind::Comment | Kind::Space => match list.last_mut() {
Some(Node::Space(s)) => *s = s.expand(0, token.data.len()),
Some(_) => list.push(parse_space(parse, token)),
None => {}
},
Kind::Comma => {
list.push(parse_comma(parse, token));
}
Kind::StringDQ | Kind::StringSQ => {
list.push(parse_string(parse, token));
}
Kind::Tag => {
list.push(parse_tag(parse, token));
}
Kind::Number => {
list.push(parse_bytes(parse, token));
}
Kind::Label => {
list.push(parse_label(parse, token)?);
}
Kind::Dot => {
list.push(parse_label(parse, token)?);
}
Kind::DotDot => {
list.push(parse_label(parse, token)?);
}
Kind::DotDotDot => {
list.push(parse_label(parse, token)?);
}
_ => {
return parse_error(parse, parse.span.zoom(token.span));
}
}
}
Ok(match parent {
Parent::Pipe => remove_outer_space(list),
Parent::List => remove_all_space(list),
Parent::Map => remove_all_space(list),
})
}
fn pipe_root_values(parse: &Parse<'_, '_>, list: Vec<Node>, next: &Token<'_>) -> Vec<Node> {
let span = match list.first() {
Some(Node::Pipe(..)) => return list,
Some(Node::Paren(..)) => return list,
Some(Node::Bracket(..)) => return list,
Some(Node::And(..)) => return list,
Some(Node::Or(..)) => return list,
Some(Node::Semicolon(..)) => return list,
Some(p) => Span::new(Span::from(p).0, parse.span.lo() + next.span.lo()),
None => Span::new(parse.span.lo(), parse.span.lo() + next.span.lo()),
};
vec![Node::Pipe(span, remove_outer_space(list))]
}
fn remove_outer_space(mut list: Vec<Node>) -> Vec<Node> {
while matches!(list.first(), Some(Node::Space(_))) {
list.remove(0);
}
while matches!(list.last(), Some(Node::Space(_))) {
list.pop();
}
list
}
fn remove_all_space(mut list: Vec<Node>) -> Vec<Node> {
list.retain(|p| !matches!(p, Node::Space(_)));
list
}
fn sequence_boundary_at(list: &[Node]) -> bool {
matches!(list.last(), None | Some(Node::Space(_) | Node::Comma(_)))
}
fn thunk_starts_at(tokens: &[Token<'_>], index: usize) -> bool {
tokens.get(index).is_some_and(|t| t.data == b":")
&& tokens
.get(index + 1)
.is_some_and(|t| t.kind == Kind::ParenStart)
}
fn parse_error<T>(parse: &Parse<'_, '_>, span: Span) -> Result<T, Error> {
Err(Error {
kind: ErrorKind::Parse,
source: parse.source.map(String::from),
message: String::from_utf8_lossy(parse.data).into_owned(),
span,
})
}
fn parse_pipe(
parse: &Parse<'_, '_>,
start: &Token<'_>,
children: &[Token<'_>],
) -> Result<Node, Error> {
let inner = Span::new(
parse.span.lo() + start.span.hi(),
children
.last()
.map(|t| parse.span.lo() + t.span.hi())
.unwrap_or(parse.span.lo() + start.span.hi()),
);
match start.kind {
Kind::Pipe => Ok(Node::Pipe(
inner,
parse_children(parse, &Parent::Pipe, children)?,
)),
Kind::And => Ok(Node::And(
inner,
parse_children(parse, &Parent::Pipe, children)?,
)),
Kind::Or => Ok(Node::Or(
inner,
parse_children(parse, &Parent::Pipe, children)?,
)),
Kind::Semicolon => Ok(Node::Semicolon(
inner,
parse_children(parse, &Parent::Pipe, children)?,
)),
_ => unreachable!("{start:?}"),
}
}
fn parse_map(
parse: &Parse<'_, '_>,
start: &Token<'_>,
end: &Token<'_>,
children: &[Token<'_>],
) -> Result<Node, Error> {
Ok(Node::Map(
Span::new(
parse.span.lo() + start.span.hi(),
parse.span.lo() + end.span.lo(),
),
parse_children(parse, &Parent::Map, children)?,
))
}
fn parse_list(
parse: &Parse<'_, '_>,
start: &Token<'_>,
end: &Token<'_>,
children: &[Token<'_>],
) -> Result<Node, Error> {
Ok(Node::List(
Span::new(
parse.span.lo() + start.span.hi(),
parse.span.lo() + end.span.lo(),
),
parse_children(parse, &Parent::List, children)?,
))
}
fn parse_paren(
parse: &Parse<'_, '_>,
start: &Token<'_>,
end: &Token<'_>,
children: &[Token<'_>],
) -> Result<Node, Error> {
Ok(Node::Paren(
Span::new(
parse.span.lo() + start.span.hi(),
parse.span.lo() + end.span.lo(),
),
parse_children(parse, &Parent::Pipe, children)?,
))
}
fn parse_bracket(
parse: &Parse<'_, '_>,
start: &Token<'_>,
end: &Token<'_>,
children: &[Token<'_>],
) -> Result<Node, Error> {
Ok(Node::Bracket(
Span::new(
parse.span.lo() + start.span.hi(),
parse.span.lo() + end.span.lo(),
),
parse_children(parse, &Parent::Pipe, children)?,
))
}
fn parse_thunk(
parse: &Parse<'_, '_>,
start: &Token<'_>,
end: &Token<'_>,
children: &[Token<'_>],
) -> Result<Node, Error> {
Ok(Node::Thunk(
Span::new(
parse.span.lo() + start.span.hi() + 1,
parse.span.lo() + end.span.lo(),
),
parse_children(parse, &Parent::Pipe, children)?,
))
}
fn parse_string(parse: &Parse<'_, '_>, token: &Token<'_>) -> Node {
Node::Bytes(
parse.span.zoom(token.span).contract(1, 1),
token
.data
.get(1..(token.data.len() - 1))
.unwrap_or_default()
.to_vec(),
)
}
fn parse_tag(parse: &Parse<'_, '_>, token: &Token<'_>) -> Node {
Node::Tag(parse.span.zoom(token.span), token.data.to_vec())
}
fn parse_comma(parse: &Parse<'_, '_>, token: &Token<'_>) -> Node {
Node::Comma(parse.span.zoom(token.span))
}
fn parse_label(parse: &Parse<'_, '_>, token: &Token<'_>) -> Result<Node, Error> {
match Label::new(token.data.to_vec()) {
Some(l) => Ok(Node::Label(parse.span.zoom(token.span), l)),
None => parse_error(parse, parse.span),
}
}
fn parse_bytes(parse: &Parse<'_, '_>, token: &Token<'_>) -> Node {
Node::Bytes(parse.span.zoom(token.span), token.data.to_vec())
}
fn parse_space(parse: &Parse<'_, '_>, token: &Token<'_>) -> Node {
Node::Space(parse.span.zoom(token.span))
}
fn find_next_pipe(tokens: &[Token<'_>]) -> usize {
let mut depth = 0;
let end = tokens.iter().position(|p| {
if p.kind.is_start() {
depth += 1;
false
} else if p.kind.is_end() {
depth -= 1;
false
} else {
depth == 0 && p.kind.is_pipe()
}
});
end.unwrap_or(tokens.len())
}
fn find_end_token(
parse: &Parse<'_, '_>,
tokens: &[Token<'_>],
start: &Kind,
end: &Kind,
) -> Result<usize, Error> {
let mut depth = 0;
let end = tokens.iter().position(|p| {
if &p.kind == start {
depth += 1;
false
} else if &p.kind == end && depth > 0 {
depth -= 1;
false
} else {
&p.kind == end
}
});
match end {
Some(end) => Ok(end),
None => parse_error(parse, parse.span),
}
}
#[cfg(test)]
mod test {
use super::Node;
use crate::lang::error::Error;
use crate::value::span::Span;
#[test]
fn test_empty() {
assert_eq!(
parser(b"").unwrap(),
Node::Pipe(Span::new(1000, 1000), vec![])
)
}
#[test]
fn test_bool() {
assert_eq!(
parser(b"true").unwrap(),
Node::Pipe(
Span::new(1000, 1004),
vec![Node::Label(Span::new(1000, 1004), b"true".into())]
)
)
}
#[test]
fn test_number() {
assert_eq!(
parser(b"-1.2").unwrap(),
Node::Pipe(
Span::new(1000, 1004),
vec![Node::Bytes(Span::new(1000, 1004), b"-1.2".to_vec())]
)
)
}
#[test]
fn test_string_sq() {
assert_eq!(
parser(b"'x'").unwrap(),
Node::Pipe(
Span::new(1000, 1003),
vec![Node::Bytes(Span::new(1001, 1002), b"x".to_vec())]
)
)
}
#[test]
fn test_string_dq() {
assert_eq!(
parser(br#""x""#).unwrap(),
Node::Pipe(
Span::new(1000, 1003),
vec![Node::Bytes(Span::new(1001, 1002), b"x".to_vec())]
)
)
}
#[test]
fn test_tags() {
assert_eq!(
parser(b"<x> 1 </x>").unwrap(),
Node::Pipe(
Span::new(1000, 1010),
vec![
Node::Tag(Span::new(1000, 1003), b"<x>".to_vec()),
Node::Space(Span::new(1003, 1004)),
Node::Bytes(Span::new(1004, 1005), b"1".to_vec()),
Node::Space(Span::new(1005, 1006)),
Node::Tag(Span::new(1006, 1010), b"</x>".to_vec())
]
)
)
}
#[test]
fn test_label() {
assert_eq!(
parser(b"a").unwrap(),
Node::Pipe(
Span::new(1000, 1001),
vec![Node::Label(Span::new(1000, 1001), b"a".into())]
)
)
}
#[test]
fn test_dots() {
assert_eq!(
parser(b"a.b.c").unwrap(),
Node::Pipe(
Span::new(1000, 1005),
vec![Node::Label(Span::new(1000, 1005), b"a.b.c".into())]
)
)
}
#[test]
fn test_and() {
assert_eq!(
parser(br#"x&&'1'"#).unwrap(),
Node::Pipe(
Span::new(1000, 1006),
vec![
Node::Pipe(
Span::new(1000, 1001),
vec![Node::Label(Span::new(1000, 1001), b"x".into())]
),
Node::And(
Span::new(1003, 1006),
vec![Node::Bytes(Span::new(1004, 1005), b"1".to_vec())],
),
]
)
)
}
#[test]
fn test_or() {
assert_eq!(
parser(b"z || get x ").unwrap(),
Node::Pipe(
Span::new(1000, 1011),
vec![
Node::Pipe(
Span::new(1000, 1002),
vec![Node::Label(Span::new(1000, 1001), b"z".into())],
),
Node::Or(
Span::new(1004, 1011),
vec![
Node::Label(Span::new(1005, 1008), b"get".into()),
Node::Space(Span::new(1008, 1009)),
Node::Label(Span::new(1009, 1010), b"x".into()),
],
),
]
)
)
}
#[test]
fn test_semicolon() {
assert_eq!(
parser(b"a;b").unwrap(),
Node::Pipe(
Span::new(1000, 1003),
vec![
Node::Pipe(
Span::new(1000, 1001),
vec![Node::Label(Span::new(1000, 1001), b"a".into())],
),
Node::Semicolon(
Span::new(1002, 1003),
vec![Node::Label(Span::new(1002, 1003), b"b".into())],
),
]
)
)
}
#[test]
fn test_pipes() {
assert_eq!(
parser(br#"a|"b"&&true c||x 1"#).unwrap(),
Node::Pipe(
Span::new(1000, 1018),
vec![
Node::Pipe(
Span::new(1000, 1001),
vec![Node::Label(Span::new(1000, 1001), b"a".into())]
),
Node::Pipe(
Span::new(1002, 1005),
vec![Node::Bytes(Span::new(1003, 1004), b"b".into())]
),
Node::And(
Span::new(1007, 1013),
vec![
Node::Label(Span::new(1007, 1011), b"true".into()),
Node::Space(Span::new(1011, 1012)),
Node::Label(Span::new(1012, 1013), b"c".into()),
]
),
Node::Or(
Span::new(1015, 1018),
vec![
Node::Label(Span::new(1015, 1016), b"x".into()),
Node::Space(Span::new(1016, 1017)),
Node::Bytes(Span::new(1017, 1018), b"1".to_vec()),
]
)
]
)
)
}
#[test]
fn test_empty_pipes() {
assert_eq!(
parser(br#"|"#).unwrap(),
Node::Pipe(
Span::new(1000, 1001),
vec![
Node::Pipe(Span::new(1000, 1000), vec![]),
Node::Pipe(Span::new(1001, 1001), vec![])
]
)
);
assert_eq!(
parser(br#"| | |"#).unwrap(),
Node::Pipe(
Span::new(1000, 1005),
vec![
Node::Pipe(Span::new(1000, 1000), vec![]),
Node::Pipe(Span::new(1001, 1002), vec![]),
Node::Pipe(Span::new(1003, 1004), vec![]),
Node::Pipe(Span::new(1005, 1005), vec![])
]
)
);
assert_eq!(
parser(br#"|||"#).unwrap(),
Node::Pipe(
Span::new(1000, 1003),
vec![
Node::Pipe(Span::new(1000, 1000), vec![]),
Node::Or(Span::new(1002, 1002), vec![]),
Node::Pipe(Span::new(1003, 1003), vec![])
]
)
);
assert_eq!(
parser(br#"&&&&"#).unwrap(),
Node::Pipe(
Span::new(1000, 1004),
vec![
Node::Pipe(Span::new(1000, 1000), vec![]),
Node::And(Span::new(1002, 1002), vec![]),
Node::And(Span::new(1004, 1004), vec![])
]
)
);
assert_eq!(
parser(br#"1 ||| 2"#).unwrap(),
Node::Pipe(
Span::new(1000, 1007),
vec![
Node::Pipe(
Span::new(1000, 1002),
vec![Node::Bytes(Span::new(1000, 1001), b"1".to_vec())]
),
Node::Or(Span::new(1004, 1004), vec![]),
Node::Pipe(
Span::new(1005, 1007),
vec![Node::Bytes(Span::new(1006, 1007), b"2".to_vec())]
),
]
)
);
}
#[test]
fn test_nested_pipes() {
assert_eq!(
parser(br#" a |(b|c)|d"#).unwrap(),
Node::Pipe(
Span::new(1000, 1011),
vec![
Node::Pipe(
Span::new(1001, 1003),
vec![Node::Label(Span::new(1001, 1002), b"a".into())]
),
Node::Pipe(
Span::new(1004, 1009),
vec![Node::Paren(
Span::new(1005, 1008),
vec![
Node::Pipe(
Span::new(1005, 1006),
vec![Node::Label(Span::new(1005, 1006), b"b".into())]
),
Node::Pipe(
Span::new(1007, 1008),
vec![Node::Label(Span::new(1007, 1008), b"c".into())]
)
]
)]
),
Node::Pipe(
Span::new(1010, 1011),
vec![Node::Label(Span::new(1010, 1011), b"d".into())]
),
]
)
)
}
#[test]
fn test_list() {
assert_eq!(
parser(b"['1' a]").unwrap(),
Node::Pipe(
Span::new(1000, 1008),
vec![Node::List(
Span::new(1001, 1007),
vec![
Node::Bytes(Span::new(1002, 1003), b"1".to_vec()),
Node::Label(Span::new(1006, 1007), b"a".into()),
]
)]
)
)
}
#[test]
fn test_empty_list() {
assert_eq!(
parser(b"[]").unwrap(),
Node::Pipe(
Span::new(1000, 1002),
vec![Node::List(Span::new(1001, 1001), vec![])]
)
);
}
#[test]
fn test_nested_list() {
assert_eq!(
parser(br#"[[[ (1) ]]]"#).unwrap(),
Node::Pipe(
Span::new(1000, 1011),
vec![Node::List(
Span::new(1001, 1010),
vec![Node::List(
Span::new(1002, 1009),
vec![Node::List(
Span::new(1003, 1008),
vec![Node::Paren(
Span::new(1005, 1006),
vec![Node::Bytes(Span::new(1005, 1006), b"1".to_vec())]
)],
)],
)],
)]
)
)
}
#[test]
fn test_map() {
assert_eq!(
parser(b"{x x y (x.y)}").unwrap(),
Node::Pipe(
Span::new(1000, 1013),
vec![Node::Map(
Span::new(1001, 1012),
vec![
Node::Label(Span::new(1001, 1002), b"x".into()),
Node::Label(Span::new(1003, 1004), b"x".into()),
Node::Label(Span::new(1005, 1006), b"y".into()),
Node::Paren(
Span::new(1008, 1011),
vec![Node::Label(Span::new(1008, 1011), b"x.y".into())]
),
]
)]
)
)
}
#[test]
fn test_nested_map() {
assert_eq!(
parser(br#"{a {b 6}}.a.b"#).unwrap(),
Node::Pipe(
Span::new(1000, 1013),
vec![
Node::Map(
Span::new(1001, 1008),
vec![
Node::Label(Span::new(1001, 1002), b"a".into()),
Node::Map(
Span::new(1004, 1007),
vec![
Node::Label(Span::new(1004, 1005), b"b".into()),
Node::Bytes(Span::new(1006, 1007), b"6".into()),
]
)
]
),
Node::Label(Span::new(1009, 1010), b".".into()),
Node::Label(Span::new(1010, 1013), b"a.b".into())
]
)
)
}
#[test]
fn test_empty_map() {
assert_eq!(
parser(b"{}").unwrap(),
Node::Pipe(
Span::new(1000, 1002),
vec![Node::Map(Span::new(1001, 1001), vec![])]
),
);
}
#[test]
fn test_keys() {
assert_eq!(
parser(br#"a[b]["c"]d"#).unwrap(),
Node::Pipe(
Span::new(1000, 1010),
vec![
Node::Label(Span::new(1000, 1001), b"a".into()),
Node::Bracket(
Span::new(1002, 1003),
vec![Node::Label(Span::new(1002, 1003), b"b".into())],
),
Node::Bracket(
Span::new(1005, 1008),
vec![Node::Bytes(Span::new(1006, 1007), b"c".to_vec())],
),
Node::Label(Span::new(1009, 1010), b"d".into()),
]
)
)
}
#[test]
fn test_list_keys() {
assert_eq!(
parser(b"[1 2][3]").unwrap(),
Node::Pipe(
Span::new(1000, 1008),
vec![
Node::List(
Span::new(1001, 1004),
vec![
Node::Bytes(Span::new(1001, 1002), b"1".to_vec()),
Node::Bytes(Span::new(1003, 1004), b"2".to_vec()),
]
),
Node::Bracket(
Span::new(1006, 1007),
vec![Node::Bytes(Span::new(1006, 1007), b"3".to_vec())]
),
]
)
)
}
#[test]
fn test_map_keys() {
assert_eq!(
parser(b"{a 1}.a #a ").unwrap(),
Node::Pipe(
Span::new(1000, 1011),
vec![
Node::Map(
Span::new(1001, 1004),
vec![
Node::Label(Span::new(1001, 1002), b"a".into()),
Node::Bytes(Span::new(1003, 1004), b"1".to_vec()),
]
),
Node::Label(Span::new(1005, 1006), b".".into()),
Node::Label(Span::new(1006, 1007), b"a".into()),
]
)
)
}
#[test]
fn test_empty_keys() {
assert_eq!(
parser(br#"."#).unwrap(),
Node::Pipe(
Span::new(1000, 1001),
vec![Node::Label(Span::new(1000, 1001), b".".into())]
)
);
assert_eq!(
parser(br#".a"#).unwrap(),
Node::Pipe(
Span::new(1000, 1002),
vec![
Node::Label(Span::new(1000, 1001), b".".into()),
Node::Label(Span::new(1001, 1002), b"a".into())
]
)
);
assert_eq!(
parser(br#".."#).unwrap(),
Node::Pipe(
Span::new(1000, 1002),
vec![Node::Label(Span::new(1000, 1002), b"..".into())]
)
);
assert_eq!(
parser(br#"..a"#).unwrap(),
Node::Pipe(
Span::new(1000, 1003),
vec![
Node::Label(Span::new(1000, 1002), b"..".into()),
Node::Label(Span::new(1002, 1003), b"a".into())
]
)
);
assert_eq!(
parser(br#"..."#).unwrap(),
Node::Pipe(
Span::new(1000, 1003),
vec![Node::Label(Span::new(1000, 1003), b"...".into())]
)
);
assert_eq!(
parser(br#"...a"#).unwrap(),
Node::Pipe(
Span::new(1000, 1004),
vec![
Node::Label(Span::new(1000, 1003), b"...".into()),
Node::Label(Span::new(1003, 1004), b"a".into())
]
)
);
assert_eq!(
parser(br#"[].."#).unwrap(),
Node::Pipe(
Span::new(1000, 1004),
vec![
Node::List(Span::new(1001, 1001), vec![]),
Node::Label(Span::new(1002, 1004), b"..".into())
]
)
);
}
#[test]
fn test_parens() {
assert_eq!(
parser(b"(1&&2) || 3").unwrap(),
Node::Pipe(
Span::new(1000, 1011),
vec![
Node::Paren(
Span::new(1001, 1005),
vec![
Node::Pipe(
Span::new(1001, 1002),
vec![Node::Bytes(Span::new(1001, 1002), b"1".to_vec())]
),
Node::And(
Span::new(1004, 1005),
vec![Node::Bytes(Span::new(1004, 1005), b"2".to_vec())]
)
]
),
Node::Space(Span::new(1006, 1007)),
Node::Or(
Span::new(1009, 1011),
vec![Node::Bytes(Span::new(1010, 1011), b"3".to_vec())]
)
]
)
)
}
#[test]
fn test_thunk() {
assert_eq!(
parser(b"map :((_))").unwrap(),
Node::Pipe(
Span::new(1000, 1010),
vec![
Node::Label(Span::new(1000, 1003), b"map".into()),
Node::Space(Span::new(1003, 1004)),
Node::Thunk(
Span::new(1006, 1009),
vec![Node::Paren(
Span::new(1007, 1008),
vec![Node::Label(Span::new(1007, 1008), b"_".into())]
)]
)
]
)
)
}
#[test]
fn test_misc() {
assert_eq!(
parser(br#"a._b-[c]..d[true]"#).unwrap(),
Node::Pipe(
Span::new(1000, 1017),
vec![
Node::Label(Span::new(1000, 1005), b"a._b-".into()),
Node::Bracket(
Span::new(1006, 1007),
vec![Node::Label(Span::new(1006, 1007), b"c".into())]
),
Node::Label(Span::new(1008, 1010), b"..".into()),
Node::Label(Span::new(1010, 1011), b"d".into()),
Node::Bracket(
Span::new(1012, 1016),
vec![Node::Label(Span::new(1012, 1016), b"true".into())]
),
]
),
)
}
#[test]
fn test_err() {
assert!(parser(br#""a"{b}"#).is_err());
assert!(parser(b"a{b}").is_err());
assert!(parser(br"\").is_err());
assert!(parser(b"<").is_err());
assert!(parser(b">").is_err());
assert!(parser(b"!").is_err());
assert!(parser(b"?").is_err());
assert!(parser(b"%").is_err());
assert!(parser(b"&").is_err());
assert!(parser(b"/").is_err());
assert!(parser(b"%").is_err());
assert!(parser(b"~").is_err());
assert!(parser(b"$").is_err());
assert!(parser(b"=").is_err());
assert!(parser(b"+").is_err());
assert!(parser(b"*").is_err());
assert!(parser(b"@").is_err());
assert!(parser(b"`").is_err());
assert!(parser("´".as_bytes()).is_err());
assert!(parser("👾".as_bytes()).is_err());
assert!(parser(b":").is_err());
assert!(!parser(b";").is_err());
assert!(!parser(b":b").is_err());
assert!(!parser(br#""a"[b]"#).is_err());
assert!(!parser(br#""a"(b)"#).is_err());
assert!(!parser(b"a(b)").is_err());
assert!(!parser(b"a:").is_err());
assert!(!parser(b"a:b").is_err());
}
#[track_caller]
fn parser(data: &[u8]) -> Result<Node, Error> {
super::parse(None, Span::new(1000, 1000 + data.len()), data)
}
}