Source files
The parts of an Antril source file - imports in all their forms, namespaces with into namespace, the global namespace, what goes at the top level, and the Main entry point.
On this page
A program or library is a set of .ant files compiled together. In a project, every .ant file under the project's folder is part of it (see Project files). The order of the files, and of the declarations in them, does not matter: a declaration can be used before the place where it is written.
The shape of a file
A file is a list of import directives followed by declarations:
import System;
import List from System;
into namespace Inventory
{
public class Item
{
public:
str Name;
new(str Name);
}
const i32 Limit = 3;
Count(List<Item> items) : i32 => items.Count;
}
Main()
{
List<Inventory.Item> items = new List<Inventory.Item>();
items.Add(new Inventory.Item("pen"));
Console.WriteLine(Inventory.Count(items) + " of " + Inventory.Limit);
}
All imports come first. After them, the top level of a file, and of a namespace block, holds:
- types: classes, values, records, interfaces, enums, exceptions and attributes (see Declarations);
- functions (see Functions);
- constants,
const T Name = value;; - extension blocks;
- nested
into namespaceblocks.
A namespace holds no variables: a field at the top level is error AN1103. Keep state in a type, for example a static class.
Namespaces
into namespace Name { … } puts its declarations into the namespace Name. A name can have several parts, and blocks can nest:
into namespace Geo.Shapes
{
const i32 Sides = 4;
}
into namespace Geo
{
into namespace Inner // Geo.Inner
{
Hello() : str => "inner";
}
Twice() : i32 => Shapes.Sides * 2; // Geo.Shapes.Sides, found from Geo
}
A namespace is open: the same namespace can be continued in any number of blocks, files and libraries.
Declarations outside any into namespace block are in the global namespace. They are found from everywhere without an import.
into namespace in a header
A type or a namespace-level function can name its namespace in its header, after its bases or its result type. It is the same as wrapping it in a block, and the name is relative to where the declaration is written:
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());
}
A member of a type stays in its type: into namespace on a method is error AN0039.
Imports
An import brings names into scope for the whole file.
| Form | What it brings |
|---|---|
import D; |
Every name of the namespace D. |
import D as X; |
The namespace under another name: X.Type, X.F(), X.Constant. The names of D are not brought one by one. |
import A, B, C from D; |
Only those names of D. |
import A, B, C from D as E, F, G; |
Those names, each under the alias in the same position: E is D.A. |
A name taken with from can be a type (its nested types come with it: E.Inner), a function, a constant, or a sub-namespace (import Shapes from Geo;, then Shapes.Sides). from is a word only inside an import.
import System.Text as T;
import Console, Math from System;
import List, Dictionary from System as L, D;
Main()
{
L<i32> values = new L<i32>();
values.Add(3);
Console.WriteLine(Math.Max(values[0], 2));
Console.WriteLine(T.JsonValue.Parse("[1,2]").ToString());
}
larva run
3
[1,2]
| Error | When |
|---|---|
| AN0034 | A list of names without from, or a different number of aliases and names. |
| AN1084 | The namespace does not exist, or has no such name. |
| AN1085 | The same name or alias is imported twice. |
Warning
Not yet available: importing a generic type by its number of type parameters (import List<> from System;, import KeyValuePair<,> from System;) and a family of variadic types (import Tuple<...> from System;). Import the name without <…>.
How a name is found
A name written in code is looked up:
- in the scope where it is written: locals, parameters, members of the enclosing types;
- in the enclosing namespace, then in its parent namespaces, up to the global namespace;
- among the names taken with
fromand the aliases of the file; - in the namespaces imported whole.
A name can always be written in full: System.Console.WriteLine("hi"), Geo.Shapes.Sides.
Main
A program starts at a free function called Main, in any namespace. There is exactly one per program; a second one is error AN1035. A library has none.
Main()
{
Console.WriteLine("hello");
}
Main can take integer, floating-point or bool parameters. Larva reads them from the command line, one per parameter:
import System;
Main(i32 width, i32 height)
{
Console.WriteLine(width * height);
}
larva build -o area.exe Program.ant
area.exe (llvm back end, O3, entry area::$Module.Main)
area 6 7
42
area
usage: C:\work\area.exe <arguments> (2 integer arguments)
A Main with no parameters accepts no arguments: started with some, the program prints the usage line and ends with exit code 2.
Main can also give a result: Main() : i32. Larva prints that result when the program ends, and the program's exit code stays 0.
Warning
Not yet available:
Main(str[] args)with the command-line arguments as text.Environment.GetCommandLineArgs()exists in System.Core, but an executable cannot be started with text arguments yet.- The result of
Main() : i32as the program's exit code: it is printed instead.
An exception that nothing catches ends the program with exit code 1 (see Exceptions).
Edit this page on GitHub Report an issue