Skip to content

Commit ed227dc

Browse files
committed
added +,- operators so user can do -a and bitwise inplace operators;
1 parent 705a73a commit ed227dc

1 file changed

Lines changed: 110 additions & 53 deletions

File tree

include/pythonic/pythonicVars.hpp

Lines changed: 110 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ namespace pythonic
948948
}
949949
if (tag_ == TypeTag::STRING || other.tag_ == TypeTag::STRING)
950950
{
951-
throw pythonic::PythonicTypeError("cannot multiply two strings");
951+
throw pythonic::PythonicTypeError("operator* not supported for strings. Cannot perform '" + type() + " * " + other.type() + "'.");
952952
}
953953

954954
// Check if any input is floating point
@@ -1006,7 +1006,7 @@ namespace pythonic
10061006
{
10071007
if (tag_ == TypeTag::STRING || other.tag_ == TypeTag::STRING)
10081008
{
1009-
throw pythonic::PythonicTypeError("cannot divide strings");
1009+
throw pythonic::PythonicTypeError("operator/ not supported for strings. Cannot perform '" + type() + " / " + other.type() + "'.");
10101010
}
10111011

10121012
long double divisor = other.toLongDouble();
@@ -1032,7 +1032,7 @@ namespace pythonic
10321032
{
10331033
if (tag_ == TypeTag::STRING || other.tag_ == TypeTag::STRING)
10341034
{
1035-
throw pythonic::PythonicTypeError("cannot perform modulo on strings");
1035+
throw pythonic::PythonicTypeError("operator% not supported for strings. Cannot perform '" + type() + " % " + other.type() + "'.");
10361036
}
10371037

10381038
long double divisor = other.toLongDouble();
@@ -2260,7 +2260,9 @@ namespace pythonic
22602260
}
22612261
}
22622262
// Mixed types - use type promotion (handles numeric + numeric, string + anything, etc.)
2263-
return addPromoted(other);
2263+
if ((is_string() || isNumeric()) && (other.is_string() || other.isNumeric()))
2264+
return addPromoted(other);
2265+
throw pythonic::PythonicTypeError("operator+ not supported for these types. Cannot perform '" + type() + " + " + other.type() + "'.");
22642266
}
22652267

22662268
// Unary plus: returns a copy (Python semantics)
@@ -2341,6 +2343,55 @@ namespace pythonic
23412343
}
23422344
return var(std::move(result));
23432345
}
2346+
case TypeTag::ORDEREDSET:
2347+
{
2348+
// Both are ordered sets, use merge-like difference
2349+
const auto &a = var_get<OrderedSet>();
2350+
const auto &b = other.var_get<OrderedSet>();
2351+
OrderedSet result;
2352+
auto it_a = a.begin();
2353+
auto it_b = b.begin();
2354+
while (it_a != a.end() && it_b != b.end())
2355+
{
2356+
if (*it_a < *it_b)
2357+
{
2358+
result.insert(*it_a);
2359+
++it_a;
2360+
}
2361+
else if (*it_b < *it_a)
2362+
{
2363+
++it_b;
2364+
}
2365+
else
2366+
{
2367+
// Equal, skip
2368+
++it_a;
2369+
++it_b;
2370+
}
2371+
}
2372+
// Insert remaining elements from a
2373+
while (it_a != a.end())
2374+
{
2375+
result.insert(*it_a);
2376+
++it_a;
2377+
}
2378+
return var(std::move(result));
2379+
}
2380+
case TypeTag::ORDEREDDICT:
2381+
{
2382+
// Both are ordered dicts, remove keys in b from a, preserve order
2383+
const auto &a = var_get<OrderedDict>();
2384+
const auto &b = other.var_get<OrderedDict>();
2385+
OrderedDict result;
2386+
for (const auto &kv : a)
2387+
{
2388+
if (b.find(kv.first) == b.end())
2389+
{
2390+
result.insert(kv);
2391+
}
2392+
}
2393+
return var(std::move(result));
2394+
}
23442395
case TypeTag::LIST:
23452396
{
23462397
const auto &a = var_get<List>();
@@ -2379,7 +2430,7 @@ namespace pythonic
23792430
{
23802431
return subPromoted(other);
23812432
}
2382-
throw pythonic::PythonicTypeError("operator- requires arithmetic types or containers");
2433+
throw pythonic::PythonicTypeError("operator- requires arithmetic types or containers. Cannot perform '" + type() + " - " + other.type() + "'.");
23832434
}
23842435

23852436
var operator*(const var &other) const
@@ -2457,7 +2508,7 @@ namespace pythonic
24572508
}
24582509
return var(std::move(result));
24592510
}
2460-
throw pythonic::PythonicTypeError("unsupported types for multiplication");
2511+
throw pythonic::PythonicTypeError("operator* not supported for these types. Cannot perform '" + type() + " * " + other.type() + "'.");
24612512
}
24622513

24632514
var operator/(const var &other) const
@@ -2569,7 +2620,7 @@ namespace pythonic
25692620
{
25702621
return divPromoted(other);
25712622
}
2572-
throw pythonic::PythonicTypeError("unsupported types for division");
2623+
throw pythonic::PythonicTypeError("operator/ not supported for these types. Cannot perform '" + type() + " / " + other.type() + "'.");
25732624
}
25742625

25752626
var operator%(const var &other) const
@@ -2636,7 +2687,7 @@ namespace pythonic
26362687
{
26372688
return modPromoted(other);
26382689
}
2639-
throw pythonic::PythonicTypeError("unsupported types for modulo");
2690+
throw pythonic::PythonicTypeError("operator% not supported for these types. Cannot perform '" + type() + " % " + other.type() + "'.");
26402691
}
26412692

26422693
// ============ In-Place Arithmetic Operators ============
@@ -3154,8 +3205,8 @@ namespace pythonic
31543205
{
31553206
return var(toDouble() == other.toDouble());
31563207
}
3157-
// Different types (except numeric) are not equal
3158-
return var(false);
3208+
// Different types (except numeric) are not equal: throw for clarity
3209+
throw pythonic::PythonicTypeError("operator== not supported for these types. Cannot perform '" + type() + " == " + other.type() + "'.");
31593210
}
31603211

31613212
var operator!=(const var &other) const
@@ -3271,7 +3322,7 @@ namespace pythonic
32713322
{
32723323
return var(toDouble() != other.toDouble());
32733324
}
3274-
return var(true);
3325+
throw pythonic::PythonicTypeError("operator!= not supported for these types. Cannot perform '" + type() + " != " + other.type() + "'.");
32753326
}
32763327

32773328
var operator>(const var &other) const
@@ -3310,7 +3361,7 @@ namespace pythonic
33103361
{
33113362
return var(toDouble() > other.toDouble());
33123363
}
3313-
throw pythonic::PythonicTypeError("unsupported types for comparison");
3364+
throw pythonic::PythonicTypeError("operator> not supported for these types. Cannot perform '" + type() + " > " + other.type() + "'.");
33143365
}
33153366

33163367
var operator>=(const var &other) const
@@ -3349,7 +3400,7 @@ namespace pythonic
33493400
{
33503401
return var(toDouble() >= other.toDouble());
33513402
}
3352-
throw pythonic::PythonicTypeError("unsupported types for comparison");
3403+
throw pythonic::PythonicTypeError("operator>= not supported for these types. Cannot perform '" + type() + " >= " + other.type() + "'.");
33533404
}
33543405

33553406
var operator<=(const var &other) const
@@ -3388,7 +3439,7 @@ namespace pythonic
33883439
{
33893440
return var(toDouble() <= other.toDouble());
33903441
}
3391-
throw pythonic::PythonicTypeError("unsupported types for comparison");
3442+
throw pythonic::PythonicTypeError("operator<= not supported for these types. Cannot perform '" + type() + " <= " + other.type() + "'.");
33923443
}
33933444

33943445
// ============ OPTIMIZED Implicit Conversion Operators for Arithmetic Types ============
@@ -3747,7 +3798,7 @@ namespace pythonic
37473798
case TypeTag::ULONG_LONG:
37483799
return var(~var_get<unsigned long long>());
37493800
default:
3750-
throw pythonic::PythonicTypeError("bitwise NOT requires integral type");
3801+
throw pythonic::PythonicTypeError("operator~ requires integral type. Cannot perform '~" + type() + "'.");
37513802
}
37523803
}
37533804

@@ -3864,7 +3915,7 @@ namespace pythonic
38643915
{
38653916
return var(toLongLong() & other.toLongLong());
38663917
}
3867-
throw pythonic::PythonicTypeError("operator& requires integral types or containers");
3918+
throw pythonic::PythonicTypeError("operator& requires integral types or containers. Cannot perform '" + type() + " & " + other.type() + "'.");
38683919
}
38693920

38703921
var operator|(const var &other) const
@@ -3976,7 +4027,7 @@ namespace pythonic
39764027
{
39774028
return var(toLongLong() | other.toLongLong());
39784029
}
3979-
throw pythonic::PythonicTypeError("operator| requires integral types or containers");
4030+
throw pythonic::PythonicTypeError("operator| requires integral types or containers. Cannot perform '" + type() + " | " + other.type() + "'.");
39804031
}
39814032

39824033
var operator^(const var &other) const
@@ -4090,46 +4141,52 @@ namespace pythonic
40904141
{
40914142
return var(toLongLong() ^ other.toLongLong());
40924143
}
4093-
throw pythonic::PythonicTypeError("operator^ requires integral types or sets/lists");
4144+
throw pythonic::PythonicTypeError("operator^ requires integral types or sets/lists. Cannot perform '" + type() + " ^ " + other.type() + "'.");
40944145
}
40954146
// In-place bitwise AND
4096-
var &operator&=(const var &other) {
4097-
*this = *this & other;
4098-
return *this;
4099-
}
4147+
var &operator&=(const var &other)
4148+
{
4149+
*this = *this & other;
4150+
return *this;
4151+
}
41004152

4101-
// In-place bitwise OR
4102-
var &operator|=(const var &other) {
4103-
*this = *this | other;
4104-
return *this;
4105-
}
4153+
// In-place bitwise OR
4154+
var &operator|=(const var &other)
4155+
{
4156+
*this = *this | other;
4157+
return *this;
4158+
}
41064159

4107-
// In-place bitwise XOR
4108-
var &operator^=(const var &other) {
4109-
*this = *this ^ other;
4110-
return *this;
4111-
}
4160+
// In-place bitwise XOR
4161+
var &operator^=(const var &other)
4162+
{
4163+
*this = *this ^ other;
4164+
return *this;
4165+
}
41124166

4113-
// In-place bitwise AND with primitive
4114-
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
4115-
var &operator&=(T other) {
4116-
*this = *this & var(other);
4117-
return *this;
4118-
}
4167+
// In-place bitwise AND with primitive
4168+
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
4169+
var &operator&=(T other)
4170+
{
4171+
*this = *this & var(other);
4172+
return *this;
4173+
}
41194174

4120-
// In-place bitwise OR with primitive
4121-
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
4122-
var &operator|=(T other) {
4123-
*this = *this | var(other);
4124-
return *this;
4125-
}
4175+
// In-place bitwise OR with primitive
4176+
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
4177+
var &operator|=(T other)
4178+
{
4179+
*this = *this | var(other);
4180+
return *this;
4181+
}
41264182

4127-
// In-place bitwise XOR with primitive
4128-
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
4129-
var &operator^=(T other) {
4130-
*this = *this ^ var(other);
4131-
return *this;
4132-
}
4183+
// In-place bitwise XOR with primitive
4184+
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
4185+
var &operator^=(T other)
4186+
{
4187+
*this = *this ^ var(other);
4188+
return *this;
4189+
}
41334190

41344191
// Bool conversion
41354192
operator bool() const
@@ -4234,7 +4291,7 @@ namespace pythonic
42344291
}
42354292
return lst[index];
42364293
}
4237-
throw pythonic::PythonicTypeError("operator[] requires a list");
4294+
throw pythonic::PythonicTypeError("operator[] requires a list. Cannot perform '" + type() + "[index]'.");
42384295
}
42394296

42404297
const var &operator[](size_t index) const
@@ -4248,7 +4305,7 @@ namespace pythonic
42484305
}
42494306
return lst[index];
42504307
}
4251-
throw pythonic::PythonicTypeError("operator[] requires a list");
4308+
throw pythonic::PythonicTypeError("operator[] requires a list. Cannot perform '" + type() + "[index]'.");
42524309
}
42534310

42544311
var &operator[](const std::string &key)
@@ -4261,7 +4318,7 @@ namespace pythonic
42614318
{
42624319
return var_get<OrderedDict>()[key];
42634320
}
4264-
throw pythonic::PythonicTypeError("operator[] requires a dict or ordered_dict");
4321+
throw pythonic::PythonicTypeError("operator[] requires a dict or ordered_dict. Cannot perform '" + type() + "[key]'.");
42654322
}
42664323

42674324
var &operator[](const char *key)

0 commit comments

Comments
 (0)