Skip to content

Commit e54bcb2

Browse files
committed
fix issue #530: use convertFromString in scripting assignments
1 parent 67cb978 commit e54bcb2

File tree

2 files changed

+71
-2
lines changed

2 files changed

+71
-2
lines changed

include/behaviortree_cpp/scripting/operators.hpp

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ struct ExprAssignment : ExprBase
361361
const auto& key = varname->name;
362362

363363
std::unique_lock entry_lock(env.vars->entryMutex());
364-
auto any_ptr = env.vars->getAny(key);
364+
Any* any_ptr = env.vars->getAny(key);
365365
if( !any_ptr )
366366
{
367367
// variable doesn't exist, create it if using operator assign_create
@@ -379,7 +379,33 @@ struct ExprAssignment : ExprBase
379379

380380
if( op == assign_create || op == assign_existing )
381381
{
382-
value.copyInto(*any_ptr);
382+
// special case first: string to other type
383+
// check if we can use the StringConverter
384+
if(value.isString() && !any_ptr->isString())
385+
{
386+
auto const str = value.cast<std::string>();
387+
if(auto converter = env.vars->portInfo(key)->converter())
388+
{
389+
*any_ptr = converter(str);
390+
}
391+
else {
392+
auto msg = StrCat("Type mismatch in scripting:",
393+
" can't convert the string '", str,
394+
"' to the type expected by that port.\n"
395+
"Have you implemented the relevant "
396+
"convertFromString<T>() ?");
397+
throw RuntimeError(msg);
398+
}
399+
}
400+
else {
401+
try {
402+
value.copyInto(*any_ptr);
403+
}
404+
catch (std::runtime_error) {
405+
throw RuntimeError("A script failed to convert the given type "
406+
"to the one expected by that port.");
407+
}
408+
}
383409
return *any_ptr;
384410
}
385411

tests/gtest_subtree.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <gtest/gtest.h>
22
#include "behaviortree_cpp/bt_factory.h"
33
#include "../sample_nodes/dummy_nodes.h"
4+
#include "../sample_nodes/movebase_node.h"
45

56
using namespace BT;
67

@@ -283,3 +284,45 @@ TEST(SubTree, ScriptRemap)
283284
ASSERT_EQ(tree.subtrees[1]->blackboard->get<int>("value"), 1);
284285
ASSERT_EQ(tree.subtrees[0]->blackboard->get<int>("value"), 1);
285286
}
287+
288+
class ModifyPose : public BT::SyncActionNode
289+
{
290+
public:
291+
// Any TreeNode with ports must have a constructor with this signature
292+
ModifyPose(const std::string& name, const BT::NodeConfig& config)
293+
: SyncActionNode(name, config)
294+
{}
295+
296+
static BT::PortsList providedPorts() {
297+
return{ BT::BidirectionalPort<Pose2D>("pose") };
298+
}
299+
300+
BT::NodeStatus tick() override {
301+
Pose2D pose;
302+
getInput("pose", pose);
303+
pose.theta *= 2;
304+
setOutput("pose", pose);
305+
return NodeStatus::SUCCESS;
306+
}
307+
};
308+
309+
TEST(SubTree, StringConversions_Issue530)
310+
{
311+
const char* xml_text = R"(
312+
<root BTCPP_format="4" >
313+
<BehaviorTree ID="MainTree">
314+
<Sequence>
315+
<Script code=" pose:='1;2;3' "/>
316+
<ModifyPose pose="{pose}"/>
317+
<Script code=" pose:='1;2;3' "/>
318+
</Sequence>
319+
</BehaviorTree>
320+
</root>
321+
)";
322+
323+
BT::BehaviorTreeFactory factory;
324+
factory.registerNodeType<ModifyPose>("ModifyPose");
325+
factory.registerBehaviorTreeFromText(xml_text);
326+
Tree tree = factory.createTree("MainTree");
327+
tree.tickOnce();
328+
}

0 commit comments

Comments
 (0)