Tokens & Operators

Tokens

S++ uses a number of tokens, with each being used in a minimal amount of contexts. The following list includes all tokens used in S++:

Token

Primary Use

Secondary Use

==

Binary equality

!=

Binary inequality

>

Binary greater than

<

Binary less than

>=

Binary greater than or equal to

<=

Binary less than or equal to

+

Binary addition

Positive number prefix

-

Binary subtraction

Negative number prefix

*

Binary multiplication

Borrow deference

/

Binary division

%

Binary remainder

**

Binary exponentiation

|

Binary bitwise OR

&

Binary bitwise AND

Borrow creation

^

Binary bitwise XOR

<<

Binary bitwise left shift

>>

Binary bitwise right shift

+=

Binary addition assignment

-=

Binary subtraction assignment

*=

Binary multiplication assignment

/=

Binary division assignment

%=

Binary remainder assignment

**=

Binary exponentiation assignment

|=

Binary bitwise OR assignment

&=

Binary bitwise AND assignment

^=

Binary bitwise XOR assignment

<<=

Binary bitwise left shift assignment

>>=

Binary bitwise right shift assignment

(

Func/object/destructure arg list

Parenthesized expression, tuple value/type

)

Func/object/destructure arg list

Parenthesized expression, tuple value/type

[

Generic/Where arg list

Array literal/destructure

]

Generic/Where arg list

Array literal/destructure

{

Block start

}

Block end

?

Propagate error

Optional type

..

Variadic marker/tuple ops

Multi argument skip (& bind)

:

Type/constraint annotation

.

Runtime member access

Decimal point

::

Static member access

,

Item separator

=

Assignment

->

Function return type

@

Annotation

!

Fallible generator exception

Never type

_

Optional generator no-value

Placeholder for unused value

!!

exhausted generator

Operators

A number of the above tokens are used as operators, and are overridable using operator classes, like in Rust. The following table shows the operator classes, and their operator method that can be overloaded.

Operator Token

Operator Class

Operator Method

==

std::ops::eq::Eq

eq

!=

std::ops::ne::Ne

ne

>

std::ops::gt::Gt

gt

<

std::ops::lt::Lt

lt

>=

std::ops::ge::Ge

ge

<=

std::ops::le::Le

le

+

std::ops::add::Add

add

-

std::ops::sub::Sub

sub

*

std::ops::mul::Mul

mul

/

std::ops::div::Div

div

%

std::ops::rem::Rem

rem

**

std::ops::pow::Pow

pow

|

std::ops::bit_ior::BitIor

bit_ior

&

std::ops::bit_and::BitAnd

bit_and

^

std::ops::bit_xor::BitXor

bit_xor

<<

std::ops::bit_shl::BitShl

bit_shl

>>

std::ops::bit_shr::BitShr

bit_shr

+=

std::ops::add_assign::AddAssign

add_assign

-=

std::ops::sub_assign::SubAssign

sub_assign

*=

std::ops::mul_assign::MulAssign

mul_assign

/=

std::ops::div_assign::DivAssign

div_assign

%=

std::ops::rem_assign::RemAssign

rem_assign

**=

std::ops::pow_assign::PowAssign

pow_assign

|=

std::ops::bit_ior_assign::BitIorAssign

bit_ior_assign

&=

std::ops::bit_and_assign::BitAndAssign

bit_and_assign

^=

std::ops::bit_xor_assign::BitXorAssign

bit_xor_assign

<<=

std::ops::bit_shl_assign::BitShlAssign

bit_shl_assign

>>=

std::ops::bit_shr_assign::BitShrAssign

bit_shr_assign

or

std::ops::ior::Ior

ior_

and

std::ops::and::And

and_

not

std::ops::not::Not

not

Non-Token Operators

There are additional operator classes that don’t have specific operator tokens, to maintain the simplicity of the language. These operators are part of the operators section of the standard library:

Operator Class

Operator Method

Usage

std::ops::neg::Neg

neg

val.neg()

std::ops::not::Not

not_

val.not

std::ops::bit_not::BitNot

bit_not

val.bit_not()

Comparison operator RHS

Due to the second-class nature of borrows, the & operator can only be specified in function calls. This means it cannot be specified in binary operators. However, for comparisons, the RHS needs to be borrowed, to support chaining comparison operators. This means the object is automatically borrowed, without the need for manually applying the & operator.

Operator Chaining

Comparison operators, except is, can be chained together, similar to Python. For example, 1 < 2 < 3 is automatically expanded to 1 < 2 and 2 < 3. Because the Eq type only borrows its argument, the rhs of the equality checks don’t get consumed, so don’t require the Copy type to be superimposed.

Equality

The equality operator between two owned types uses the Eq::eq method. An equality between two borrowed types uses reference equality, checking whether the two borrows are borrowing the same object or not. Because of the law of exclusivity, a mutable borrow cannot exist simultaneously with any other borrow of the same object, so a comparison would always return false. Therefore, it is not needed to have an &mut in a comparison.