2016-08-02 01:17:41 +00:00
|
|
|
//
|
|
|
|
|
// Copyright 2015 Ettus Research LLC
|
2018-02-19 23:30:32 +00:00
|
|
|
// Copyright 2018 Ettus Research, a National Instruments Company
|
2016-08-02 01:17:41 +00:00
|
|
|
//
|
2018-02-19 23:30:32 +00:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2016-08-02 01:17:41 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
|
|
#include "../lib/rfnoc/nocscript/function_table.hpp"
|
2019-01-14 18:35:25 +00:00
|
|
|
#include "nocscript_common.hpp"
|
2016-08-02 01:17:41 +00:00
|
|
|
#include <boost/bind.hpp>
|
|
|
|
|
#include <boost/format.hpp>
|
2019-01-14 18:35:25 +00:00
|
|
|
#include <boost/make_shared.hpp>
|
|
|
|
|
#include <boost/test/floating_point_comparison.hpp>
|
|
|
|
|
#include <boost/test/unit_test.hpp>
|
2016-08-02 01:17:41 +00:00
|
|
|
#include <algorithm>
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
// We need this global variable for one of the later tests
|
|
|
|
|
int and_counter = 0;
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_literals)
|
|
|
|
|
{
|
|
|
|
|
expression_literal literal_int("5", expression::TYPE_INT);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_int.infer_type(), expression::TYPE_INT);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_int.get_int(), 5);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_int.to_bool(), true);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_int.get_string(), uhd::type_error);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_int.get_bool(), uhd::type_error);
|
|
|
|
|
|
|
|
|
|
expression_literal literal_int0("0", expression::TYPE_INT);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_int0.infer_type(), expression::TYPE_INT);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_int0.to_bool(), false);
|
|
|
|
|
|
|
|
|
|
expression_literal literal_double("2.3", expression::TYPE_DOUBLE);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_double.infer_type(), expression::TYPE_DOUBLE);
|
|
|
|
|
BOOST_CHECK_CLOSE(literal_double.get_double(), 2.3, 0.01);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_double.to_bool(), true);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_double.get_string(), uhd::type_error);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_double.get_bool(), uhd::type_error);
|
|
|
|
|
|
|
|
|
|
expression_literal literal_bool(true);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool.get_bool(), true);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool.to_bool(), true);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool.eval().get_bool(), true);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_bool.get_string(), uhd::type_error);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_bool.get_int(), uhd::type_error);
|
|
|
|
|
|
|
|
|
|
expression_literal literal_bool_false(false);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool_false.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool_false.get_bool(), false);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_bool_false.to_bool(), false);
|
|
|
|
|
BOOST_REQUIRE_EQUAL(literal_bool_false.eval().get_bool(), false);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_bool_false.get_string(), uhd::type_error);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_bool_false.get_int(), uhd::type_error);
|
|
|
|
|
|
|
|
|
|
expression_literal literal_string("'foo bar'", expression::TYPE_STRING);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_string.infer_type(), expression::TYPE_STRING);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_string.get_string(), "foo bar");
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_string.get_bool(), uhd::type_error);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_string.get_int(), uhd::type_error);
|
|
|
|
|
|
|
|
|
|
expression_literal literal_int_vec("[1, 2, 3]", expression::TYPE_INT_VECTOR);
|
|
|
|
|
BOOST_CHECK_EQUAL(literal_int_vec.infer_type(), expression::TYPE_INT_VECTOR);
|
2018-04-26 20:13:32 +00:00
|
|
|
std::vector<int> test_data{1, 2, 3};
|
2016-08-02 01:17:41 +00:00
|
|
|
std::vector<int> result = literal_int_vec.get_int_vector();
|
2019-01-14 18:35:25 +00:00
|
|
|
BOOST_CHECK_EQUAL_COLLECTIONS(
|
|
|
|
|
test_data.begin(), test_data.end(), result.begin(), result.end());
|
2016-08-02 01:17:41 +00:00
|
|
|
BOOST_REQUIRE_THROW(literal_int_vec.get_bool(), uhd::type_error);
|
|
|
|
|
BOOST_REQUIRE_THROW(literal_int_vec.get_int(), uhd::type_error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Need those for the variable testing:
|
2019-01-14 18:35:25 +00:00
|
|
|
expression::type_t variable_get_type(const std::string& var_name)
|
2016-08-02 01:17:41 +00:00
|
|
|
{
|
|
|
|
|
if (var_name == "spp") {
|
|
|
|
|
std::cout << "Returning type for $spp..." << std::endl;
|
|
|
|
|
return expression::TYPE_INT;
|
|
|
|
|
}
|
|
|
|
|
if (var_name == "is_true") {
|
|
|
|
|
std::cout << "Returning type for $is_true..." << std::endl;
|
|
|
|
|
return expression::TYPE_BOOL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw uhd::syntax_error("Cannot infer type (unknown variable)");
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_literal variable_get_value(const std::string& var_name)
|
2016-08-02 01:17:41 +00:00
|
|
|
{
|
|
|
|
|
if (var_name == "spp") {
|
|
|
|
|
std::cout << "Returning value for $spp..." << std::endl;
|
|
|
|
|
return expression_literal(5);
|
|
|
|
|
}
|
|
|
|
|
if (var_name == "is_true") {
|
|
|
|
|
std::cout << "Returning value for $is_true..." << std::endl;
|
|
|
|
|
return expression_literal(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw uhd::syntax_error("Cannot read value (unknown variable)");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_variables)
|
|
|
|
|
{
|
2019-01-14 18:35:25 +00:00
|
|
|
BOOST_REQUIRE_THROW(expression_variable v_fail("foo", // Invalid token
|
|
|
|
|
boost::bind(&variable_get_type, _1),
|
|
|
|
|
boost::bind(&variable_get_value, _1)),
|
|
|
|
|
uhd::assertion_error);
|
|
|
|
|
|
|
|
|
|
expression_variable v("$spp", // The token
|
|
|
|
|
boost::bind(&variable_get_type, _1), // type-getter
|
|
|
|
|
boost::bind(&variable_get_value, _1) // value-getter
|
2016-08-02 01:17:41 +00:00
|
|
|
);
|
|
|
|
|
BOOST_CHECK_EQUAL(v.infer_type(), expression::TYPE_INT);
|
|
|
|
|
BOOST_CHECK_EQUAL(v.eval().get_int(), 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_container)
|
|
|
|
|
{
|
|
|
|
|
// Create some sub-expressions:
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_literal::sptr l_true = E(true);
|
2016-08-02 01:17:41 +00:00
|
|
|
expression_literal::sptr l_false = E(false);
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_literal::sptr l_int = E(5);
|
2016-08-02 01:17:41 +00:00
|
|
|
BOOST_REQUIRE_EQUAL(l_false->get_bool(), false);
|
|
|
|
|
BOOST_REQUIRE_EQUAL(l_false->to_bool(), false);
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_variable::sptr l_boolvar =
|
|
|
|
|
boost::make_shared<expression_variable>("$is_true",
|
|
|
|
|
boost::bind(&variable_get_type, _1),
|
|
|
|
|
boost::bind(&variable_get_value, _1));
|
2016-08-02 01:17:41 +00:00
|
|
|
|
|
|
|
|
// This will throw anytime it's evaluated:
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_variable::sptr l_failvar =
|
|
|
|
|
boost::make_shared<expression_variable>("$does_not_exist",
|
|
|
|
|
boost::bind(&variable_get_type, _1),
|
|
|
|
|
boost::bind(&variable_get_value, _1));
|
2016-08-02 01:17:41 +00:00
|
|
|
|
|
|
|
|
expression_container c;
|
|
|
|
|
std::cout << "One true, OR: " << std::endl;
|
|
|
|
|
c.add(l_true);
|
|
|
|
|
c.set_combiner_safe(expression_container::COMBINE_OR);
|
|
|
|
|
expression_literal ret_val_1 = c.eval();
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_1.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_1.eval().get_bool(), true);
|
|
|
|
|
|
|
|
|
|
std::cout << std::endl << std::endl << "Two true, one false, OR: " << std::endl;
|
|
|
|
|
c.add(l_true);
|
|
|
|
|
c.add(l_false);
|
|
|
|
|
expression_literal ret_val_2 = c.eval();
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_2.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_2.eval().get_bool(), true);
|
|
|
|
|
|
|
|
|
|
expression_container c2;
|
|
|
|
|
c2.add(l_false);
|
|
|
|
|
c2.add(l_false);
|
|
|
|
|
c2.set_combiner(expression_container::COMBINE_AND);
|
|
|
|
|
std::cout << std::endl << std::endl << "Two false, AND: " << std::endl;
|
|
|
|
|
expression_literal ret_val_3 = c2.eval();
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_3.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_REQUIRE_EQUAL(ret_val_3.eval().get_bool(), false);
|
|
|
|
|
|
|
|
|
|
c2.add(l_failvar);
|
|
|
|
|
// Will not fail, because l_failvar never gets eval'd:
|
|
|
|
|
expression_literal ret_val_4 = c2.eval();
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_4.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_4.eval().get_bool(), false);
|
|
|
|
|
|
|
|
|
|
// Same here:
|
|
|
|
|
c.add(l_failvar);
|
|
|
|
|
expression_literal ret_val_5 = c.eval();
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_5.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK_EQUAL(ret_val_5.eval().get_bool(), true);
|
|
|
|
|
|
|
|
|
|
// Now it'll throw:
|
|
|
|
|
c.set_combiner(expression_container::COMBINE_ALL);
|
|
|
|
|
BOOST_REQUIRE_THROW(c.eval(), uhd::syntax_error);
|
|
|
|
|
|
|
|
|
|
std::cout << "Checking type inference on ',' sequences: " << std::endl;
|
|
|
|
|
// Check types match
|
|
|
|
|
BOOST_CHECK_EQUAL(c2.infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
expression_container c3;
|
|
|
|
|
c3.set_combiner(expression_container::COMBINE_ALL);
|
|
|
|
|
c3.add(l_false);
|
|
|
|
|
c3.add(l_int);
|
|
|
|
|
BOOST_CHECK_EQUAL(c3.infer_type(), expression::TYPE_INT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// We'll define two functions here: ADD and XOR. The former shall
|
|
|
|
|
// be defined for INT and DOUBLE
|
|
|
|
|
class functable_mockup_impl : public function_table
|
|
|
|
|
{
|
2019-01-14 18:35:25 +00:00
|
|
|
public:
|
|
|
|
|
functable_mockup_impl(void){};
|
2016-08-02 01:17:41 +00:00
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
bool function_exists(const std::string& name) const
|
|
|
|
|
{
|
2016-08-02 01:17:41 +00:00
|
|
|
return name == "ADD" or name == "XOR" or name == "AND";
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
bool function_exists(const std::string& name,
|
|
|
|
|
const expression_function::argtype_list_type& arg_types) const
|
|
|
|
|
{
|
2016-08-02 01:17:41 +00:00
|
|
|
if (name == "ADD") {
|
2019-01-14 18:35:25 +00:00
|
|
|
if (arg_types.size() == 2 and arg_types[0] == expression::TYPE_DOUBLE
|
|
|
|
|
and arg_types[1] == expression::TYPE_DOUBLE) {
|
2016-08-02 01:17:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-01-14 18:35:25 +00:00
|
|
|
if (arg_types.size() == 2 and arg_types[0] == expression::TYPE_INT
|
|
|
|
|
and arg_types[1] == expression::TYPE_INT) {
|
2016-08-02 01:17:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name == "XOR" or name == "AND") {
|
2019-01-14 18:35:25 +00:00
|
|
|
if (arg_types.size() == 2 and arg_types[0] == expression::TYPE_BOOL
|
|
|
|
|
and arg_types[1] == expression::TYPE_BOOL) {
|
2016-08-02 01:17:41 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
expression::type_t get_type(const std::string& name,
|
|
|
|
|
const expression_function::argtype_list_type& arg_types) const
|
|
|
|
|
{
|
2016-08-02 01:17:41 +00:00
|
|
|
if (not function_exists(name, arg_types)) {
|
2019-01-14 18:35:25 +00:00
|
|
|
throw uhd::syntax_error(
|
|
|
|
|
str(boost::format(
|
|
|
|
|
"[EXPR_TEXT] get_type(): Unknown function: %s, %d arguments")
|
|
|
|
|
% name % arg_types.size()));
|
2016-08-02 01:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name == "XOR" or name == "AND") {
|
|
|
|
|
return expression::TYPE_BOOL;
|
|
|
|
|
}
|
|
|
|
|
if (name == "ADD") {
|
|
|
|
|
return arg_types[0];
|
|
|
|
|
}
|
|
|
|
|
UHD_THROW_INVALID_CODE_PATH();
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_literal eval(const std::string& name,
|
|
|
|
|
const expression_function::argtype_list_type& arg_types,
|
|
|
|
|
expression_container::expr_list_type& args)
|
|
|
|
|
{
|
2016-08-02 01:17:41 +00:00
|
|
|
if (name == "XOR") {
|
2019-01-14 18:35:25 +00:00
|
|
|
if (arg_types.size() != 2 or args.size() != 2
|
2016-08-02 01:17:41 +00:00
|
|
|
or arg_types[0] != expression::TYPE_BOOL
|
|
|
|
|
or arg_types[1] != expression::TYPE_BOOL
|
|
|
|
|
or args[0]->infer_type() != expression::TYPE_BOOL
|
2019-01-14 18:35:25 +00:00
|
|
|
or args[1]->infer_type() != expression::TYPE_BOOL) {
|
2016-08-02 01:17:41 +00:00
|
|
|
throw uhd::syntax_error("eval(): XOR type mismatch");
|
|
|
|
|
}
|
2019-01-14 18:35:25 +00:00
|
|
|
return expression_literal(
|
|
|
|
|
bool(args[0]->eval().get_bool() xor args[1]->eval().get_bool()));
|
2016-08-02 01:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name == "AND") {
|
2019-01-14 18:35:25 +00:00
|
|
|
if (arg_types.size() != 2 or args.size() != 2
|
2016-08-02 01:17:41 +00:00
|
|
|
or arg_types[0] != expression::TYPE_BOOL
|
|
|
|
|
or arg_types[1] != expression::TYPE_BOOL
|
|
|
|
|
or args[0]->infer_type() != expression::TYPE_BOOL
|
2019-01-14 18:35:25 +00:00
|
|
|
or args[1]->infer_type() != expression::TYPE_BOOL) {
|
2016-08-02 01:17:41 +00:00
|
|
|
throw uhd::syntax_error("eval(): AND type mismatch");
|
|
|
|
|
}
|
|
|
|
|
std::cout << "Calling AND" << std::endl;
|
|
|
|
|
and_counter++;
|
2019-01-14 18:35:25 +00:00
|
|
|
return expression_literal(
|
|
|
|
|
bool(args[0]->eval().get_bool() and args[1]->eval().get_bool()));
|
2016-08-02 01:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (name == "ADD") {
|
|
|
|
|
if (args.size() != 2) {
|
|
|
|
|
throw uhd::syntax_error("eval(): ADD type mismatch");
|
|
|
|
|
}
|
2019-01-14 18:35:25 +00:00
|
|
|
if ((args[0]->infer_type() == expression::TYPE_INT)
|
|
|
|
|
and (args[1]->infer_type() == expression::TYPE_INT)) {
|
|
|
|
|
return expression_literal(
|
|
|
|
|
int(args[0]->eval().get_int() + args[1]->eval().get_int()));
|
|
|
|
|
} else if ((args[0]->infer_type() == expression::TYPE_DOUBLE)
|
|
|
|
|
and (args[1]->infer_type() == expression::TYPE_DOUBLE)) {
|
|
|
|
|
return expression_literal(
|
|
|
|
|
double(args[0]->eval().get_double() + args[1]->eval().get_double()));
|
2016-08-02 01:17:41 +00:00
|
|
|
}
|
|
|
|
|
throw uhd::syntax_error("eval(): ADD type mismatch");
|
|
|
|
|
}
|
|
|
|
|
throw uhd::syntax_error("eval(): unknown function");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We don't actually need this
|
2019-01-14 18:35:25 +00:00
|
|
|
void register_function(const std::string&,
|
|
|
|
|
const function_table::function_ptr&,
|
|
|
|
|
const expression::type_t,
|
|
|
|
|
const expression_function::argtype_list_type&){};
|
2016-08-02 01:17:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The annoying part: Testing the test fixtures
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_functable_mockup)
|
|
|
|
|
{
|
|
|
|
|
functable_mockup_impl functable;
|
|
|
|
|
|
|
|
|
|
BOOST_CHECK(functable.function_exists("ADD"));
|
|
|
|
|
BOOST_CHECK(functable.function_exists("XOR"));
|
|
|
|
|
BOOST_CHECK(not functable.function_exists("FOOBAR"));
|
|
|
|
|
|
|
|
|
|
BOOST_CHECK(functable.function_exists("ADD", two_int_args));
|
|
|
|
|
BOOST_CHECK(functable.function_exists("ADD", two_double_args));
|
|
|
|
|
BOOST_CHECK(functable.function_exists("XOR", two_bool_args));
|
|
|
|
|
BOOST_CHECK(not functable.function_exists("ADD", two_bool_args));
|
|
|
|
|
BOOST_CHECK(not functable.function_exists("ADD", no_args));
|
|
|
|
|
BOOST_CHECK(not functable.function_exists("XOR", no_args));
|
|
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(functable.get_type("ADD", two_int_args), expression::TYPE_INT);
|
2019-01-14 18:35:25 +00:00
|
|
|
BOOST_CHECK_EQUAL(
|
|
|
|
|
functable.get_type("ADD", two_double_args), expression::TYPE_DOUBLE);
|
2016-08-02 01:17:41 +00:00
|
|
|
BOOST_CHECK_EQUAL(functable.get_type("XOR", two_bool_args), expression::TYPE_BOOL);
|
|
|
|
|
|
2018-04-26 20:13:32 +00:00
|
|
|
expression_container::expr_list_type add_args_int{E(2), E(3)};
|
|
|
|
|
expression_container::expr_list_type add_args_dbl{E(2.25), E(5.0)};
|
|
|
|
|
expression_container::expr_list_type xor_args_bool{E(true), E(false)};
|
2016-08-02 01:17:41 +00:00
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
BOOST_CHECK_EQUAL(
|
|
|
|
|
functable.eval("ADD", two_int_args, add_args_int), expression_literal(5));
|
|
|
|
|
BOOST_CHECK_EQUAL(
|
|
|
|
|
functable.eval("ADD", two_double_args, add_args_dbl), expression_literal(7.25));
|
|
|
|
|
BOOST_CHECK_EQUAL(
|
|
|
|
|
functable.eval("XOR", two_bool_args, xor_args_bool), expression_literal(true));
|
2016-08-02 01:17:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_function_expression)
|
|
|
|
|
{
|
|
|
|
|
function_table::sptr ft = boost::make_shared<functable_mockup_impl>();
|
|
|
|
|
|
|
|
|
|
// Very simple function: ADD(2, 3)
|
|
|
|
|
expression_function func1("ADD", ft);
|
|
|
|
|
func1.add(E(2));
|
|
|
|
|
func1.add(E(3));
|
|
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(func1.eval(), expression_literal(5));
|
|
|
|
|
|
|
|
|
|
// More elaborate: ADD(ADD(2, 3), ADD(ADD(4, 5), 6)) ?= 20
|
|
|
|
|
// f4 f1 f3 f2
|
|
|
|
|
expression_function f1("ADD", ft);
|
|
|
|
|
f1.add(E(2));
|
|
|
|
|
f1.add(E(3));
|
|
|
|
|
expression_function f2("ADD", ft);
|
|
|
|
|
f2.add(E(4));
|
|
|
|
|
f2.add(E(5));
|
|
|
|
|
expression_function f3("ADD", ft);
|
|
|
|
|
f3.add(boost::make_shared<expression_function>(f2));
|
|
|
|
|
f3.add(E(6));
|
|
|
|
|
expression_function f4("ADD", ft);
|
|
|
|
|
f4.add(boost::make_shared<expression_function>(f1));
|
|
|
|
|
f4.add(boost::make_shared<expression_function>(f3));
|
|
|
|
|
|
|
|
|
|
BOOST_CHECK_EQUAL(f4.eval().get_int(), 20);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_function_expression_laziness)
|
|
|
|
|
{
|
|
|
|
|
function_table::sptr ft = boost::make_shared<functable_mockup_impl>();
|
|
|
|
|
|
|
|
|
|
// We run AND(AND(false, false), AND(false, false)).
|
|
|
|
|
// f1 f2 f3
|
|
|
|
|
// That makes three ANDs
|
|
|
|
|
// in total. However, we will only see AND being evaluated twice, because
|
|
|
|
|
// the outcome is clear after running the first AND in the argument list.
|
|
|
|
|
expression_function::sptr f2 = boost::make_shared<expression_function>("AND", ft);
|
|
|
|
|
f2->add(E(false));
|
|
|
|
|
f2->add(E(false));
|
|
|
|
|
BOOST_CHECK(not f2->eval().get_bool());
|
|
|
|
|
|
|
|
|
|
expression_function::sptr f3 = boost::make_shared<expression_function>("AND", ft);
|
|
|
|
|
f3->add(E(false));
|
|
|
|
|
f3->add(E(false));
|
|
|
|
|
BOOST_CHECK(not f3->eval().get_bool());
|
|
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
and_counter = 0;
|
2016-08-02 01:17:41 +00:00
|
|
|
expression_function::sptr f1 = boost::make_shared<expression_function>("AND", ft);
|
|
|
|
|
f1->add(f2);
|
|
|
|
|
f1->add(f3);
|
|
|
|
|
|
|
|
|
|
BOOST_CHECK(not f1->eval().get_bool());
|
|
|
|
|
BOOST_CHECK_EQUAL(and_counter, 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BOOST_AUTO_TEST_CASE(test_sptrs)
|
|
|
|
|
{
|
|
|
|
|
expression_container::sptr c = expression_container::make();
|
|
|
|
|
BOOST_CHECK_EQUAL(c->infer_type(), expression::TYPE_BOOL);
|
|
|
|
|
BOOST_CHECK(c->eval().get_bool());
|
|
|
|
|
|
2019-01-14 18:35:25 +00:00
|
|
|
expression_variable::sptr v = expression_variable::make("$spp",
|
|
|
|
|
boost::bind(&variable_get_type, _1), // type-getter
|
|
|
|
|
boost::bind(&variable_get_value, _1) // value-getter
|
2016-08-02 01:17:41 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
c->add(v);
|
|
|
|
|
BOOST_REQUIRE_EQUAL(c->infer_type(), expression::TYPE_INT);
|
|
|
|
|
BOOST_CHECK_EQUAL(c->eval().get_int(), 5);
|
|
|
|
|
}
|