diff --git a/libraries/animation/src/AnimExpression.cpp b/libraries/animation/src/AnimExpression.cpp index 5fc1bc9b4f..79004a72a6 100644 --- a/libraries/animation/src/AnimExpression.cpp +++ b/libraries/animation/src/AnimExpression.cpp @@ -208,9 +208,11 @@ AnimExpression::Token AnimExpression::consumeNot(const QString& str, QString::co Expr → Term Expr' Expr' → '||' Term Expr' | ε -Term → Factor Term' -Term' → '&&' Term' +Term → Unary Term' +Term' → '&&' Unary Term' | ε +Unary → '!' Unary + | Factor Factor → INT | BOOL | FLOAT @@ -249,9 +251,9 @@ bool AnimExpression::parseExprPrime(const QString& str, QString::const_iterator& } } -// Term → Factor Term' +// Term → Unary Term' bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter) { - if (!parseFactor(str, iter)) { + if (!parseUnary(str, iter)) { return false; } if (!parseTermPrime(str, iter)) { @@ -260,11 +262,11 @@ bool AnimExpression::parseTerm(const QString& str, QString::const_iterator& iter return true; } -// Term' → '&&' Term' | ε +// Term' → '&&' Unary Term' | ε bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); if (token.type == Token::And) { - if (!parseTerm(str, iter)) { + if (!parseUnary(str, iter)) { unconsumeToken(token); return false; } @@ -280,6 +282,24 @@ bool AnimExpression::parseTermPrime(const QString& str, QString::const_iterator& } } +// Unary → '!' Unary | Factor +bool AnimExpression::parseUnary(const QString& str, QString::const_iterator& iter) { + + auto token = consumeToken(str, iter); + if (token.type == Token::Not) { + if (!parseUnary(str, iter)) { + unconsumeToken(token); + return false; + } + _opCodes.push_back(OpCode {OpCode::Not}); + return true; + } + unconsumeToken(token); + + return parseFactor(str, iter); +} + + // Factor → INT | BOOL | FLOAT | IDENTIFIER | '(' Expr ')' bool AnimExpression::parseFactor(const QString& str, QString::const_iterator& iter) { auto token = consumeToken(str, iter); diff --git a/libraries/animation/src/AnimExpression.h b/libraries/animation/src/AnimExpression.h index 8a1961b326..468217f5b3 100644 --- a/libraries/animation/src/AnimExpression.h +++ b/libraries/animation/src/AnimExpression.h @@ -119,6 +119,7 @@ protected: bool parseExprPrime(const QString& str, QString::const_iterator& iter); bool parseTerm(const QString& str, QString::const_iterator& iter); bool parseTermPrime(const QString& str, QString::const_iterator& iter); + bool parseUnary(const QString& str, QString::const_iterator& iter); bool parseFactor(const QString& str, QString::const_iterator& iter); OpCode evaluate(const AnimVariantMap& map) const; diff --git a/tests/animation/src/AnimTests.cpp b/tests/animation/src/AnimTests.cpp index 63eb39dc48..6812bb63b6 100644 --- a/tests/animation/src/AnimTests.cpp +++ b/tests/animation/src/AnimTests.cpp @@ -522,43 +522,19 @@ void AnimTests::testExpressionParser() { QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::And); } - /* - e = AnimExpression("2 + 3"); - QVERIFY(e._opCodes.size() == 3); - if (e._opCodes.size() == 3) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[0].intVal == 2); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[1].intVal == 3); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); + e = AnimExpression("!(true || false) && true"); + QVERIFY(e._opCodes.size() == 6); + if (e._opCodes.size() == 6) { + QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Bool); + QVERIFY(e._opCodes[0].intVal == (int)true); + QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Bool); + QVERIFY(e._opCodes[1].intVal == (int)false); + QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Or); + QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Not); + QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Bool); + QVERIFY(e._opCodes[4].intVal == (int)true); + QVERIFY(e._opCodes[5].type == AnimExpression::OpCode::And); } - - e = AnimExpression("2 + 3 * 10"); - QVERIFY(e._opCodes.size() == 5); - if (e._opCodes.size() == 5) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[0].intVal == 2); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[1].intVal == 3); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[2].intVal == 10); - QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Multiply); - QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Add); - } - - e = AnimExpression("(2 + 3) * 10"); - QVERIFY(e._opCodes.size() == 5); - if (e._opCodes.size() == 5) { - QVERIFY(e._opCodes[0].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[0].intVal == 2); - QVERIFY(e._opCodes[1].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[1].intVal == 3); - QVERIFY(e._opCodes[2].type == AnimExpression::OpCode::Add); - QVERIFY(e._opCodes[3].type == AnimExpression::OpCode::Int); - QVERIFY(e._opCodes[3].intVal == 10); - QVERIFY(e._opCodes[4].type == AnimExpression::OpCode::Multiply); - } - */ } #define TEST_BOOL_EXPR(EXPR) \ @@ -630,23 +606,22 @@ void AnimTests::testExpressionEvaluator() { TEST_BOOL_EXPR(f || false); TEST_BOOL_EXPR(f || true); -/* - result = AnimExpression("(2 + 3) * (5 + 3)").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Int); - QVERIFY(result.intVal == (2 + 3) * (5 + 3)); + TEST_BOOL_EXPR(!true); + TEST_BOOL_EXPR(!false); + TEST_BOOL_EXPR(!true || true); - result = AnimExpression("(ten + twenty) * 5").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Int); - QVERIFY(result.intVal == (10 + 20) * 5); + TEST_BOOL_EXPR(!true && !false || !true); + TEST_BOOL_EXPR(!true && !false || true); + TEST_BOOL_EXPR(!true && false || !true); + TEST_BOOL_EXPR(!true && false || true); + TEST_BOOL_EXPR(true && !false || !true); + TEST_BOOL_EXPR(true && !false || true); + TEST_BOOL_EXPR(true && false || !true); + TEST_BOOL_EXPR(true && false || true); - result = AnimExpression("(ten + twenty) * 5.0").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Float); - QVERIFY(result.floatVal == (10 + 20) * 5.0f); - - result = AnimExpression("five * forty").evaluate(vars); - QVERIFY(result.type == AnimExpression::OpCode::Float); - QVERIFY(result.floatVal == 5.0f * 40.0f); -*/ + TEST_BOOL_EXPR(!(true && f) || !t); + TEST_BOOL_EXPR(!!!(t) && (!!f || true)); + TEST_BOOL_EXPR(!(true && f) && true); }