Expressions


Everything that returns a value is an expression. Expressions can also be ran on their own as expression statements, ignoring the value.

The following expressions are implemented by [name]:

Parenthesis on LValues/RValues


[name] doesn't rely on a strict classification of expression types like C and C++ do, but it can help us understand the rest of the page. LValues are basically values that can be assigned a value (values that can be in the left hand of an assignment operation), while RValues cannot. Keep in mind that LValues and RValues aren't data types or a characteristic of a data type [or are they? references...??]

Literals


There are three kinds of literals: integers, floating point and arrays. All literals act like RValues.

Integer literals

By default, integer literals are interpreted as base-10 (decimal) values. A signed integer literal (e.g., -5) is internally parsed as the unary negation of an unsigned integer literal (-(5)), with the negation applied during compilation. The compiler assumes the type i64 for integer literals unless the value exceeds the range of i64, in which case the type u64 is inferred instead.

Hexadecimal literals start with 0x and are followed by hexadecimal characters. There may be underscores to separate digits; they will be ignored.

0xa5b84C

allowed

0xC_00_54_1F

also allowed

Binary literals start with 0b and have similar rules:

0b10010110

allowed

0b1001_1010_00_01

also allowed

Character literals are also interpreted as integer literals, and are delimited by single quotes. They can be as large as needed:

'a' // A character literal (u8)
'日' // A wide (Unicode) character literal (u32)
'helo' // An odd representation of an u64

Floating point literals

Floating point literals are literals which include a dot or a letter at the end specifying the width:

0.5 // A floating point literal (f64 by default)
0.5h // A half precision float (f16)
0.5f // A single precision float (f32)
4d // A double precision float (f64, even if it doesn't have a dot)

Array literals

Array literals are are initialized in the read section of the compiled object file, and a pointer is actually the returned value of the expression. There are two syntaxes, one for normal arrays and one for strings (which is just syntactic sugar):

[1, 5, 3, 2] // An array of i64
['h', 'e', 'l', 'l', 'o'] // An array of u8
"hello" // The same as above, in a more readable way
L"日常" A wide character (u32) string.

Arrays can contain uninitialized data (data which requires code execution to have a known value). In a similar fashion to variables, those values are initialized as zero and populated before the pointer is used.

[1, 2+3, x, myFun()]

This array is instantiated as [1, 5, 0, 0], then the third value is set to X, then myFun() is ran and its value replaces the fourth of the array.

Assignment


An assignment is an expression which assigns a value to an LValue.

*lvalue* = *expression*

The returned value is the new value assigned; the assignment itself is a RValue ((x = 5) = 2 cannot work). This allows for long assignment chains, such as x = y = z = 5.

Augmented assignment

Augmented assignment is a form of assignment that also performs an operation on the LValue. It can work with any operation by prefixing it to the =. For example, +=. In addition to that, there are special unary augmented assignment operators:

  • ++ increments the value, equivalent to x += 1.

  • -- decrements the value, equivalent to x -= 1.

  • !! logically negates a value. Equivalent to x = !x.

  • ~~ bitwise negates a value. Equivalent to x = ~x.

Operation


Operations can be unary (in which case it goes to the left of the operand), or take in one operand per side. The result of an operation is always an RValue. [name] implements the following operators:

SymbolOperationType
+AdditionArithmetic
-SubtractionArithmetic
*MultiplicationArithmetic
/DivisionArithmetic
%ModulusArithmetic
&Bitwise ANDBitwise
|Bitwise ORBitwise
^Bitwise XORBitwise
~Bitwise NOTBitwise
>>Right ShiftBitwise
<<Left ShiftBitwise
&&Logical ANDLogical
||Logical ORLogical
^^Logical XORLogical
!Logical NOTLogical

It also implements the following comparison operators:

SymbolOperation
==Equal
!=Not equal
>Greater than
<Lesser than
>=Greater or equal
<=Lesser or equal

Conditional operators


[name] implements my favourite operator, the ternary operator.

x ? a : b

if x is true, return a. otherwise, return b.

The second operand is optional, becoming an operator similar to the Elvis operator:

x ? a

if x is true, return x. otherwise, return a.

This is great because it does not evaluate the x operation twice if it is truthy.

[WIP] The result of both conditional operators is, sadly, an RValue. It does not pass references. [or does it? can i implement this? we'll see once the language is done]

Variables


Variable references are LValues. They are the prime example of an LValue. When they are passed to something that requires an RValue, they return their value as RValue.

Function references


Keep in mind, a reference to a function is an expression (an RValue, at that). Lambda functions, or just referencing a function by its identifier, always behave as pointers to the function in the data section.

Member operator


Members of a type (both attributes and methods) can be accessed with the following syntax (an expression that can be interpreted as a type is required beforehand):

.member

If the member is an attribute, it can behave as RValue or LValue depending on the input: if it was an RValue (or a constant variable) it will be an RValue, otherwise an LValue.

Subscription operator

The subscript operator is used to dereference an item from an array (a pointer). (Safe) syntactic sugar for *(&x + y), where x is the variable and y the index. An expression that can be interpreted as a pointer (NOT a function pointer) is required beforehand.

[index]

The behaviour rules are the same as the member operator.

Function call


Functions can be called with the following syntax:

name(parametersopt)

If a function is found with the correct name, all the overloads of the function with different parameters are searched to find:

  1. an overload with the same amount of parameters (required)
  2. the overload in which the parameters are the most similar, if there are multiple

Casting


Casting is similar to C casting:

(type)rvalue

Be aware of the order of operations, because I am not.