Values and Expressions
All runtime "values" in Terbium are represented as expressions. An expression is
a syntactic construct, and it is a piece of code that can be evaluated to produce
a value. For example, the expression 1 + 2
1 + 2
evaluates to the value 3
3
.
There are many different kinds of expressions in Terbium, some including,
- literals, such as
1
1
and"hello"
"hello"
. These are expressions that evaluate to themselves. - variables, such as
x
x
andy
y
. These are expressions that evaluate to the value bound to the variable. - operators, such as
1 + 2
1 + 2
and-3
-3
. These are expressions that evaluate to the result of applying the operator to the operands. - groups, such as
(1 + 2)
(1 + 2)
and-(3)
-(3)
. These are expressions that evaluate to the value of the expression inside the group, and are used to control the order of evaluation.
We will take a closer look at each of these kinds of expressions.
Literals
A literal is an expression that evaluates to itself. For example, the expression
1
1
evaluates to the value 1
1
, and the expression "hello"
"hello"
evaluates
to the value "hello"
"hello"
.
Literals take many forms:
- integer literals, such as
1
1
and2
2
. - floating-point literals, such as
1.0
1.0
and2.0
2.0
. - character literals, such as
c'a'
c'a'
. - string literals, such as
"hello"
"hello"
and"world"
"world"
. - boolean literals, such as
true
true
andfalse
false
. - void, the unit value, evaluating to
void
void
. This is the value of an expression that does not evaluate to anything.
Integer literals
An integer literal can be written as a sequence of digits, optionally suffixed
with u
to indicate that the integer is unsigned. We will see more about
unsigned integers later.
Optionally, an integer literal can be prefixed with radix modifiers:
0b
or0B
for binary,0o
or0O
for octal, and0x
or0X
for hexadecimal.
For example, 0b101
0b101
is the same as 5
5
, and 0xff
0xff
is the same as
255
255
.
Additionally, underscores may be used to separate digits in an integer literal,
for example, 1_000_000
1_000_000
is the same as 1000000
1000000
.
Floating-point literals
A floating-point literal evaluates to a floating-point number. A floating-point
number is a number with a fractional part, such as 1.5
1.5
or 3.14
3.14
.
A floating-point literal can have underscores to separate digits, for example,
1_000.000_001
1_000.000_001
is the same as 1000.000001
1000.000001
.
You can also use e
or E
to indicate scientific notation, for example,
1e6
1e6
is the same as 1000000
1000000
, and 1.5e-3
1.5e-3
is the same as
0.0015
0.0015
.
Character literals
A character literal evaluates to a character. A character literal is written
as a one-character string prefixed with c
, for example c'A'
c'A'
or c'\n'
c'\n'
.
We will see more about characters later.
String literals
A string literal evaluates to a string. A string literal is written as a
sequence of characters surrounded by single or double quotes, for example "hello"
"hello"
Strings can span multiple lines:
"this string
spans multiple lines"
Escape sequences
Strings can also contain escape sequences:
Sequence | Description |
---|---|
\n | Newline |
\r | Carriage Return |
\t | Tab |
\b | Backspace |
\f | Form Feed |
\\ | Literal backslash |
\' | Literal ' |
\" | Literal " |
\0 [1] | Null byte |
\x12 [2] | Character by hex codepoint (2 digits) |
\u1234 [2] | Character by hex codepoint (4 digits) |
\U12345678 [2] | Character by hex codepoint (8 digits) |
[1] Because strings will always have an encoding, null-bytes can only be placed in byte-string literals.
[2] Numbers are a placeholder of a valid hex value of the specified length, e.g. \u200b
'Here\'s a contraction with apostrophes'
"This is a \"quote\" with quotation marks"
'This string has\nnewlines'
'An em dash: \u2014'
Raw strings
Strings can also be raw, which means that escape sequences are not interpreted.
A raw string is written as a string prefixed with ~
, for example ~"hello \n world"
~"hello \n world"
is the same as "hello \\n world"
"hello \\n world"
.
Quote-escaped strings
A cleaner way to escape quotes is to use quote-escaped strings. A quote-escaped
string is written by prefixing the string with any N number of pound symbols (#
), and then
suffixing the string with the same number of pound symbols.
For example, #"hello "world""#
#"hello "world""#
is the same as "hello \"world\""
"hello \"world\""
,
and ###"hello #"world"#"###
###"hello #"world"#"###
is the same as "hello #\"world\""
"hello #\"world\""
.
Interpolated strings
Strings can also be interpolated, which means that expressions can be evaluated
inside the string. An interpolated string is written as a string prefixed with
$
, any then any interpolated expressions are surrounded by {
and }
.
Use {{
and }}
to escape the braces.
For example, $"1 + 2 = {1 + 2}"
$"1 + 2 = {1 + 2}"
is the same as "1 + 2 = 3"
"1 + 2 = 3"
. The internals
of string interpolation are explained later.
Boolean literals
A boolean literal evaluates to a boolean value. A boolean represents a truth
value, and can be either true
true
or false
false
.
Void
Void is the unit value, and is written as void
void
. Void is the value of an
expression that does not evaluate to anything, and it should not be commonly used.
Operators and Arithmetic
An operator is an expression that evaluates to the result of applying the
operator to the operands. For example, 1 + 2
1 + 2
evaluates to 3
3
, and
-3
-3
evaluates to -3
-3
.
Operators can be unary, binary, or ternary.
Unary operators
A unary operator is an operator that takes one operand. For example, -3
-3
is a unary operator, because it takes one operand, 3
3
.
There are two types of unary operators: prefix and postfix. A prefix unary
operator is written before the operand, for example -3
-3
. A postfix unary
operator is written after the operand. There are no postfix unary operators in
Terbium.
The following are the unary operators in Terbium:
Operator | Description |
---|---|
- | Negation |
! | Logical not |
~ | Bitwise not |
Binary operators
A binary operator is an operator that takes two operands. For example,
1 + 2
1 + 2
is a binary operator, because it takes two operands, 1
1
and
2
2
. All binary operators in Terbium are infix, which means that they are
written between the operands.
The following are the binary operators in Terbium:
Operator | Description |
---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
% | Modulo |
** | Exponentiation |
& | Bitwise and |
| | Bitwise or |
^ | Bitwise xor |
<< | Bitwise left shift |
>> | Bitwise right shift |
&& | Logical and |
|| | Logical or |
== | Equality |
!= | Inequality |
< | Less than |
<= | Less than or equal to |
> | Greater than |
>= | Greater than or equal to |
.. | Range |
..= | Inclusive range |
There are also keyword operators, which are operators that are written as keywords. The following are the keyword operators in Terbium:
Operator | Description |
---|---|
is is | Type equality |
in in | Contains |
to to | Type-cast |
Comparison operators
Comparison operators are a subset of binary operators that compare two values, always returning a boolean value
(true
true
or false
false
). They are ==
==
, !=
!=
, <
<
, <=
<=
, >
>
, >=
>=
, is
is
and in
in
.
is
is
and in
in
have negated counterparts, !is
!is
and !in
!in
respectively.
a !is b
a !is b
is the same as !(a is b)
!(a is b)
and a !in b
a !in b
is the same as !(a in b)
!(a in b)
.
Comparison operators can be chained together to compare multiple values.
For example, 1 < x != 10
1 < x != 10
is the same as writing 1 < x && x != 10
1 < x && x != 10
.
Generally, if a
a
, b
b
, c
c
... z
z
are expressions and op1
, op2
, op3
... opN
are
comparison operators, then a op1 b op2 c op3 d ... opN z
a op1 b op2 c op3 d ... opN z
is the same as writing
a op1 b && b op2 c && c op3 d && ... && y opN z
a op1 b && b op2 c && c op3 d && ... && y opN z
.
Ternary operators
A ternary operator is an operator that takes three operands. The ternary if
or inline if operator is the only ternary operator in Terbium. It is written
as if CONDITION then THEN_VALUE else ELSE_VALUE
if CONDITION then THEN_VALUE else ELSE_VALUE
.
For example, if 1 > 2 then "yes" else "no"
if 1 > 2 then "yes" else "no"
evaluates to "no"
"no"
. Ternary operators desugar to standard
if-statements, which are explained in the Control Flow section.
Grouping (Parentheses)
Similar in mathematics, parentheses can be used to group expressions so that they are
evaluated first. For example, (1 + 2) * 3
(1 + 2) * 3
evaluates to 9
9
.