Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conandata.yml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version: "1.2.0"
version: "1.2.1"
34 changes: 18 additions & 16 deletions src/ast/comp_chain_expr.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "cura-formulae-engine/ast/comp_chain_expr.h"
#include "cura-formulae-engine/eval.h"

#include <algorithm>
#include <string>
#include <unordered_set>
#include <variant>
Expand Down Expand Up @@ -90,30 +91,31 @@ namespace CuraFormulaeEngine::ast
break;
case Member:
case NotMember:
if (!right_value_result.has_value())
{
bool found = false;
if (std::holds_alternative<std::string>(right_value.value))
{
return zeus::unexpected(right_value_result.error());
if (!std::holds_alternative<std::string>(left_value.value))
{
return zeus::unexpected(eval::Error::TypeMismatch);
}
const auto& haystack = std::get<std::string>(right_value.value);
const auto& needle = std::get<std::string>(left_value.value);
found = haystack.find(needle) != std::string::npos;
}

const auto& rhs_value = right_value_result.value();
if (!std::holds_alternative<std::vector<eval::Value>>(rhs_value.value))
else if (std::holds_alternative<std::vector<eval::Value>>(right_value.value))
{
return zeus::unexpected(eval::Error::TypeMismatch);
const auto& list = std::get<std::vector<eval::Value>>(right_value.value);
found = std::ranges::any_of(list, [&](const eval::Value& item) { return left_value == item; });
}

comparison_result = operators[i] == NotMember;

const auto& list = std::get<std::vector<eval::Value>>(rhs_value.value);
for (const auto& item : list)
else
{
if (left_value == item)
{
comparison_result = operators[i] == Member;
break;
}
return zeus::unexpected(eval::Error::TypeMismatch);
}
comparison_result = (operators[i] == Member) ? found : !found;
break;
}
}

if (!comparison_result.has_value())
{
Expand Down
120 changes: 120 additions & 0 deletions tests/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,126 @@ TEST_CASE("not member list", "[parser, member]")
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("member string found", "[parser, member]")
{
auto input = R"("foo" in "foobar")"sv;

std::vector<ExprPtr> expressions;
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foo")));
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foobar")));

const auto expected_ast = make_expr_ptr<ComparisonChainExpr>(std::move(expressions), std::vector{ComparisonOperators::Member});
const auto expected_eval = CuraFormulaeEngine::eval::Value(true);

const auto message = CuraFormulaeEngine::parser::parse(input);
REQUIRE(message.has_value());
const auto &ast = message.value();
REQUIRE(ast.deepEq(expected_ast));
const auto eval = ast.evaluate(&CuraFormulaeEngine::env::std_env);
REQUIRE(eval.has_value());
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("member string not found", "[parser, member]")
{
auto input = R"("baz" in "foobar")"sv;

std::vector<ExprPtr> expressions;
expressions.push_back(make_expr_ptr<StringExpr>(std::string("baz")));
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foobar")));

const auto expected_ast = make_expr_ptr<ComparisonChainExpr>(std::move(expressions), std::vector{ComparisonOperators::Member});
const auto expected_eval = CuraFormulaeEngine::eval::Value(false);

const auto message = CuraFormulaeEngine::parser::parse(input);
REQUIRE(message.has_value());
const auto &ast = message.value();
REQUIRE(ast.deepEq(expected_ast));
const auto eval = ast.evaluate(&CuraFormulaeEngine::env::std_env);
REQUIRE(eval.has_value());
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("not member string found", "[parser, member]")
{
auto input = R"("foo" not in "foobar")"sv;

std::vector<ExprPtr> expressions;
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foo")));
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foobar")));

const auto expected_ast = make_expr_ptr<ComparisonChainExpr>(std::move(expressions), std::vector{ComparisonOperators::NotMember});
const auto expected_eval = CuraFormulaeEngine::eval::Value(false);

const auto message = CuraFormulaeEngine::parser::parse(input);
REQUIRE(message.has_value());
const auto &ast = message.value();
REQUIRE(ast.deepEq(expected_ast));
const auto eval = ast.evaluate(&CuraFormulaeEngine::env::std_env);
REQUIRE(eval.has_value());
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("not member string not found", "[parser, member]")
{
auto input = R"("baz" not in "foobar")"sv;

std::vector<ExprPtr> expressions;
expressions.push_back(make_expr_ptr<StringExpr>(std::string("baz")));
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foobar")));

const auto expected_ast = make_expr_ptr<ComparisonChainExpr>(std::move(expressions), std::vector{ComparisonOperators::NotMember});
const auto expected_eval = CuraFormulaeEngine::eval::Value(true);

const auto message = CuraFormulaeEngine::parser::parse(input);
REQUIRE(message.has_value());
const auto &ast = message.value();
REQUIRE(ast.deepEq(expected_ast));
const auto eval = ast.evaluate(&CuraFormulaeEngine::env::std_env);
REQUIRE(eval.has_value());
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("member string in list", "[parser, member]")
{
auto input = R"("foo" in ["foo", "bar"])"sv;

std::vector<ExprPtr> expressions;
expressions.push_back(make_expr_ptr<StringExpr>(std::string("foo")));
expressions.push_back(make_list_expr(make_expr_ptr<StringExpr>(std::string("foo")), make_expr_ptr<StringExpr>(std::string("bar"))));

const auto expected_ast = make_expr_ptr<ComparisonChainExpr>(std::move(expressions), std::vector{ComparisonOperators::Member});
const auto expected_eval = CuraFormulaeEngine::eval::Value(true);

const auto message = CuraFormulaeEngine::parser::parse(input);
REQUIRE(message.has_value());
const auto &ast = message.value();
REQUIRE(ast.deepEq(expected_ast));
const auto eval = ast.evaluate(&CuraFormulaeEngine::env::std_env);
REQUIRE(eval.has_value());
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("not member string in list", "[parser, member]")
{
auto input = R"("baz" not in ["foo", "bar"])"sv;

std::vector<ExprPtr> expressions;
expressions.push_back(make_expr_ptr<StringExpr>(std::string("baz")));
expressions.push_back(make_list_expr(make_expr_ptr<StringExpr>(std::string("foo")), make_expr_ptr<StringExpr>(std::string("bar"))));

const auto expected_ast = make_expr_ptr<ComparisonChainExpr>(std::move(expressions), std::vector{ComparisonOperators::NotMember});
const auto expected_eval = CuraFormulaeEngine::eval::Value(true);

const auto message = CuraFormulaeEngine::parser::parse(input);
REQUIRE(message.has_value());
const auto &ast = message.value();
REQUIRE(ast.deepEq(expected_ast));
const auto eval = ast.evaluate(&CuraFormulaeEngine::env::std_env);
REQUIRE(eval.has_value());
REQUIRE(eval.value().deepEq(expected_eval));
}

TEST_CASE("expression or operator", "[parser, expression]")
{
auto input = "True or False"sv;
Expand Down