initial import

This commit is contained in:
2025-06-22 20:39:04 -05:00
commit f8a70886f0
3428 changed files with 302546 additions and 0 deletions

View File

@@ -0,0 +1,130 @@
From: Tomas Babej <tomas@tbabej.com>
Date: Sat, 30 Jan 2021 17:50:58 -0500
Subject: Backport parser issues fixes
This backports upstream PR #2405 and commit a5eee5f, which contain extra
fixes and tests for issues with numeric project names (amongst others)
which were being wrongly interpreted as expressions.
Addresses upstream issues TW-{2388,2386,2257,1908,1896}
---
diff --git a/src/CLI2.cpp b/src/CLI2.cpp
index ec2bd6c7..c49eb4d7 100644
--- a/src/CLI2.cpp
+++ b/src/CLI2.cpp
@@ -1277,7 +1277,9 @@ void CLI2::desugarFilterAttributes ()
A2 op ("", Lexer::Type::op);
op.tag ("FILTER");
- A2 rhs ("", values[0]._lextype);
+ // Attribute types that do not support evaluation should be interpreted
+ // as strings (currently this means that string attributes are not evaluated)
+ A2 rhs ("", evalSupported ? values[0]._lextype: Lexer::Type::string);
rhs.tag ("FILTER");
// Special case for '<name>:<value>'.
@@ -1371,7 +1373,7 @@ void CLI2::desugarFilterAttributes ()
// Do not modify this construct without full understanding.
// Getting this wrong breaks a whole lot of filtering tests.
- if (values.size () > 1 || evalSupported)
+ if (evalSupported)
{
for (auto& v : values)
reconstructed.push_back (v);
@@ -1946,6 +1948,41 @@ void CLI2::desugarFilterPlainArgs ()
}
////////////////////////////////////////////////////////////////////////////////
+// Detects if the bracket at iterator it is a start or end of an empty paren expression
+// Examples:
+// ( status = pending ) ( )
+// ^
+// it -----| => true
+//
+// ( status = pending ) ( project = Home )
+// ^
+// it -----| => false
+bool CLI2::isEmptyParenExpression (std::vector<A2>::iterator it, bool forward /* = true */) const
+{
+ int open = 0;
+ int closed = 0;
+
+ for (auto a = it; a != (forward ? _args.end (): _args.begin()); (forward ? ++a: --a))
+ {
+ if (a->attribute("raw") == "(")
+ open++;
+ else if (a->attribute("raw") == ")")
+ closed++;
+ else
+ // Encountering a non-paren token means there is something between parenthees
+ return false;
+
+ // Getting balanced parentheses means we have an empty paren expression
+ if (open == closed && open != 0)
+ return true;
+ }
+
+ // Should not end here.
+ return false;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
// Two consecutive FILTER, non-OP arguments that are not "(" or ")" need an
// "and" operator inserted between them.
//
@@ -1971,10 +2008,18 @@ void CLI2::insertJunctions ()
// Insert AND between terms.
else if (a != prev)
{
- if ((prev->_lextype != Lexer::Type::op && a->attribute ("raw") == "(") ||
- (prev->_lextype != Lexer::Type::op && a->_lextype != Lexer::Type::op) ||
- (prev->attribute ("raw") == ")" && a->_lextype != Lexer::Type::op) ||
- (prev->attribute ("raw") == ")" && a->attribute ("raw") == "("))
+ if ((prev->_lextype != Lexer::Type::op &&
+ a->attribute ("raw") == "(" &&
+ ! isEmptyParenExpression(a, true) ) ||
+ (prev->attribute ("raw") == ")" &&
+ a->_lextype != Lexer::Type::op &&
+ ! isEmptyParenExpression(prev, false)) ||
+ (prev->attribute ("raw") == ")" &&
+ a->attribute ("raw") == "(" &&
+ ! isEmptyParenExpression(a, true) &&
+ ! isEmptyParenExpression(prev, false)) ||
+ (prev->_lextype != Lexer::Type::op &&
+ a->_lextype != Lexer::Type::op))
{
A2 opOr ("and", Lexer::Type::op);
opOr.tag ("FILTER");
diff --git a/src/CLI2.h b/src/CLI2.h
index f6b0ce94..025be4c8 100644
--- a/src/CLI2.h
+++ b/src/CLI2.h
@@ -99,6 +99,7 @@ private:
void findUUIDs ();
void insertIDExpr ();
void lexFilterArgs ();
+ bool isEmptyParenExpression (std::vector<A2>::iterator it, bool forward = true) const;
void desugarFilterPlainArgs ();
void insertJunctions ();
void defaultCommand ();
diff --git a/src/columns/ColTypeString.cpp b/src/columns/ColTypeString.cpp
index 37c1433d..4ef97578 100644
--- a/src/columns/ColTypeString.cpp
+++ b/src/columns/ColTypeString.cpp
@@ -58,7 +58,12 @@ void ColumnTypeString::modify (Task& task, const std::string& value)
std::string domRef;
Lexer::Type type;
if (lexer.token (domRef, type) &&
- type == Lexer::Type::dom)
+ type == Lexer::Type::dom &&
+ // Ensure 'value' contains only the DOM reference and no other tokens
+ // The lexer.token returns false for end-of-string.
+ // This works as long as all the DOM references we should support consist
+ // only of a single token.
+ lexer.token (domRef, type) == false)
{
Eval e;
e.addSource (domSource);