Introduction to Asa
Beginner Level
This topic is intended for beginner programmers.
Asa is a systems programming language built to be used in a similar fashion to C++, but be a good replacement. It aims to improve upon many of the shortcomings of that aging and bloated language, without sacrificing performance.
Hello World!
Builtin.* should get the printl function.See:
Comments
Comments in Asa follow the same rules as those in C/C++.
Single line comments begin with two forward slashes: //
Everything before the // is considered code, and everything after is considered a comment, until it reaches the end of the line:
Multi-line comments begin with /*, and end with */
Everything between /* and */ is considered a comment, including newlines. The comment only ends when it reaches the close symbol, */.
Due to how multi-line comments are parsed, this means that you can also place them within lines of code without issue:
Identifiers
Identifiers in Asa may contain any alphanumeric character or underscore, but must begin with an alphabetic character or underscore.
Builtin Operators
| Action | Symbol | Description | Example |
|---|---|---|---|
| Addition | ++= |
Adds two values together | 1 + 2 == 3;x += 2; |
| Subtraction | --= |
Subtracts one value from another | 5 - 3 == 2;x -= 2; |
| Negation | - |
Gives the opposite signed value | x = -3;-3 == 0-3; |
| Multiplication | **= |
Multiplies one value by another | 4 * 3 == 12;x *= 5; |
| Division | //= |
Divides one value by another | 12 / 3 == 4;x /= 2; |
| Modulo | %%= |
Gives the remainder after division | 5 % 3 == 2;x %= 2; |
| Left bit shift | <<<<= |
Shifts the bits of the value to the left by the given amount | 2 << 1 == 4;x <<= 3; |
| Right bit shift | >>>>= |
Shifts the bits of the value to the right by the given amount | 8 >> 1 == 4;x >>= 2; |
| Bitwise And | &&= |
Performs a logical bitwise AND on the bits of two values | 0b101 & 0b111 == 0b101;x &= 0b1001; |
| Bitwise Or | ||= |
Performs a logical bitwise OR on the bits of two values | 0b100 | 0b011 == 0b111;x |= 0b01; |
| Bitwise Xor | ^^= |
Performs a logical bitwise XOR on the bits of two values | 0b101 ^ 0b011 == 0b110;x ^= 0b01; |
| Bitwise Not | ~~= |
Performs a logical bitwise NOT on the bits of a value | ~0b011 == 0b100;x ~= 0b01; |
The Compile Time Define Operator
One of the operators you will be using most often in Asa is the compile time define. This is the double colon, ::.
It shares many of the characteristics of the set operator (=), and sometimes their functionality even overlaps.
Importantly, anything defined with this operator is immutable. This means that it cannot change during runtime. But, that does not mean it cannot be re-defined at compile time. In that way, it can somewhat also be compared to the #define preprocessor keyword from C or C++.
Compile time define is used to assign any expression to a name. A very basic example would be:
This code will evaluate the exact same as:
See type modifiers
Of course, more interesting expressions are better. Let's put a lambda expression on the right side:
Now this is a function.
Other uses
:: is used for defining other things as well, such as structs, modules, and special functions.
See:
Structs
You can create a struct by writing the name, and defining it as a struct expression:
Then to create an instance:
Struct Members
Member variables and functions are defined as normal. Functions, though, have slightly different behavior. For example:
The difference with functions defined inside of a struct is that they can only be called with the access operator (.), but they can also access members within the struct itself. To do this, you must use the this keyword, which references the instance the function is within. Then member access is as normal:
Struct Specific Functions
There are some functions that have specific names and functionality for handling structs.
create
Modules
You can define a module by writing the name, and defining it as a module expression:
Modules can have sub-modules to any depth:
Accessing
You can use the access operator . to use members of a module.
Accessing the variable x from outside moduleA would be done like so:
Expressions
In Asa, most things you write are "expressions". In other words, the individual components should be able to be evaluated all on their own. For example, take the following function:
Given the above function, we can split it into its sub-expressions:
The name:
functionNameand a lambda:
(){}
The lambda is simply an unnamed function. You can create one with parentheses containing the function arguments, followed by curly braces containing the body. Like:
If you want the lambda to have a return value, it should be preceded by the type. Like:
Now, neither of those pieces of code do anything. So giving that lambda expression a name with the compiler define operator :: lets you easily use it anywhere:
But the name someFunc is just an alias for the lambda expression. You could have evaluated it by just appending parenthesis to the end of the lambda itself and passing the arguments:
Special Function Definitions
Just like in C++, there are some special ways to define functions for certain use cases.
Operator Overloading
Operator overloading is used to override builtin behavior or add new behavior to existing or new symbols. For example:
Defining an operator overload is done with the following syntax:
operator(<symbol>) :: <return type>(<Left value>, <Right value>){
}The <symbol> can be any overloadable operator token. Examples: +, ==, [], or ... The compile time define :: and a few punctuation symbols cannot be overloaded. Also, the list of available symbols is predefined, so some combinations may be missing.
Strings
Strings are defined in the String module. They are simply an address to a null-terminated character array, and a length:
You can declare a string variable like any other struct:
And you can use string literals to create a string with a value:
A string literal is just any text surrounded by double quotes.
Formatted Strings
Like a regular string, formatted strings, or f-strings for short, are surrounded by quotes. But f-strings are also preceded by an f character:
They are not a different data type from string, rather they are just a different way to process string literals. They allow you to easily concatenate data with strings in a much shorter way.
For example, the following is a standard way to insert multiple pieces of data into a string:
This is a lot of code to do something so simple! So instead we can use an f-string:
The output is the same, but we no longer need to manually cast the values into strings, that is done automatically. Also, we do not need to manually concatenate multiple strings together using +. Just put the expression in between curly braces, like {5+3}, and it will be evaluated, casted to string, and concatenated in place.
F-strings do not give any performance benefit compared to its manual counterpart, as it is essentially expanding into the manual form under the hood.