Skip to content

Commit

Permalink
add syntax for entries in the root blackboard
Browse files Browse the repository at this point in the history
  • Loading branch information
facontidavide committed Apr 5, 2024
1 parent 7771171 commit 1ef1c4d
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 55 deletions.
2 changes: 2 additions & 0 deletions include/behaviortree_cpp/basic_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ using StringView = std::string_view;

bool StartWith(StringView str, StringView prefix);

bool StartWith(StringView str, char prefix);

// vector of key/value pairs
using KeyValueVector = std::vector<std::pair<std::string, std::string>>;

Expand Down
50 changes: 41 additions & 9 deletions include/behaviortree_cpp/scripting/any_types.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2022 Davide Faconti - All Rights Reserved
/* Copyright (C) 2022-24 Davide Faconti - All Rights Reserved
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
Expand All @@ -12,14 +12,6 @@

#pragma once

#include <cmath>
#include <cstdio>
#include <map>
#include <string>
#include <vector>
#include <utility>
#include <charconv>

#include "lexy/action/parse.hpp"
#include "lexy/callback.hpp"
#include "lexy/dsl.hpp"
Expand All @@ -31,6 +23,46 @@ namespace BT::Grammar
{
namespace dsl = lexy::dsl;

struct _xid_start_character : lexyd::char_class_base<_xid_start_character>
{
static LEXY_CONSTEVAL auto char_class_name()
{
return "code-point.BT-start-character";
}

static LEXY_CONSTEVAL auto char_class_ascii()
{
lexy::_detail::ascii_set result;
result.insert('a', 'z');
result.insert('A', 'Z');
result.insert('_');
result.insert('@');
return result;
}

static LEXY_UNICODE_CONSTEXPR bool char_class_match_cp(char32_t cp)
{
// underscore handled as part of ASCII.
return lexy::_detail::code_point_has_properties<LEXY_UNICODE_PROPERTY(xid_start)>(cp);
}

template <typename Encoding>
static constexpr auto char_class_match_swar(lexy::_detail::swar_int c)
{
return lexyd::ascii::_alphau::template char_class_match_swar<Encoding>(c);
}
};
inline constexpr auto xid_start_character = _xid_start_character{};

// A Unicode-aware identifier.
struct Name
{
static constexpr auto rule =
dsl::identifier(xid_start_character, dsl::unicode::xid_continue);

static constexpr auto value = lexy::as_string<std::string>;
};

//----------
struct Integer : lexy::token_production
{
Expand Down
16 changes: 6 additions & 10 deletions include/behaviortree_cpp/scripting/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@ struct ExprAssignment : ExprBase
{
env.vars->createEntry(key, PortInfo());
entry = env.vars->getEntry(key);
if(!entry)
{
throw LogicError("Bug: report");
}
}
else
{
Expand Down Expand Up @@ -550,7 +554,8 @@ struct ExprAssignment : ExprBase
// special case: string to other type.
// Check if we can use the StringConverter
auto const str = value.cast<std::string>();
const auto& entry_info = env.vars->entryInfo(key);
const auto* entry_info = env.vars->entryInfo(key);

if(auto converter = entry_info->converter())
{
*dst_ptr = converter(str);
Expand Down Expand Up @@ -648,15 +653,6 @@ namespace dsl = lexy::dsl;

constexpr auto escaped_newline = dsl::backslash >> dsl::newline;

// A Unicode-aware identifier.
struct Name
{
static constexpr auto rule =
dsl::identifier(dsl::unicode::xid_start_underscore, dsl::unicode::xid_continue);

static constexpr auto value = lexy::as_string<std::string>;
};

// An expression that is nested inside another expression.
struct nested_expr : lexy::transparent_production
{
Expand Down
5 changes: 5 additions & 0 deletions src/basic_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -467,4 +467,9 @@ bool StartWith(StringView str, StringView prefix)
strncmp(str.data(), prefix.data(), prefix.size()) == 0;
}

bool StartWith(StringView str, char prefix)
{
return str.size() >= 1 && str[0] == prefix;
}

} // namespace BT
66 changes: 30 additions & 36 deletions src/blackboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,71 +45,51 @@ Any* Blackboard::getAny(const std::string& key)
const std::shared_ptr<Blackboard::Entry>
Blackboard::getEntry(const std::string& key) const
{
std::unique_lock<std::mutex> lock(mutex_);
auto it = storage_.find(key);
if(it != storage_.end())
// special syntax: "@" will always refer to the root BB
if(StartWith(key, '@'))
{
return it->second;
}
// not found. Try autoremapping
if(auto parent = parent_bb_.lock())
{
auto remap_it = internal_to_external_.find(key);
if(remap_it != internal_to_external_.cend())
if(auto parent = parent_bb_.lock())
{
auto const& new_key = remap_it->second;
return parent->getEntry(new_key);
return parent->getEntry(key);
}
if(autoremapping_ && !IsPrivateKey(key))
else
{
return parent->getEntry(key);
return getEntry(key.substr(1, key.size() - 1));
}
}
return {};
}

std::shared_ptr<Blackboard::Entry> Blackboard::getEntry(const std::string& key)
{
std::unique_lock<std::mutex> lock(mutex_);
auto it = storage_.find(key);
if(it != storage_.end())
{
return it->second;
}

// not found. Try autoremapping
if(auto parent = parent_bb_.lock())
{
auto remap_it = internal_to_external_.find(key);
if(remap_it != internal_to_external_.cend())
{
auto const& new_key = remap_it->second;
auto entry = parent->getEntry(new_key);
if(entry)
{
storage_.insert({ key, entry });
}
return entry;
return parent->getEntry(new_key);
}
if(autoremapping_ && !IsPrivateKey(key))
{
auto entry = parent->getEntry(key);
if(entry)
{
storage_.insert({ key, entry });
}
return entry;
return parent->getEntry(key);
}
}
return {};
}

const TypeInfo* Blackboard::entryInfo(const std::string& key)
std::shared_ptr<Blackboard::Entry> Blackboard::getEntry(const std::string& key)
{
std::unique_lock<std::mutex> lock(mutex_);
return static_cast<const Blackboard&>(*this).getEntry(key);
}

auto it = storage_.find(key);
return (it == storage_.end()) ? nullptr : &(it->second->info);
const TypeInfo* Blackboard::entryInfo(const std::string& key)
{
auto entry = getEntry(key);
return (!entry) ? nullptr : &(entry->info);
}

void Blackboard::addSubtreeRemapping(StringView internal, StringView external)
Expand Down Expand Up @@ -167,7 +147,21 @@ std::recursive_mutex& Blackboard::entryMutex() const

void Blackboard::createEntry(const std::string& key, const TypeInfo& info)
{
createEntryImpl(key, info);
if(StartWith(key, '@'))
{
if(auto parent = parent_bb_.lock())
{
parent->createEntry(key, info);
}
else
{
createEntryImpl(key.substr(1, key.size() - 1), info);
}
}
else
{
createEntryImpl(key, info);
}
}

void Blackboard::cloneInto(Blackboard& dst) const
Expand Down
44 changes: 44 additions & 0 deletions tests/gtest_blackboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,47 @@ TEST(BlackboardTest, BlackboardBackup)
status = tree.tickWhileRunning();
ASSERT_EQ(status, BT::NodeStatus::SUCCESS);
}

TEST(BlackboardTest, RootBlackboard)
{
BT::BehaviorTreeFactory factory;

const std::string xml_text = R"(
<root BTCPP_format="4" >
<BehaviorTree ID="SubA">
<Sequence>
<SubTree ID="SubB" />
<Script code=" @var3:=3 " />
</Sequence>
</BehaviorTree>
<BehaviorTree ID="SubB">
<Sequence>
<SaySomething message="{@msg}" />
<Script code=" @var4:=4 " />
</Sequence>
</BehaviorTree>
<BehaviorTree ID="MainTree">
<Sequence>
<Script code=" msg:='hello' " />
<SubTree ID="SubA" />
<Script code=" var1:=1 " />
<Script code=" @var2:=2 " />
</Sequence>
</BehaviorTree>
</root> )";

factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
factory.registerBehaviorTreeFromText(xml_text);
auto tree = factory.createTree("MainTree");

auto status = tree.tickWhileRunning();
ASSERT_EQ(status, BT::NodeStatus::SUCCESS);

ASSERT_EQ(1, tree.rootBlackboard()->get<int>("var1"));
ASSERT_EQ(2, tree.rootBlackboard()->get<int>("var2"));
ASSERT_EQ(3, tree.rootBlackboard()->get<int>("var3"));
ASSERT_EQ(4, tree.rootBlackboard()->get<int>("var4"));
}

0 comments on commit 1ef1c4d

Please sign in to comment.