behavior_tree_lite/parser/
nom_parser.rs

1use nom::{
2    branch::alt,
3    bytes::complete::{is_not, tag},
4    character::complete::{
5        alpha1, alphanumeric1, char, multispace0, newline, none_of, one_of, space0,
6    },
7    combinator::{opt, recognize, value},
8    multi::{many0, many1, separated_list1},
9    sequence::{delimited, pair, preceded, terminated, tuple},
10    Finish, IResult,
11};
12
13use crate::{BlackboardValueOwned, PortType};
14
15#[derive(Debug, PartialEq)]
16pub struct NodeDef<'src> {
17    name: &'src str,
18    ports: Vec<PortDef<'src>>,
19}
20
21impl<'src> NodeDef<'src> {
22    pub fn new(name: &'src str) -> Self {
23        Self {
24            name,
25            ports: Vec::new(),
26        }
27    }
28
29    pub fn name(&self) -> &str {
30        self.name
31    }
32
33    pub fn ports(&self) -> &[PortDef<'src>] {
34        &self.ports
35    }
36}
37
38#[derive(Debug, PartialEq)]
39pub struct PortDef<'src> {
40    pub direction: PortType,
41    pub name: &'src str,
42    pub ty: Option<&'src str>,
43}
44
45fn identifier(input: &str) -> IResult<&str, &str> {
46    recognize(pair(
47        alt((alpha1, tag("_"))),
48        many0(alt((alphanumeric1, tag("_")))),
49    ))(input)
50}
51
52fn newlines(i: &str) -> IResult<&str, ()> {
53    delimited(space0, many1(one_of("\r\n")), space0)(i).map(|(rest, _)| (rest, ()))
54}
55
56fn port_def(i: &str) -> IResult<&str, PortDef> {
57    let (i, inout) = delimited(space0, alt((tag("in"), tag("out"), tag("inout"))), space0)(i)?;
58    let (i, name) = identifier(i)?;
59    let (i, ty) = opt(preceded(delimited(space0, char(':'), space0), identifier))(i)?;
60    let (i, _) = multispace0(i)?;
61    let direction = match inout {
62        "in" => PortType::Input,
63        "out" => PortType::Output,
64        "inout" => PortType::InOut,
65        _ => {
66            return Err(nom::Err::Failure(nom::error::Error::new(
67                i,
68                nom::error::ErrorKind::Verify,
69            )))
70        }
71    };
72    Ok((
73        i,
74        PortDef {
75            direction,
76            name,
77            ty,
78        },
79    ))
80}
81
82fn ports_def(i: &str) -> IResult<&str, Vec<PortDef>> {
83    let (i, _) = many0(newlines)(i)?;
84
85    let (i, v) = many0(delimited(space0, port_def, many0(pair(space0, newlines))))(i)?;
86
87    let (i, _) = many0(newlines)(i)?;
88
89    Ok((i, v))
90}
91
92fn open_paren(i: &str) -> IResult<&str, ()> {
93    value((), delimited(space0, char('('), space0))(i)
94}
95
96fn close_paren(i: &str) -> IResult<&str, ()> {
97    value((), delimited(space0, char(')'), space0))(i)
98}
99
100fn open_brace(i: &str) -> IResult<&str, ()> {
101    value((), delimited(space0, char('{'), space0))(i)
102}
103
104fn close_brace(i: &str) -> IResult<&str, ()> {
105    value((), delimited(space0, char('}'), space0))(i)
106}
107
108pub fn node_def(i: &str) -> IResult<&str, NodeDef> {
109    let (i, _) = delimited(multispace0, tag("node"), space0)(i)?;
110
111    let (i, name) = delimited(space0, alphanumeric1, space0)(i)?;
112
113    let (i, ports) = delimited(open_brace, ports_def, close_brace)(i)?;
114
115    Ok((i, NodeDef { name, ports }))
116}
117
118pub fn parse_nodes(i: &str) -> IResult<&str, Vec<NodeDef>> {
119    many0(node_def)(i)
120}
121
122#[derive(Debug, PartialEq, Eq)]
123pub struct TreeDef<'src> {
124    pub(crate) ty: &'src str,
125    pub(crate) port_maps: Vec<PortMap<'src>>,
126    pub(crate) children: Vec<TreeDef<'src>>,
127    pub(crate) vars: Vec<VarDef<'src>>,
128}
129
130impl<'src> TreeDef<'src> {
131    pub fn get_type(&self) -> &str {
132        self.ty
133    }
134
135    pub fn port_maps(&self) -> &[PortMap<'src>] {
136        &self.port_maps
137    }
138
139    pub fn children(&self) -> &[TreeDef<'src>] {
140        &self.children
141    }
142}
143
144#[derive(Debug, PartialEq, Eq)]
145pub struct VarDef<'src> {
146    pub(crate) name: &'src str,
147    pub(crate) init: Option<&'src str>,
148}
149
150#[derive(Debug, PartialEq, Eq)]
151pub struct VarAssign<'src> {
152    pub(crate) name: &'src str,
153    pub(crate) init: &'src str,
154}
155
156impl<'src> TreeDef<'src> {
157    #[allow(dead_code)]
158    fn new(ty: &'src str) -> Self {
159        Self {
160            ty,
161            port_maps: vec![],
162            children: vec![],
163            vars: vec![],
164        }
165    }
166
167    #[allow(dead_code)]
168    fn new_with_child(ty: &'src str, child: TreeDef<'src>) -> Self {
169        Self {
170            ty,
171            port_maps: vec![],
172            children: vec![child],
173            vars: vec![],
174        }
175    }
176
177    fn new_with_children(ty: &'src str, children: Vec<TreeDef<'src>>) -> Self {
178        Self {
179            ty,
180            port_maps: vec![],
181            children,
182            vars: vec![],
183        }
184    }
185
186    #[allow(dead_code)]
187    fn new_with_children_and_vars(
188        ty: &'src str,
189        children: Vec<TreeDef<'src>>,
190        vars: Vec<VarDef<'src>>,
191    ) -> Self {
192        Self {
193            ty,
194            port_maps: vec![],
195            children,
196            vars,
197        }
198    }
199
200    fn new_with_tree_elems(ty: &'src str, children: Vec<TreeElem<'src>>) -> Self {
201        Self::new_with_ports_and_tree_elems(ty, vec![], children)
202    }
203
204    #[allow(dead_code)]
205    fn new_with_ports(ty: &'src str, port_maps: Vec<PortMap<'src>>) -> Self {
206        Self::new_with_ports_and_tree_elems(ty, port_maps, vec![])
207    }
208
209    fn new_with_ports_and_tree_elems(
210        ty: &'src str,
211        port_maps: Vec<PortMap<'src>>,
212        children: Vec<TreeElem<'src>>,
213    ) -> Self {
214        fn new_set_bool(name: &str, init: String) -> TreeDef {
215            TreeDef::new_with_ports(
216                "SetBool",
217                vec![
218                    PortMap {
219                        node_port: "value",
220                        blackboard_value: BlackboardValue::Literal(init),
221                        ty: PortType::Input,
222                    },
223                    PortMap {
224                        node_port: "output",
225                        blackboard_value: BlackboardValue::Ref(name),
226                        ty: PortType::Output,
227                    },
228                ],
229            )
230        }
231
232        let (children, vars) = children.into_iter().fold((vec![], vec![]), |mut acc, cur| {
233            match cur {
234                TreeElem::Node(node) => acc.0.push(node),
235                TreeElem::Var(var) => {
236                    if let Some(init) = var.init {
237                        acc.0.push(new_set_bool(var.name, init.to_owned()));
238                    }
239                    acc.1.push(var);
240                }
241                TreeElem::VarAssign(var) => {
242                    acc.0.push(new_set_bool(var.name, var.init.to_owned()));
243                }
244            }
245            acc
246        });
247
248        Self {
249            ty,
250            port_maps,
251            children,
252            vars,
253        }
254    }
255}
256
257#[derive(Debug, PartialEq, Eq)]
258pub enum BlackboardValue<'src> {
259    /// Literal value could have been decoded, so it is an owned string.
260    Literal(String),
261    Ref(&'src str),
262}
263
264impl<'src> BlackboardValue<'src> {
265    fn to_owned(&self) -> BlackboardValueOwned {
266        match self {
267            Self::Literal(s) => BlackboardValueOwned::Literal(s.clone()),
268            Self::Ref(s) => BlackboardValueOwned::Ref(s.to_string()),
269        }
270    }
271}
272
273#[derive(Debug, PartialEq, Eq)]
274pub struct PortMap<'src> {
275    pub(crate) ty: PortType,
276    pub(crate) node_port: &'src str,
277    pub(crate) blackboard_value: BlackboardValue<'src>,
278}
279
280impl<'src> PortMap<'src> {
281    pub fn get_type(&self) -> PortType {
282        self.ty
283    }
284
285    pub fn node_port(&self) -> &'src str {
286        self.node_port
287    }
288
289    pub fn blackboard_value(&self) -> &BlackboardValue<'src> {
290        &self.blackboard_value
291    }
292
293    pub fn to_owned(&self) -> PortMapOwned {
294        PortMapOwned {
295            ty: self.ty,
296            node_port: self.node_port.to_owned(),
297            blackboard_value: self.blackboard_value.to_owned(),
298        }
299    }
300}
301
302#[derive(Debug, PartialEq, Eq)]
303pub struct PortMapOwned {
304    pub(crate) ty: PortType,
305    pub(crate) node_port: String,
306    pub(crate) blackboard_value: BlackboardValueOwned,
307}
308
309impl PortMapOwned {
310    pub fn new(ty: PortType, node_port: String, blackboard_value: BlackboardValueOwned) -> Self {
311        Self {
312            ty,
313            node_port,
314            blackboard_value,
315        }
316    }
317}
318
319fn subtree_ports_def(i: &str) -> IResult<&str, Vec<PortDef>> {
320    let (i, ports) = delimited(
321        open_paren,
322        many0(delimited(space0, port_def, opt(char(',')))),
323        close_paren,
324    )(i)?;
325    Ok((i, ports))
326}
327
328#[derive(Debug, PartialEq)]
329pub struct TreeRootDef<'src> {
330    pub(crate) name: &'src str,
331    pub(crate) root: TreeDef<'src>,
332    pub(crate) ports: Vec<PortDef<'src>>,
333}
334
335impl<'src> TreeRootDef<'src> {
336    pub fn name(&self) -> &str {
337        self.name
338    }
339
340    pub fn root(&self) -> &TreeDef<'src> {
341        &self.root
342    }
343
344    pub fn ports(&self) -> &[PortDef<'src>] {
345        &self.ports
346    }
347}
348
349fn parse_tree(i: &str) -> IResult<&str, TreeRootDef> {
350    let (i, _) = delimited(multispace0, tag("tree"), space0)(i)?;
351
352    let (i, name) = delimited(space0, identifier, space0)(i)?;
353
354    let (i, ports) = opt(subtree_ports_def)(i)?;
355
356    let (i, _) = delimited(space0, tag("="), space0)(i)?;
357
358    let (i, root) = parse_conditional_expr(i)?;
359
360    Ok((
361        i,
362        TreeRootDef {
363            name,
364            root,
365            ports: ports.unwrap_or_default(),
366        },
367    ))
368}
369
370fn line_comment<T>(i: &str) -> IResult<&str, Option<T>> {
371    let (i, _) = tuple((space0, char('#'), opt(is_not("\n\r"))))(i)?;
372
373    Ok((i, None))
374}
375
376fn line_comment_tree_elem(i: &str) -> IResult<&str, Option<TreeElem>> {
377    line_comment::<TreeElem>(i)
378}
379
380fn some<I, R>(f: impl Fn(I) -> IResult<I, R>) -> impl Fn(I) -> IResult<I, Option<R>> {
381    move |i| {
382        let (i, res) = f(i)?;
383        Ok((i, Some(res)))
384    }
385}
386
387#[derive(Debug)]
388enum TreeElem<'src> {
389    Node(TreeDef<'src>),
390    Var(VarDef<'src>),
391    VarAssign(VarAssign<'src>),
392}
393
394fn tree_children(i: &str) -> IResult<&str, Vec<TreeElem>> {
395    let (i, _) = many0(newlines)(i)?;
396
397    let (i, v) = many0(delimited(
398        space0,
399        alt((
400            line_comment,
401            some(var_assign),
402            some(var_decl),
403            some(parse_condition_node),
404            some(parse_tree_elem),
405        )),
406        many0(newlines),
407    ))(i)?;
408
409    let (i, _) = many0(newlines)(i)?;
410
411    Ok((i, v.into_iter().flatten().collect()))
412}
413
414fn parse_tree_node(i: &str) -> IResult<&str, TreeDef> {
415    let (i, ty) = delimited(space0, identifier, space0)(i)?;
416
417    let (i, input_ports) = opt(delimited(open_paren, port_maps, close_paren))(i)?;
418
419    let (i, children) = opt(delimited(open_brace, tree_children, close_brace))(i)?;
420
421    let (i, _) = opt(line_comment_tree_elem)(i)?;
422
423    Ok((
424        i,
425        TreeDef::new_with_ports_and_tree_elems(
426            ty,
427            input_ports.unwrap_or(vec![]),
428            children.unwrap_or(vec![]),
429        ),
430    ))
431}
432
433fn parse_tree_elem(i: &str) -> IResult<&str, TreeElem> {
434    let (i, elem) = parse_conditional_expr(i)?;
435    Ok((i, TreeElem::Node(elem)))
436}
437
438fn parse_conditional_factor(i: &str) -> IResult<&str, TreeDef> {
439    let (i, excl) = opt(delimited(space0, char('!'), space0))(i)?;
440
441    if excl.is_some() {
442        let (i, res) = parse_conditional_factor(i)?;
443
444        Ok((i, TreeDef::new_with_child("Inverter", res)))
445    } else {
446        alt((
447            delimited(open_paren, parse_conditional_expr, close_paren),
448            parse_tree_node,
449        ))(i)
450    }
451}
452
453fn parse_conditional_and(i: &str) -> IResult<&str, TreeDef> {
454    let (i, children) = separated_list1(tag("&&"), parse_conditional_factor)(i)?;
455
456    if children.len() == 1 {
457        Ok((i, children.into_iter().next().unwrap()))
458    } else {
459        Ok((i, TreeDef::new_with_children("Sequence", children)))
460    }
461}
462
463fn parse_conditional_expr(i: &str) -> IResult<&str, TreeDef> {
464    let (i, children) = separated_list1(tag("||"), parse_conditional_and)(i)?;
465
466    if children.len() == 1 {
467        Ok((i, children.into_iter().next().unwrap()))
468    } else {
469        Ok((i, TreeDef::new_with_children("Fallback", children)))
470    }
471}
472
473fn parse_condition_node(i: &str) -> IResult<&str, TreeElem> {
474    let (i, _ty) = delimited(space0, tag("if"), space0)(i)?;
475
476    let (i, condition) = delimited(open_paren, parse_conditional_expr, close_paren)(i)?;
477
478    let (i, then_children) = delimited(open_brace, tree_children, close_brace)(i)?;
479
480    let (i, else_children) = opt(delimited(
481        pair(delimited(space0, tag("else"), space0), open_brace),
482        tree_children,
483        close_brace,
484    ))(i)?;
485
486    let mut children = vec![
487        condition,
488        TreeDef::new_with_tree_elems("Sequence", then_children),
489    ];
490
491    if let Some(else_children) = else_children {
492        children.push(TreeDef::new_with_tree_elems("Sequence", else_children));
493    }
494
495    Ok((
496        i,
497        TreeElem::Node(TreeDef::new_with_children("if", children)),
498    ))
499}
500
501fn var_decl(i: &str) -> IResult<&str, TreeElem> {
502    let (i, _var) = delimited(space0, tag("var"), space0)(i)?;
503
504    let (i, name) = delimited(space0, identifier, space0)(i)?;
505
506    let (i, init) = opt(delimited(
507        delimited(space0, char('='), space0),
508        alt((tag("true"), tag("false"))),
509        space0,
510    ))(i)?;
511
512    let (i, _) = opt(line_comment_tree_elem)(i)?;
513
514    Ok((i, TreeElem::Var(VarDef { name, init })))
515}
516
517fn var_assign(i: &str) -> IResult<&str, TreeElem> {
518    let (i, name) = delimited(space0, identifier, space0)(i)?;
519
520    let (i, _) = delimited(space0, char('='), space0)(i)?;
521
522    let (i, init) = delimited(space0, alt((tag("true"), tag("false"))), space0)(i)?;
523
524    let (i, _) = opt(line_comment_tree_elem)(i)?;
525
526    Ok((i, TreeElem::VarAssign(VarAssign { name, init })))
527}
528
529fn port_maps(i: &str) -> IResult<&str, Vec<PortMap>> {
530    many0(delimited(
531        multispace0,
532        port_map,
533        many0(pair(multispace0, char(','))),
534    ))(i)
535}
536
537fn port_map(i: &str) -> IResult<&str, PortMap> {
538    let (i, node_port) = delimited(space0, identifier, space0)(i)?;
539
540    let (i, inout) = delimited(space0, alt((tag("<->"), tag("<-"), tag("->"))), space0)(i)?;
541
542    let (i, blackboard_name) = delimited(space0, alt((bb_ref, str_literal)), space0)(i)?;
543
544    let ty = match inout {
545        "<-" => PortType::Input,
546        "->" => PortType::Output,
547        "<->" => PortType::InOut,
548        _ => {
549            return Err(nom::Err::Failure(nom::error::Error::new(
550                i,
551                nom::error::ErrorKind::Alt,
552            )))
553        }
554    };
555
556    // You cannot output to a literal! It is a parse error rather than runtime error.
557    if let BlackboardValue::Literal(_) = blackboard_name {
558        if !matches!(ty, PortType::Input) {
559            return Err(nom::Err::Failure(nom::error::Error::new(
560                i,
561                nom::error::ErrorKind::Verify,
562            )));
563        }
564    }
565
566    Ok((
567        i,
568        PortMap {
569            ty,
570            node_port,
571            blackboard_value: blackboard_name,
572        },
573    ))
574}
575
576fn bb_ref(i: &str) -> IResult<&str, BlackboardValue> {
577    let (i, s) = identifier(i)?;
578    Ok((i, BlackboardValue::Ref(s)))
579}
580
581fn str_literal(input: &str) -> IResult<&str, BlackboardValue> {
582    let (r, val) = delimited(
583        preceded(multispace0, char('\"')),
584        many0(none_of("\"")),
585        terminated(char('"'), multispace0),
586    )(input)?;
587    Ok((
588        r,
589        BlackboardValue::Literal(
590            val.iter()
591                .collect::<String>()
592                .replace("\\\\", "\\")
593                .replace("\\n", "\n"),
594        ),
595    ))
596}
597
598pub fn parse_file(i: &str) -> Result<(&str, TreeSource), nom::error::Error<&str>> {
599    source_text(i).finish()
600}
601
602fn source_text(i: &str) -> IResult<&str, TreeSource> {
603    enum NodeOrTree<'src> {
604        Node(NodeDef<'src>),
605        Tree(TreeRootDef<'src>),
606    }
607
608    let (i, stmts) = many0(alt((
609        delimited(multispace0, line_comment, newline),
610        some(|i| {
611            let (i, node) = node_def(i)?;
612            Ok((i, NodeOrTree::Node(node)))
613        }),
614        some(|i| {
615            let (i, tree) = parse_tree(i)?;
616            Ok((i, NodeOrTree::Tree(tree)))
617        }),
618    )))(i)?;
619
620    // Eat up trailing newlines to indicate that the input was thoroughly consumed
621    let (i, _) = multispace0(i)?;
622
623    let (node_defs, tree_defs) =
624        stmts
625            .into_iter()
626            .flatten()
627            .fold((vec![], vec![]), |mut acc, cur| {
628                match cur {
629                    NodeOrTree::Node(node) => acc.0.push(node),
630                    NodeOrTree::Tree(tree) => acc.1.push(tree),
631                }
632                acc
633            });
634
635    Ok((
636        i,
637        TreeSource {
638            node_defs,
639            tree_defs,
640        },
641    ))
642}
643
644#[derive(Debug, PartialEq)]
645pub struct TreeSource<'src> {
646    pub node_defs: Vec<NodeDef<'src>>,
647    pub tree_defs: Vec<TreeRootDef<'src>>,
648}
649
650#[cfg(test)]
651mod test;