2222
2323#include " ROOT/StringUtils.hxx"
2424
25- #include < array>
2625#include < functional>
2726#include < iomanip>
2827#include < iostream>
2928#include < limits>
3029#include < memory>
3130#include < set>
31+ #include < stack>
3232#include < sstream>
3333#include < unordered_map>
3434
@@ -49,6 +49,43 @@ std::string doubleToString(double val)
4949 return ss.str ();
5050}
5151
52+ bool areMatching (char opening, char closing)
53+ {
54+ return (opening == ' (' && closing == ' )' ) || (opening == ' {' && closing == ' }' ) ||
55+ (opening == ' [' && closing == ' ]' ) || (opening == ' \" ' && closing == ' \" ' );
56+ }
57+
58+ bool isBalanced (const TString &s)
59+ {
60+ std::stack<char > i;
61+ auto sLength = s.Length ();
62+ for (Ssiz_t c = 0 ; c < sLength ; ++c) {
63+ if (s[c] == ' [' || s[c] == ' {' || s[c] == ' (' ) {
64+ i.push (s[c]);
65+ } else if (s[c] == ' ]' || s[c] == ' }' || s[c] == ' )' ) {
66+ if (i.empty () || !areMatching (i.top (), s[c])) {
67+ Error (" TFormula" , " Found unbalanced char %c (expected closing of %c) at index %d of %s" , s[c], i.top (), c,
68+ s.Data ());
69+ return false ;
70+ } else
71+ i.pop ();
72+ } else if (s[c] == ' \" ' ) {
73+ if (i.empty ())
74+ i.push (s[c]);
75+ else if (areMatching (i.top (), s[c]))
76+ i.pop ();
77+ else {
78+ i.push (s[c]);
79+ }
80+ }
81+ }
82+ if (!i.empty ()) {
83+ Error (" TFormula" , " String %s with %zu unbalanced chars." , s.Data (), i.size ());
84+ return false ;
85+ }
86+ return true ;
87+ }
88+
5289// In the interpreter, we must match the SIMD width used by compiled ROOT.
5390// ROOT::Double_v aliases the best available native SIMD type, which may differ
5491// between compiled and interpreted contexts (e.g. with -march=native).
@@ -1860,6 +1897,12 @@ Bool_t TFormula::PrepareFormula(TString &formula)
18601897{
18611898 fFuncs .clear ();
18621899 fReadyToExecute = false ;
1900+
1901+ // Check for balanced parentheses
1902+ if (!isBalanced (formula)) {
1903+ return false ;
1904+ }
1905+
18631906 ExtractFunctors (formula);
18641907
18651908 // update the expression with the new formula
0 commit comments