Compiler Directives
In Asa, there are a number of directives for modifying the behavior of the compiler during compilation. These all start with the character #. Any compiler directive is an expression that will be evaluated at compile time.
#import
One of the most used directives, used for importing modules by name. For example:
#import Rendering.Window; #import Rendering.Drawing.Line;
This imports the module Window in the directory modules/Rendering. The module expression can be more complex, for example sub-directories: #import A.B.C.ModuleName;, which would be in modules/A/B/C. You can also wildcard import modules by using the base path followed by an asterisk: #import Builtin.*;, which would import all modules of all files in the directory modules/Builtin/.
#import looks in multiple locations for the specified module. First, it looks in the local directory from where it is called. If there is a matching module (including all path components), then it will stop there. If it does not find a matching module locally, it will look in the global modules folder, which is installed next to the asa executable. This allows you to override builtin modules for specific use cases.
#embed
This is similar to #import, but instead of only including a single module, it loads the entire file. Also, it does so by an explicit path. For example:
#embed "./otherFile.asa";
This would compile and import the entire other file at the given path. The path is evaluated relative to the file which #embed is in.
#library
Used to specify the name of a library to link against. For example:
#library "ssl";
This would link against libssl. It is equivalent to passing -lssl with --clangoptions.
#library_static
Used to specify the name of a library to statically link against. For example:
#library_static "/path/to/libssl.a";
This would link against libssl. It is equivalent to passing /path/to/libssl.a with --clangoptions.
#linenum
Gets the line number as an integer of its own location in the source code file. For example:
// some line print(#linenum); // Prints 4
#linecol
Gets the line column as an integer of its own location in the source code file. For example:
print(#linecol); // Prints 6
#line
Gets the line contents as a string at its own location in the source code file. For example:
print(#line);
The above prints print(#line);. (Putting this in a comment would be recursive.)
#filepath
Gets the full path of the source code file as a string. For example:
// In a file at /home/user/main.asa print(#filepath);
The above would print /home/user/main.asa.
#funcname
Gets the name of the function it is in as a string. For example:
someFunc :: int(){ print(#funcname); ... }
The above would print someFunc.
#modulename
Gets the name of the immediate module it is in as a string. For example:
moduleA :: module{ print(#modulename); }
The above would print moduleA. But in the case of nested modules like so:
moduleA :: module{ moduleB :: module{ print(#modulename); } }
The above would print moduleB.
#asaversion
Gets the version of the Asa compiler as a string as it was when compiled. For example:
print(#asaversion);
The above would print the current version string of the asa compiler.
#counter
Acts as an automatically incrementing integer. For example:
print(#counter); // Prints 0 print(#counter); // Prints 1 print(#counter); // Prints 2
#nameof(I)
Gets the name of an identifier as a string. For example:
someVar : int = 0; print(#nameof(someVar));
The above would print the string someVar.
#typeof(T)
Gets the type name of an identifier or type as a string. For example:
someVar : int = 0; print(#typeof(someVar)); // Would print `int` print(#typeof(string)); // Would print `string`
#sizeof(T)
Gets the size in bytes of an identifier or type as an integer. For example:
someVar : int = 0; print(#sizeof(someVar)); // Would print `4` print(#sizeof(int8)); // Would print `1`
#extern
This is a method to reference external functions from libraries. For example:
#extern printf :: int32 (s : const *char, ...);
The above would allow you to use the printf function from the C standard library. #extern use is simply stating the function name and parameters as they are defined, and not including a body.
#compiles(expression)
Checks at compile time if expression will compile successfully, or cause a compiler error. Returns true if it compiled without error, and false if it failed. The error message is thrown out, and never printed to stdout or stderr.
printl(#compiles(1 + 1)); // Prints `true` printl(#compiles(undefinedVariable + 1)); // Prints `false`
#variant
This is a function modifier that creates variants of the function. For example:
foo :: () #variant w = 0; { printl(w); }
Then you can use it like so:
foo<w=7>(); // -> 7 foo<w=2>(); // -> 2
This looks like arguments with extra steps, but the main difference is that it permanently creates a completely different function for each combination during the compilation process. So the above would have equivalent code to:
foo :: (){ printl(7); } foo :: (){ printl(2); }
This is useful if you want to allow for a function to work with multiple types:
foo :: T(v : T) #variant T = int; { return v * 2; }