Skip to content

Pick upstream script fixes for numeric strings (#1191, #1239, #1254, #1162) - #45

Merged
L4co77 merged 5 commits into
main-picknikfrom
sync/upstream-script-numeric-strings
Nov 3, 2026
Merged

L4co77 merged 5 commits into
main-picknikfrom
sync/upstream-script-numeric-strings

Conversation

@L4co77

@L4co77 L4co77 commented Nov 2, 2026

Copy link
Copy Markdown

[written by AI]

Refs PickNikRobotics/moveit_pro#24179. Replaces #44, as agreed in #44 (comment).

Motivation

#44 changed Script operators in this fork only. Upstream BehaviorTree/BehaviorTree.CPP has since fixed the core of the same problem, numbers that reach scripts as strings through SubTree ports, so taking those commits narrows the fork's drift instead of widening it.

Brief description

Four upstream commits, cherry-picked with -x, plus one fork commit:

Fork-specific conflict resolutions, also in the commit messages:

Behavior changes vs. 4.9.0-5noble

compatibility-bot (moveit_pro reviewer role) built both and ran the same scripts against each. 0 of the 109 Script and precondition expressions shipped in moveit_pro and moveit_pro_example_ws behave differently.

  • Needs a Breaking Change: note: &, |, ^ no longer convert a numeric string mixed with a number. A SubTree literal mask="6" in mask & 3 gave 2 and now fails with Operation not permitted. This matches upstream and was accepted for parity; the fix for a customer script is (mask + 0) & 3.
  • Bug fixes:
    • + - * / no longer use only the leading digits of a string: '45degree_runs/' + 7 gave 52, '0x10' + 1 gave 1. These now fail.
    • .. between a number and a numeric string concatenates (count .. '5') instead of returning no value.
    • ! works on string-backed booleans.
    • ~ rejects fractional, NaN and out-of-range values instead of truncating them.
    • A double of 2^63 or more read into an integer port fails instead of wrapping.

Still not fixed upstream either, to be sent there as PRs and picked up with a later sync: 1 .. 2 returning an empty value, '1' - '2' on two numeric strings, prefix parsing in comparisons, .. printing 2.000000.

How it was tested

Built in a container from the moveit-pro-dev image (clang with libstdc++ 13), BTCPP_GROOT_INTERFACE=OFF.

  • Full suite: 587/587 (580 on main-picknik before, plus the upstream tests these commits bring) in RelWithDebInfo, ASan and UBSan builds.
  • pre-commit (clang-format 17, clang-tidy, codespell) clean on the changed files.
  • The #else branch of the new guard isn't exercised: every toolchain here has floating-point from_chars.

The upstream commits are in upstream order except BehaviorTree#1162, which came last. BehaviorTree#1239's ~9223372036854775808.0 test fails at that commit and passes once BehaviorTree#1162 is applied.

fallenmi and others added 5 commits November 3, 2026 00:00
Co-authored-by: Igor Stadnyk <fallenmi@users.noreply.github.com>
(cherry picked from commit b4c070b)
…ehaviorTree#1239)

The ~ operator in ExprUnaryArithmetic::evaluate guarded the cast of its
double operand to int64_t with a hand-written range comparison. NaN passes
it (every comparison is false) and so does exactly 2^63, because
double(INT64_MAX) rounds up to 2^63; the following static_cast is then
undefined behavior (UBSan float-cast-overflow). Fractional operands were
also truncated silently, while the binary bitwise operators reject them.

Use the checked Any::cast<int64_t> the binary bitwise operators already
use, so these operands raise the existing RuntimeError instead.

(cherry picked from commit ea8dafa)
…ript arithmetic (BehaviorTree#1246) (BehaviorTree#1254)

Since BehaviorTree#1121 (shipped in 4.9.1), a numeric literal passed to a SubTree port
was stored as int/int64_t/double. That locked the entry type, so the same
value could no longer be read by a std::string port (tree creation failed),
custom convertFromString<T> was bypassed, and the spelling was lost
("007" became 7).

Literals are stored as strings again. The goal of BehaviorTree#1121, arithmetic on
numeric literals in Script, is kept by the script evaluator instead: in
+ - * /, a string operand mixed with a number is converted when the whole
string is a number (integer first, then double).

Behavior change compared to 4.9.1 - 4.10.0, back to pre-4.9.1 behavior:
two literal operands are strings ("1" + "2" is "12", "10" < "2" compares
text), and compound assignment, unary minus, bitwise and logic operators
on such a literal require an explicit number again.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 0388ee8)

Fork adaptation: NumericStringToNumber uses std::from_chars with a full-consumption check
instead of parseDouble, which upstream added in BehaviorTree#1167 (not in this fork). xml_parsing.cpp
already stores SubTree literals as strings here, so that part of the change is a no-op.
tests/gtest_subtree.cpp keeps this fork's SubTree tests (it accepts duplicate SubTree names,
#41) and adds LiteralNumericPortsPreserveType and LiteralPortsAreReadByAnyPortType.
…oNumber

NumericStringToNumber came from upstream BehaviorTree#1254 with parseDouble, which this fork lacks
(upstream BehaviorTree#1167), and was adapted to std::from_chars. Guard that call with
__cpp_lib_to_chars like the fork's other double conversions, with a classic-locale stream
as the fallback, so toolchains without floating-point from_chars still build.
@L4co77 L4co77 self-assigned this Nov 2, 2026
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 6e761516-8ecd-4d1f-bed2-cb651b8b921e
Commits

Reviewing files that changed from the base of the PR and between 1cc7638 and 584e03d.

Files selected for processing: 6
  • include/behaviortree_cpp/scripting/operators.hpp
  • include/behaviortree_cpp/utils/convert_impl.hpp
  • include/behaviortree_cpp/utils/safe_any.hpp
  • tests/gtest_basic_types.cpp
  • tests/gtest_subtree.cpp
  • tests/script_parser_test.cpp

Included review availability: This review used your included allowance. 9 included reviews remain after this review. Your included PR review attempts over the past 7 days set your current allowance at 10 reviews per hour.

Summary

Summary by CodeRabbit

  • New Features
    • Arithmetic operations can now use fully numeric strings alongside numbers, while string concatenation remains unchanged.
    • Logical NOT now recognizes common string representations of true and false.
  • Bug Fixes
    • Invalid or partially numeric strings are no longer treated as numbers in arithmetic.
    • Out-of-range floating-point values are rejected when converted to integers, including at integer boundaries.

The changes tighten floating-point-to-integer conversion bounds and update script operators to handle numeric and boolean strings. New tests cover conversions, arithmetic, logical NOT, unary complement, and literal subtree ports.

Changes: Numeric conversion and scripting

Layer / File(s) Summary
Floating-point conversion bounds
include/behaviortree_cpp/utils/convert_impl.hpp, include/behaviortree_cpp/utils/safe_any.hpp, tests/gtest_basic_types.cpp
Floating-point conversions reject values at rounded integer upper bounds. Tests cover Any::cast and Blackboard::set at and within the tested boundaries.
Script string conversion and operators
include/behaviortree_cpp/scripting/operators.hpp, tests/script_parser_test.cpp, tests/gtest_subtree.cpp
Arithmetic converts a string operand only when it is fully numeric and paired with a numeric operand. Logical NOT recognizes the specified boolean spellings, and unary complement uses checked int64_t conversion. Tests cover these operators and literal subtree port values.

Possibly related PRs

Suggested reviewers: dvadovsz

Merge Risk: Minimal · up to 584e0

No concrete issue currently prevents merging; the floating-point parsing fallback remains untested on toolchains that use it.

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore (reviewers only)

Failed Failed checks: 1 error

Check name Status Explanation Resolution
Human Review Check Error The PR adds the public inline function BT::Ast::NumericStringToNumber(Any&) to include/behaviortree_cpp/scripting/operators.hpp. It also changes public-header conversion behavior in `convert_impl.… This PR requires review by a requested human reviewer. After review, a non-author requested reviewer should override this pre-merge check.
Passed Passed checks: 3 passed
Check name Status Explanation
Description check Passed The description follows the repository's expected structure in substance. It states the motivation, lists each cherry-picked upstream commit and the fork-specific conflict resolutions, and describes b…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description follows the repository's expected structure in substance. It states the motivation, lists each cherry-picked upstream commit and the fork-specific conflict resolutions, and describes behavior changes against 4.9.0-5noble, including a breaking change note for bitwise operators. It also reports the testing done (587/587 tests in RelWithDebInfo, ASan and UBSan, clean pre-commit) and notes the untested #else fallback branch. The template itself is a checklist of contributor guidance rather than sections with required content, so the description covers its intent: it explains the API/behavior change, the bug fixes, and the testing. The description does not explicitly confirm the template items about adding comments or running ./run_clang_tidy.sh, and it does not mention the CONTRIBUTORS_GUIDE.md review. Those are minor gaps.

Full details: Human Review Check

Explanation

The PR adds the public inline function BT::Ast::NumericStringToNumber(Any&amp;) to include/behaviortree_cpp/scripting/operators.hpp. It also changes public-header conversion behavior in convert_impl.hpp and safe_any.hpp. This matches the explicit public API failure condition.

Resolution

This PR requires review by a requested human reviewer. After review, a non-author requested reviewer should override this pre-merge check.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.

@L4co77
L4co77 marked this pull request as ready for review November 2, 2026 23:37
@L4co77
L4co77 requested a review from dvadovsz November 2, 2026 23:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pre-merge checks failed. Please resolve the failing checks before merging.

@L4co77
L4co77 added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main-picknik with commit 4633186 Nov 3, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants