Basics
Files, namespaces, Main, comments, variables, primitive types, literals, operators, control flow and strings in Antril.
On this page
This page covers what every Antril file uses. Here is a whole program to start with:
import System;
into namespace Tour
{
/// Sums the numbers below `limit` that are multiples of 3 or 5.
SumOfMultiples(i32 limit) : i32
{
i32 total = 0;
loop (i32 n = 1..limit)
{
if (n % 3 == 0 || n % 5 == 0)
total += n;
}
return total;
}
Main()
{
i32 result = SumOfMultiples(10);
Console.WriteLine($"The sum is {result}");
}
}
larva run
The sum is 23
Files and namespaces
An .ant file is a list of imports followed by declarations: types, functions and constants.
into namespace Name { … } puts declarations into a namespace. The same namespace can be opened in many files and libraries. Declarations outside any into namespace block are in the global namespace.
import brings names into scope for the whole file:
| Form | What it brings |
|---|---|
import System; |
Every public name of System. |
import List, Dictionary from System; |
Only those names. |
import System.Text as T; |
The namespace under another name: T.JsonValue. |
import A, B from D as X, Y; |
Those names, each with the alias in its position. |
A name can always be written in full instead: System.Console.WriteLine("hi").
A type or a function can also name its namespace in its header, relative to where it is written. This is the same as wrapping it in an into namespace block:
import System;
public class Shape into namespace Geo
{
public:
static Sides() : i32 => 4;
}
Area(f64 side) : f64 into namespace Geo => side * side;
Main()
{
Console.WriteLine(Geo.Area(3) + Geo.Shape.Sides());
}
Main
A program starts at a free function called Main. There is exactly one per program.
Main()
{
Console.WriteLine("hello");
}
Main can also be declared with an integer result, Main() : i32: Larva prints that result when the program ends. Main can take numbers from the command line, but not text yet; see Source files.
Comments
// To the end of the line.
/* Across
several lines. */
/// A documentation comment: it describes the declaration below it.
/// The editor shows it on hover, and `larva show` prints it.
Area(f64 w, f64 h) : f64 => w * h;
Variables and constants
A variable is declared with its type first. Several variables of one type can share a declaration.
i32 count = 0;
str name = "Antril";
i32 width = 4, height = 3;
A variable of a value type (numbers, bool, value types) that is not assigned starts at zero.
const declares a constant. Its value is computed when the program compiles, and it can be declared in a namespace, in a type, or inside a body.
import System;
into namespace Config
{
const i32 Retries = 3;
const str Name = "server";
const str Label = Name + "-" + "main";
const i64 Big = Int32.MaxValue + 1i64;
Main()
{
const f64 Half = 0.5;
Console.WriteLine(Label);
Console.WriteLine(Big);
Console.WriteLine(Retries * Half);
}
}
larva run
server-main
2147483648
1.5
nameof(x) gives the name of a variable, member, type or function as a constant string: nameof(count) is "count", and nameof(i32) is "Int32".
Primitive types
| Type | What it is |
|---|---|
bool |
true or false. |
i8 i16 i32 i64 i128 i256 |
Signed integers of 8 to 256 bits. |
u8 u16 u32 u64 u128 u256 |
Unsigned integers of 8 to 256 bits. |
f16 f32 f64 f128 f256 |
IEEE floating-point numbers of 16 to 256 bits. |
iptr uptr |
Integers the size of a pointer. |
str |
Text: a System.String. |
any |
Any value: the root of every class (System.Any). A value stored in any is boxed. |
void |
No value: what a function without a result returns. |
Each primitive is a type of the standard library (i32 is System.Int32, f64 is System.Float64), with members such as Int32.MaxValue, Int32.Parse(text) and ToString().
Antril has no separate character type. A character literal like 'A' is its code point, a number: a u16 when nothing else is expected. System.Char has functions on code points, such as Char.IsDigit('7').
Literals
import System;
Main()
{
i32 count = 42;
i64 big = 9_000_000_000;
u8 small = 255u8;
f32 ratio = 0.5f32;
f64 pi = 3.14159;
i32 mask = 0xFF;
i32 bits = 0b1010;
u128 huge = 340282366920938463463374607431768211455u128;
u16 letter = 'A';
bool ready = true;
str name = "Antril\n";
Console.WriteLine(count + mask + bits);
Console.WriteLine(big);
Console.WriteLine(huge);
Console.WriteLine(letter);
Console.Write(name);
}
larva run
307
9000000000
340282366920938463463374607431768211455
65
Antril
- An integer literal is an
i32, or ani64if it does not fit. A literal with a decimal point is anf64. Where a type is expected, a literal takes that type. - A suffix names the type:
255u8,1i64,0.5f32,3f128. 0xstarts a hexadecimal number and0ba binary one._separates digits.- Strings use
\n,\t,\"and\\escapes. nullis the empty value of a nullable type (see Types).
Conversions
Conversions that cannot lose information are implicit: an integer to a wider one of the same sign, an unsigned integer to a wider signed one, an integer to a float, f32 to f64. Everything else needs a cast:
i64 wide = 5; // implicit
i32 narrow = (i32)wide; // a cast
i8 truncated = (i8)200; // -56: a cast keeps the low bits
i32 whole = (i32)3.9; // 3
Operators
| Kind | Operators |
|---|---|
| Arithmetic | + - * / %, and -x |
| Comparison | == != < <= > >= |
| Logical | && || ! |
| Bitwise | & | ^ ~ << >> |
| Assignment | = += -= *= /= %= &= |= ^= <<= >>= |
| Increment | ++ -- (before or after the variable) |
| Conditional | c ? a : b |
| Null | a ?? b (a unless it is null), a?.b (null if a is null) |
| Types | x is T, x is T name, x as T |
| Ranges | a..b (excludes b), a..=b (includes b) |
+ joins strings, and turns a number or an object on the other side into text: "n = " + 5 is "n = 5". == on strings compares their content.
Types can declare their own operators; see Functions and generics.
Control flow
if
if (temperature > 30)
Console.WriteLine("hot");
else if (temperature > 15)
Console.WriteLine("mild");
else
Console.WriteLine("cold");
Braces are needed only for more than one statement.
loop
Antril has one keyword for every kind of loop:
| Form | What it does |
|---|---|
loop (T x in items) { … } |
Each element of an array, a string or a collection. |
loop (condition) { … } |
While the condition holds. loop (true) runs until a break. |
do { … } loop (condition); |
Runs once, then while the condition holds. |
loop (i32 i = 0..10) { … } |
i from 0 to 9. 0..=10 includes 10. |
loop (i32 i = 0; i < 10; i += 2) { … } |
Start, condition, step. |
loop (i32 i = 1) { … } |
Without end: i starts at 1 and goes up by one each time. |
break leaves the loop and continue goes to the next turn.
import System;
Main()
{
loop (i32 i = 0..3)
Console.Write(i);
Console.WriteLine();
loop (i32 k = 0; k < 10; k += 3)
Console.Write(k);
Console.WriteLine();
i32 n = 1;
loop (n < 100)
n *= 3;
Console.WriteLine(n);
do n -= 50; loop (n > 0);
Console.WriteLine(n);
loop (i32 c = 1)
{
if (c > 3)
break;
Console.Write(c);
}
Console.WriteLine();
loop (str word in ["alpha", "beta"])
Console.WriteLine(word.ToUpper());
}
larva run
012
0369
243
-7
123
ALPHA
BETA
switch
switch matches a value against patterns, as a statement or as an expression. _ matches anything.
import System;
Describe(i32 n) : str => n switch
{
< 0 => "negative",
0 => "zero",
1..10 => "small",
_ => "large",
};
Main()
{
i32 count = 2;
switch (count)
{
0 => Console.WriteLine("none");
1 or 2 => Console.WriteLine("a few");
_ => Console.WriteLine("many");
}
Console.WriteLine(Describe(-3) + ", " + Describe(5) + ", " + Describe(50));
}
larva run
a few
negative, small, large
Patterns can be:
- constants:
0,"abc",Color.Red; - comparisons:
< 0,>= 90; - ranges:
1..10,1..=9; - combinations with
and,orandnot; - types, with an optional name:
Circle c; - properties:
{ X: 0, Y: > 1 }; - positions, for records, tuples and types with
Deconstruct:Point(0, var y),(1, _); null.
A when condition after a pattern adds a check: Circle c when c.Radius > 10 => …. The same patterns work after is: if (p is { X: 0 }).
Strings
str is immutable text. Some of its members:
str s = " Hello World ".Trim();
s.Length; // 11
s.ToUpper(); // "HELLO WORLD"
s.Substring(6, 5); // "World"
s.IndexOf("World"); // 6
s.StartsWith("Hell"); // true
s.Replace("World", "you"); // "Hello you"
"a,b,c".Split(','); // a List<str>
String.Join("-", parts); // joins a list
An interpolated string starts with $. Each {…} holds an expression, with an optional width after , (negative: aligned left) and a format after ::
import System;
Main()
{
f64 price = 3.5;
i32 quantity = 4;
Console.WriteLine($"{quantity} x {price} = {price * quantity}");
Console.WriteLine($"[{quantity,5}] [{quantity,-5}] [{price:F2}]");
}
larva run
4 x 3.5 = 14
[ 4] [4 ] [3.50]
To build long text piece by piece, use StringBuilder (see the library overview).
Printing
Console.WriteLine writes a value and a new line; Console.Write writes without the new line. Both take every primitive type, strings, and any other value (shown with its ToString()). Console.ReadLine() reads a line, or gives null at the end of the input.
Because a character literal is a number, Console.Write('A') writes 65. Write "A" for text.
Next: Types.
Edit this page on GitHub Report an issue