From 4d2b2b8c8d87d18002447e58e3570b6be8f39648 Mon Sep 17 00:00:00 2001 From: Dmitrii Petukhov Date: Wed, 12 Feb 2025 18:33:20 +0200 Subject: [PATCH] Implement support for exists() in BISON expressions Signed-off-by: Dmitrii Petukhov --- .../bmq/bmqeval/bmqeval_simpleevaluator.cpp | 29 +++++++++++++++ .../bmq/bmqeval/bmqeval_simpleevaluator.h | 36 +++++++++++++++++++ .../bmq/bmqeval/bmqeval_simpleevaluator.t.cpp | 9 +++++ .../bmqeval/bmqeval_simpleevaluatorparser.y | 27 +++++++++++--- .../bmqeval/bmqeval_simpleevaluatorscanner.l | 5 +++ 5 files changed, 102 insertions(+), 4 deletions(-) diff --git a/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.cpp b/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.cpp index b88ef3d473..7ceefb5f17 100644 --- a/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.cpp +++ b/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.cpp @@ -364,5 +364,34 @@ bdld::Datum SimpleEvaluator::Not::evaluate(EvaluationContext& context) const return bdld::Datum::createBoolean(!value.theBoolean()); } +// -------------------------- +// class SimpleEvaluator::Exists +// -------------------------- + +SimpleEvaluator::Exists::Exists(const bsl::string& name) +: d_name(name) +{ +} + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) +SimpleEvaluator::Exists::Exists(bsl::string&& name) noexcept +: d_name(bsl::move(name)) +{ +} +#endif + +bdld::Datum SimpleEvaluator::Exists::evaluate(EvaluationContext& context) const +{ + bdld::Datum value = context.d_propertiesReader->get(d_name, + context.d_allocator); + + if (value.isError()) { + return bdld::Datum::createBoolean(false); + } + + return bdld::Datum::createBoolean(true); +} + } // close package namespace } // close enterprise namespace diff --git a/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.h b/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.h index 79e4122ba1..7a8e581ed7 100644 --- a/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.h +++ b/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.h @@ -478,6 +478,41 @@ class SimpleEvaluator { evaluate(EvaluationContext& context) const BSLS_KEYWORD_OVERRIDE; }; + // --- + // Exists + // --- + + class Exists : public Expression { + private: + // DATA + + // The name of the property. + bsl::string d_name; + + public: + // CREATORS + + /// Create an object that evaluates property `name`, in the + /// evaluation context, as a boolean. + explicit Exists(const bsl::string& name); + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) && \ + defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) + /// Create an object that evaluates property `name`, in the + /// evaluation context, as a boolean. + explicit Exists(bsl::string&& name) noexcept; +#endif + + // ACCESSORS + + /// Evaluate `expression` passed to the constructor. If it is a + /// boolean, return the negated value as a boolean Datum. + /// Otherwise, set the error in the context to e_TYPE, stop the + /// evaluation, and return a null datum. + bdld::Datum + evaluate(EvaluationContext& context) const BSLS_KEYWORD_OVERRIDE; + }; + private: // SimpleEvaluator(const SimpleEvaluator& other) BSLS_KEYWORD_DELETED; // SimpleEvaluator& operator=(const SimpleEvaluator& other) @@ -549,6 +584,7 @@ class SimpleEvaluator { friend class SimpleEvaluatorScanner; // for access to Expression hierarchy friend class CompilationContext; // for access to ExpressionPtr }; + // ======================== // class CompilationContext // ======================== diff --git a/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.t.cpp b/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.t.cpp index de3fd963fc..7c48688b16 100644 --- a/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.t.cpp +++ b/src/groups/bmq/bmqeval/bmqeval_simpleevaluator.t.cpp @@ -55,6 +55,7 @@ class MockPropertiesReader : public PropertiesReader { d_map["i_42"] = bdld::Datum::createInteger(42); d_map["i64_42"] = bdld::Datum::createInteger64(42, allocator); d_map["s_foo"] = bdld::Datum::createStringRef("foo", allocator); + d_map["exists"] = bdld::Datum::createInteger(42); } // Destroy this object. @@ -520,6 +521,14 @@ static void test3_evaluation() {"i_0 != -9223372036854775807", true}, // -(2 ** 63) + 1 {"i_0 != 9223372036854775807", true}, // 2 ** 63 - 1 {"i_0 != -9223372036854775808", true}, // -(2 ** 63) + + // exists + {"exists(i_42)", true}, + {"exists(non_existing_property)", false}, + {"exists(i_42) && i_42 > 41", true}, + {"exists(non_existing_property) && non_existing_property > 41", false}, + {"exists == 42", true}, + {"exists(exists)", true}, }; const TestParameters* testParametersEnd = testParameters + sizeof(testParameters) / diff --git a/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorparser.y b/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorparser.y index cfcd81e15e..83896ca5e7 100644 --- a/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorparser.y +++ b/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorparser.y @@ -75,6 +75,7 @@ %token PLUS "+" MINUS "-"; %token TIMES "*" DIVIDES "/" MODULUS "%"; %token EQ "=" NE "<>" LT "<" LE "<=" GE ">=" GT ">"; +%token EXISTS "exists"; %left OR; %left AND; @@ -84,6 +85,7 @@ %left TIMES DIVIDES MODULUS; %right NOT "!"; +%type variable; %type expression; %type predicate; %start predicate @@ -95,18 +97,35 @@ predicate : expression END ctx.d_expression = $1; } -expression +variable : PROPERTY { + ++ctx.d_numProperties; + $$ = $1; + } + | EXISTS + { + ++ctx.d_numProperties; + $$ = $1; + } -#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) \ +expression + : variable { + #if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) \ && defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) $$ = ctx.makeUnaryExpression(bsl::move($1)); #else $$ = ctx.makeUnaryExpression($1); #endif - - ++ctx.d_numProperties; + } + | EXISTS LPAR variable RPAR + { +#if defined(BSLS_COMPILERFEATURES_SUPPORT_RVALUE_REFERENCES) \ +&& defined(BSLS_COMPILERFEATURES_SUPPORT_NOEXCEPT) + $$ = ctx.makeUnaryExpression(bsl::move($3)); +#else + $$ = ctx.makeUnaryExpression($3); +#endif } | INTEGER { $$ = ctx.makeLiteral($1); } diff --git a/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorscanner.l b/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorscanner.l index c0da8dea85..b9e5cd6a3d 100644 --- a/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorscanner.l +++ b/src/groups/bmq/bmqeval/bmqeval_simpleevaluatorscanner.l @@ -32,6 +32,11 @@ return SimpleEvaluatorParser::make_FALSE(); } +"exists" { + updatePosition(); + return SimpleEvaluatorParser::make_EXISTS(yytext); +} + [a-zA-Z][a-zA-Z0-9_.]* { updatePosition(); return SimpleEvaluatorParser::make_PROPERTY(yytext);