404 lines
7.9 KiB
C++
404 lines
7.9 KiB
C++
|
#include <catch.hpp>
|
||
|
|
||
|
#include <pfor/expression/expression.h>
|
||
|
|
||
|
template<typename T>
|
||
|
struct Value {
|
||
|
using IsExpression = pfor::expr::tag::Expression;
|
||
|
|
||
|
T* ptr;
|
||
|
|
||
|
Value(T& v): ptr{&v} {}
|
||
|
T& eval() { return *ptr; }
|
||
|
};
|
||
|
|
||
|
template<typename T, std::size_t N>
|
||
|
struct Array {
|
||
|
using IsExpression = pfor::expr::tag::Expression;
|
||
|
|
||
|
T* ptr;
|
||
|
|
||
|
Array(T* v): ptr{v} {}
|
||
|
T& operator[](std::size_t i) { return ptr[i]; }
|
||
|
};
|
||
|
|
||
|
TEST_CASE("operations") {
|
||
|
int a = 240, b = 3;
|
||
|
int *pa = &a, *pb = &b;
|
||
|
int t[5]{100, 200, 300, 400, 500}, u[5]{1, 2, 3, 4, 5};
|
||
|
int *ps[]{pa, pb};
|
||
|
|
||
|
Value<int> va{a}, vb{b};
|
||
|
Value<int*> vpa{pa}, vpb{pb};
|
||
|
Array<int, 5> at{t}, au{u};
|
||
|
Array<int*, 2> aps{ps};
|
||
|
|
||
|
int i3{3};
|
||
|
Value<int> v3{i3};
|
||
|
|
||
|
SECTION("unary operators") {
|
||
|
SECTION("PostIncr") {
|
||
|
int a_{a}, b_{b}, t3{t[3]};
|
||
|
pfor::expr::op::PostIncr o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == a_);
|
||
|
REQUIRE(a == a_+1);
|
||
|
|
||
|
REQUIRE(o.eval(vb) == b_);
|
||
|
REQUIRE(b == b_+1);
|
||
|
|
||
|
REQUIRE(o.eval(3, at) == t3);
|
||
|
REQUIRE(t[3] == t3+1);
|
||
|
}
|
||
|
|
||
|
SECTION("PostDecr") {
|
||
|
int a_{a}, b_{b}, t3{t[3]};
|
||
|
pfor::expr::op::PostDecr o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == a_);
|
||
|
REQUIRE(a == a_-1);
|
||
|
|
||
|
REQUIRE(o.eval(vb) == b_);
|
||
|
REQUIRE(b == b_-1);
|
||
|
|
||
|
REQUIRE(o.eval(3, at) == t3);
|
||
|
REQUIRE(t[3] == t3-1);
|
||
|
}
|
||
|
|
||
|
SECTION("PreIncr") {
|
||
|
int a_{a}, b_{b}, t3{t[3]};
|
||
|
pfor::expr::op::PreIncr o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == a_+1);
|
||
|
REQUIRE(o.eval(vb) == b_+1);
|
||
|
REQUIRE(o.eval(3, at) == t3+1);
|
||
|
}
|
||
|
|
||
|
SECTION("PreDecr") {
|
||
|
int a_{a}, b_{b}, t3{t[3]};
|
||
|
pfor::expr::op::PreDecr o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == a_-1);
|
||
|
REQUIRE(o.eval(vb) == b_-1);
|
||
|
REQUIRE(o.eval(3, at) == t3-1);
|
||
|
}
|
||
|
|
||
|
SECTION("Plus") {
|
||
|
pfor::expr::op::Plus o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == a);
|
||
|
REQUIRE(o.eval(vb) == b);
|
||
|
REQUIRE(o.eval(3, at) == t[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Minus") {
|
||
|
pfor::expr::op::Minus o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == -a);
|
||
|
REQUIRE(o.eval(vb) == -b);
|
||
|
REQUIRE(o.eval(3, at) == -t[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Not") {
|
||
|
pfor::expr::op::Not o;
|
||
|
|
||
|
REQUIRE_FALSE(o.eval(va));
|
||
|
REQUIRE_FALSE(o.eval(vb));
|
||
|
REQUIRE_FALSE(o.eval(3, at));
|
||
|
}
|
||
|
|
||
|
SECTION("BitNot") {
|
||
|
pfor::expr::op::BitNot o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == ~a);
|
||
|
REQUIRE(o.eval(vb) == ~b);
|
||
|
REQUIRE(o.eval(3, at) == ~t[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Indirection") {
|
||
|
pfor::expr::op::Indirection o;
|
||
|
|
||
|
REQUIRE(o.eval(vpa) == a);
|
||
|
REQUIRE(o.eval(1, aps) == b);
|
||
|
}
|
||
|
|
||
|
SECTION("AddressOf") {
|
||
|
pfor::expr::op::AddressOf o;
|
||
|
|
||
|
REQUIRE(o.eval(va) == &a);
|
||
|
REQUIRE(o.eval(3, at) == t+3);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SECTION("binary operators") {
|
||
|
SECTION("PtrToMem") {
|
||
|
struct Foo {
|
||
|
int bar = 42;
|
||
|
} foo;
|
||
|
|
||
|
Value<decltype(&Foo::bar) const> vm{&Foo::bar};
|
||
|
Value<Foo*const> vf{&foo};
|
||
|
|
||
|
decltype(&Foo::bar) const tm[]{&Foo::bar};
|
||
|
Foo*const tf[]{&foo};
|
||
|
Array<decltype(&Foo::bar) const, 1> am{tm};
|
||
|
Array<Foo*const, 1> af{tf};
|
||
|
|
||
|
pfor::expr::op::PtrToMem o;
|
||
|
|
||
|
// TODO fix segfault in release
|
||
|
// REQUIRE(o.eval(vf, vm) == 42);
|
||
|
// REQUIRE(o.eval(0, af, am) == 42);
|
||
|
}
|
||
|
|
||
|
SECTION("Multiplication") {
|
||
|
pfor::expr::op::Multiplication o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a*b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]*u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Division") {
|
||
|
pfor::expr::op::Division o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a/b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]/u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Modulo") {
|
||
|
pfor::expr::op::Modulo o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a%b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]%u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Addition") {
|
||
|
pfor::expr::op::Addition o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a+b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]+u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Subtraction") {
|
||
|
pfor::expr::op::Subtraction o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a-b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]-u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("LeftShift") {
|
||
|
pfor::expr::op::LeftShift o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a<<b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]<<u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("RightShift") {
|
||
|
pfor::expr::op::RightShift o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a>>b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]>>u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Lower") {
|
||
|
pfor::expr::op::Lower o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a<b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]<u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("LowerEqual") {
|
||
|
pfor::expr::op::LowerEqual o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a<=b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]<=u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Greater") {
|
||
|
pfor::expr::op::Greater o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a>b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]>u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("GreaterEqual") {
|
||
|
pfor::expr::op::GreaterEqual o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == a>=b);
|
||
|
REQUIRE(o.eval(3, at, au) == t[3]>=u[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("Equal") {
|
||
|
pfor::expr::op::Equal o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a==b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]==u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("NotEqual") {
|
||
|
pfor::expr::op::NotEqual o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a!=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]!=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("BitAnd") {
|
||
|
pfor::expr::op::BitAnd o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a&b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]&u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("BitXor") {
|
||
|
pfor::expr::op::BitXor o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a^b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]^u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("BitOr") {
|
||
|
pfor::expr::op::BitOr o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a|b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]|u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("And") {
|
||
|
pfor::expr::op::And o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a&&b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]&&u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("Or") {
|
||
|
pfor::expr::op::Or o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a||b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]||u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("Assign") {
|
||
|
pfor::expr::op::Assign o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignAdd") {
|
||
|
pfor::expr::op::AssignAdd o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a+=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]+=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignSub") {
|
||
|
pfor::expr::op::AssignSub o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a-=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]-=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignMul") {
|
||
|
pfor::expr::op::AssignMul o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a*=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]*=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignDiv") {
|
||
|
pfor::expr::op::AssignDiv o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a/=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]/=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignMod") {
|
||
|
pfor::expr::op::AssignMod o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a%=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]%=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignLS") {
|
||
|
pfor::expr::op::AssignLS o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a<<=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]<<=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignRS") {
|
||
|
pfor::expr::op::AssignRS o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a>>=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]>>=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignAnd") {
|
||
|
pfor::expr::op::AssignAnd o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a&=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]&=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignXor") {
|
||
|
pfor::expr::op::AssignXor o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a^=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]^=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("AssignOr") {
|
||
|
pfor::expr::op::AssignOr o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == (a|=b));
|
||
|
REQUIRE(o.eval(3, at, au) == (t[3]|=u[3]));
|
||
|
}
|
||
|
|
||
|
SECTION("Comma") {
|
||
|
pfor::expr::op::Comma o;
|
||
|
|
||
|
REQUIRE(o.eval(va, vb) == b);
|
||
|
REQUIRE(o.eval(3, at, au) == au[3]);
|
||
|
|
||
|
REQUIRE(o.eval(va, va, vb) == b);
|
||
|
REQUIRE(o.eval(3, at, at, au) == au[3]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SECTION("If") {
|
||
|
pfor::expr::op::If o;
|
||
|
|
||
|
REQUIRE(o.eval(va, va, vb) == a);
|
||
|
REQUIRE(o.eval(3, at, at, au) == t[3]);
|
||
|
}
|
||
|
|
||
|
SECTION("FunctionCall") {
|
||
|
auto f1 = []{ return 42; };
|
||
|
auto f2 = [](int i, int j) { return std::to_string(i/2+j); };
|
||
|
|
||
|
decltype(f2) tf2[]{f2};
|
||
|
Array<decltype(f2), 1> atf2{tf2};
|
||
|
|
||
|
pfor::expr::op::FunctionCall o;
|
||
|
|
||
|
REQUIRE(o.eval(Value<decltype(f1)>{f1}) == 42);
|
||
|
REQUIRE(o.eval(0, atf2, at, au) == "51");
|
||
|
}
|
||
|
|
||
|
SECTION("Subscript") {
|
||
|
pfor::expr::op::Subscript o;
|
||
|
|
||
|
int i{1};
|
||
|
int id[]{1, 0};
|
||
|
int a[]{3, 2, 1, 0};
|
||
|
int a2[][2]{{3, 2}, {1, 4}};
|
||
|
Value<int> vi{i};
|
||
|
Value<int[4]> va{a};
|
||
|
Array<int, 4> ai{id};
|
||
|
Array<int[2], 4> aa{a2};
|
||
|
|
||
|
REQUIRE(o.eval(va, vi) == a[i]);
|
||
|
REQUIRE(o.eval(1, aa, ai) == a2[1][id[1]]);
|
||
|
}
|
||
|
}
|