behavior_tree_lite/parser/
loader.rs1use std::collections::{HashMap, HashSet};
2
3use super::nom_parser::{TreeDef, TreeSource};
4use crate::{
5 error::{AddChildError, LoadError},
6 nodes::{IsTrueNode, SubtreeNode, INPUT},
7 BBMap, BehaviorNodeContainer, NumChildren, PortSpec, PortType, Registry, Symbol,
8};
9
10pub fn load(
16 tree_source: &TreeSource,
17 registry: &Registry,
18 check_ports: bool,
19) -> Result<BehaviorNodeContainer, LoadError> {
20 let main = tree_source
21 .tree_defs
22 .iter()
23 .find(|tree| tree.name == "main")
24 .ok_or(LoadError::MissingTree)?;
25
26 let top = TreeStack {
27 name: "main",
28 parent: None,
29 };
30
31 let mut vars = HashSet::new();
32
33 load_recurse(
34 &main.root,
35 registry,
36 tree_source,
37 check_ports,
38 &top,
39 &mut vars,
40 )
41}
42
43struct TreeStack<'a, 'src> {
74 name: &'src str,
75 parent: Option<&'a TreeStack<'a, 'src>>,
76}
77
78impl<'a, 'src> TreeStack<'a, 'src> {
79 fn find(&self, name: &str) -> bool {
80 if self.name == name {
81 true
82 } else if let Some(parent) = self.parent {
83 parent.find(name)
84 } else {
85 false
86 }
87 }
88}
89
90fn load_recurse(
91 parent: &TreeDef,
92 registry: &Registry,
93 tree_source: &TreeSource,
94 check_ports: bool,
95 parent_stack: &TreeStack,
96 vars: &mut HashSet<Symbol>,
97) -> Result<BehaviorNodeContainer, LoadError> {
98 let mut ret = if let Some(ret) = registry.build(parent.ty) {
99 BehaviorNodeContainer::new_raw_with_name(ret, parent.ty.to_string())
100 } else {
101 let tree = tree_source
102 .tree_defs
103 .iter()
104 .find(|tree| tree.name == parent.ty)
105 .ok_or_else(|| LoadError::MissingNode(parent.ty.to_owned()))?;
106
107 if parent_stack.find(parent.ty) {
109 return Err(LoadError::InfiniteRecursion {
110 node: parent.ty.to_owned(),
111 });
112 }
113 let tree_stack = TreeStack {
114 name: parent.ty,
115 parent: Some(parent_stack),
116 };
117
118 let mut vars = HashSet::new();
121
122 let loaded_subtree = load_recurse(
123 &tree.root,
124 registry,
125 tree_source,
126 check_ports,
127 &tree_stack,
128 &mut vars,
129 )?;
130 BehaviorNodeContainer {
131 name: parent.ty.to_owned(),
132 node: Box::new(SubtreeNode::new(
133 HashMap::new(),
134 tree.ports
135 .iter()
136 .map(|port| PortSpec {
137 key: port.name.into(),
138 ty: port.direction,
139 })
140 .collect(),
141 )),
142 blackboard_map: HashMap::new(),
143 child_nodes: vec![loaded_subtree],
144 last_result: None,
145 is_subtree: true,
146 subtree_expanded: std::cell::Cell::new(false),
147 }
148 };
149
150 for var_def in &parent.vars {
152 vars.insert(var_def.name.into());
153 }
154
155 for child in &parent.children {
156 let mut new_node = if child.port_maps.is_empty() && child.children.is_empty() {
157 if vars.contains(&child.ty.into()) {
158 let mut bbmap = BBMap::new();
159 bbmap.insert(
160 *INPUT,
161 crate::BlackboardValue::Ref(child.ty.into(), PortType::Input),
162 );
163 Some(
164 BehaviorNodeContainer::new(Box::new(IsTrueNode), bbmap)
165 .with_name("IsTrue".to_owned()),
166 )
167 } else {
168 None
169 }
170 } else {
171 None
172 };
173
174 if new_node.is_none() {
175 let mut child_node = load_recurse(
176 child,
177 registry,
178 tree_source,
179 check_ports,
180 parent_stack,
181 vars,
182 )?;
183 let provided_ports = child_node.node.provided_ports();
184 let mut bbmap = BBMap::new();
185 for entry in child.port_maps.iter() {
186 if check_ports {
187 if let Some(port) = provided_ports.iter().find(|p| p.key == entry.node_port) {
188 if port.ty != entry.ty {
189 return Err(LoadError::PortIOUnmatch {
190 node: child.ty.to_owned(),
191 port: entry.node_port.to_owned(),
192 });
193 }
194 } else {
195 return Err(LoadError::PortUnmatch {
196 node: child.ty.to_owned(),
197 port: entry.node_port.to_owned(),
198 });
199 }
200 }
201 bbmap.insert(
202 entry.node_port.into(),
203 match entry.blackboard_value {
204 super::nom_parser::BlackboardValue::Ref(ref value) => {
205 crate::BlackboardValue::Ref(value.into(), entry.ty)
206 }
207 super::nom_parser::BlackboardValue::Literal(ref value) => {
208 crate::BlackboardValue::Literal(value.clone())
209 }
210 },
211 );
212 }
213 child_node.blackboard_map = bbmap;
214 new_node = Some(child_node);
215 }
216
217 if let Some(new_node) = new_node {
218 if NumChildren::Finite(ret.child_nodes.len()) < ret.node.max_children() {
219 ret.child_nodes.push(new_node);
220 } else {
221 return Err(LoadError::AddChildError(
222 AddChildError::TooManyNodes,
223 parent.ty.to_string(),
224 ));
225 }
226 }
227 }
228
229 Ok(ret)
230}
231
232#[cfg(test)]
233mod test;