This page covers advanced Jai language constructs and topics such as polymorphism, inline assembly, and context are covered under the advanced section. This section assumes you already understand the basic language constructs covered in the `Getting Started` section.

If you want to get in at the deep end, there are excellent and far more detailed guides in the how_to/ directory that comes with the Jai compiler, as well as documentation for individual modules in the respective locations under modules/ and some advanced examples under examples/.

Jai supports operator overloading. Operators that can be overloaded include: `+`, `-`, `*`, `/`, `==`, `!=`, `<<`, `>>`, `&`, `|`, `[]`, `%`, `^`, `<<<`, `>>>`. Operator overloading should be used conservatively, limited only to mathematical operations.

Given a `Vector3` datatype, you can define an `operator +` for it. Defining `operator +` automatically defines `operator +=` and vice versa.

``````Vector3 :: struct { x: float; y: float; z: float;} // Vector3 of {x,y,z}

operator + :: (a: Vector3, b: Vector3)->Vector3 {
c: Vector3;
c.x = a.x + b.x;
c.y = a.y + b.y;
c.z = a.z + b.z;
return c;
}

a := Vector3.{1.0, 2.0, 3.0};
b := Vector3.{3.0, 4.0, 2.5};
c := a + b;
c += a;
``````

Adding the keyword `#symmetric` to any two parameter function causes the order of two parameters to be irrelevant. We can define `operator *` on a `Vector3` to mean scalar multiplication:

``````operator *:: (a: Vector3, b: float)->Vector3 #symmetric {
b: Vector3;
b.x = a.x * b;
b.y = a.y * b;
b.z = a.z * b;
return b;
}

a := Vector3.{3.0, 4.0, 5.0};
c := a * 3;
c  = 3 * a;
``````

As the example above shows, the `#symmetric` keyword allows someone to create a `Vector3` with an `operator *` that can perform both `a * 3` and `3 * a`.

Here is an example of using `operator []`. The `operator []` is a read-only operator overload, i.e. only `b := object[index]` is supported, but `object[index] = b` does not exist. There is no `operator []=`.

``````Obj :: struct {
array: [10] int;
}

operator [] :: (obj: Obj, i: int) -> int {
return obj.array[i];
}

o : Obj;
print("o[0] = %\n", o[0]);
``````

Here is an example of using `operator *=`.

``````operator *= :: (obj: *Obj, scalar: int) {
for *a : obj.array
<<a *= scalar;
}

o : Obj;
o *= 100;
``````

### Operators that you can NOT overload

`operator =` can not be overloaded. Although you can overload `+=`, `-=`, `*=`, etc., you cannot overload `operator =`. Overloading `operator =` can cause a lot of confusion in which one may think one is just assigning a variable, but is accidentally calling `operator =`, causing a massive slowdown in the code.

`operator new` can not be overloaded. `New` in Jai is a regular function call, not a keyword built into the language. You can change the context of the `New` function, and that is the way you can change the allocator.

## Polymorphism

Polymorphism is used to define functions and `struct`s that require at compile-time known types `T` via `\$T`.

The dollar-sign before the type-parameter `\$T` indicates that this type has to be derived by the compiler and therefore all required type information has to be known at compile time.

### Polymorphic type declarations

There are (at least) three major ways of defining polymorphic types. As we already saw, we can define the type of a variable via e.g. `x : int;`. Here, the compiler knows the type at compiletime, since it's explicitely written out.

If we accept any (compile-time) type, we can use the dollar sign, e.g.

``````x : \$T
``````

In this case, any type is matched to `T`, that includes any `struct`, `int`, `bool`, `Any`, etc. There is no restriction on the possible types used. On the one hand, this enables us to write truly generic functions, on the other hand, we expect the programmers to know, what they're using `x` for - and in case they don't, the compiler will complain or the program will crash.

We can be more precise than that. Assuming we have polymorphic structs (see below), e.g. `Foo(T: Type)`, we can restrict the type of `x` by only allowing `Foo`s:

``````x : Foo(\$T)
``````

In this case, the inner type `T` still could be anything, but at least we know that `x` is some kind of `Foo`. This declaration can be nested, e.g.

``````x : Foo(Bar(\$T, Sth(\$C, \$D)), \$U)
``````

Sometimes, however, this way of restricting the type of `x` is too strict. It is possible to require members of `x` similar to traits or interfaces in other languages via the `/` notation:

``````x : \$T/Foo
``````

Here, we know that `x` has the fields of `Foo` and we can treat it as such. This does not mean `x` is a `Foo`! It can simply incorporate a `Foo` via e.g. `using f: Foo;`. This enables also component bases systems where each struct via `using _c: SomeComponent;`

In all of these cases, it is possible to re-use the polymorphic types, e.g. `T`, once the compiler could figure what they were. Examples of that are further below.

There are also other ways of defining the types, e.g. `\$T/interface Foo` that will be explained further below.

### Functions

Let's take a look at a simple function:

``````foo :: (x: \$T) {
print("%\n", x);
}
``````

At this point, we don't know the type of `x`, but we name it `T` and it has to be known at compile time! We can use it like this:

``````x := 42; // T == int
y := "hello"; // T == string

foo(x); // knows it's an int
foo(y); // knows it's a string
``````

Of course, functions can have multiple polymorphic variables

``````foo :: (a: \$A, b: \$B, c: \$C) {...}
``````

You can use the same type for multiple parameters and return values, just use the identifier for the type.

``````foo :: (a: \$T, b: T, c: T) -> T {...}
``````

Polymorphic return parameter: We already know, that we can reuse the polymorphic type definition for the return type of a function, see the example above. However, in some cases, the return parameter depends on the argument parameter types

``````foo :: (a: \$A, b: \$B) -> [some function determining the type depending on A and B] {...}
``````

One way of doing this is `#modify` which will be explained further down below. Unfortunately, this method is cumbersome since it does not work directly with the types `A` and `B`, but the AST representation of the parameters.

Another way of achieving this functionality, is with helper-structs: We can define

``````Helper :: struct(A: Type, B: Type) {
T :: #run helper(A,B);
}
helper :: (\$A: Type, \$B: Type) -> Type {
T : Type = A; // do your logic here
return T;
}
``````

The `helper` function actually does the logic and returns the wanted return type depending on the input types. It is run at compile-time via the `#run` instruction. To use the return type, we now define our original function `foo` as

``````foo :: (a: \$A, b: \$B) -> Helper(A,B).T {...}
``````

The `Helper` struct can be used anywhere to define the type of a variable, e.g. in `foo`

``````x : Helper(A,B).T;
``````

### Structs

Similar to function, polymorphic structs are also possible! In this case, you need to introduce the polymorphic type `\$T` after the `struct` keyword for compile-time constants:

``````Foo :: struct(x: \$T) {...}
``````

This way, the type of `x` has to be known at compile time:

``````a : Foo(42); // ok, 42 is a constant
x := 2;
// b : Foo(x); // not ok, x is not a constant value!
y :: 2;
b : Foo(y); // ok, y is a constant value
``````

If you want to define a struct that has a polymorphic type for it's members, you can use the type `Type` to define it during compile-time

``````Foo :: struct(T: Type) {
some_data : T;
}
``````

When using this struct, you have to declare the type

``````f : Foo(int);
``````

Continuing the example above, you can access the type parameter of `Foo` through `Foo.T`.

``````f: Foo(int);
print("type = %\n", f.T); // prints out "type = int"
``````

The polymorphic struct do not only restrict to data types, but they can also extend to functions:

``````Foo :: struct(
// everything here has to be known at compile time
// these entries will be baked out and do not remain part of the struct in memory during run-time!

T: Type,
fun: (T) -> T
// ...
) {
// everything here can be chaged
// (as long as it's not a constant via :: ) at run-time
// and stays in memory

value: T;
// ...
}
``````

Further, it is possible to define recursive types, e.g.

``````Foo :: struct(
T: Type,
fun: (T) -> int
){}

Bar :: struct(_T: Type) {
using f: Foo(Bar(_T), bar_fun)
}
bar_fun :: (b: Bar(\$T)) -> int {
return 42;
}
``````

Do not attempt to print the type: (`beta 0.0.083`)

``````T :: Bar(int);   // the compiler resolves the type just fine
print("%\n", T); // this will go into an infinite loop at run-time
``````

### Arrays

It is possible to use polymorphic arrays int both size `N` and element-type `T`, e.g.

``````foo :: (x: [\$N]\$T) {
print("%: %, %\n", type_of(N), N, T);
}
``````

Here, both `N` and `T` have to be known at compile time. `N` refers to the number of elements and is itself of type `int`! Using the above definition of `foo`, we'd get in this example

``````x := int.[1,2,3,4];
foo(x); // prints "s64: 4, s64"
``````

It is important to know, that arrays of different sizes are different types! So

``````[4]int != [5]int
``````

### Type Comparison

We can compare types with the equals operator `==`:

``````x : float64 = 0.1;
assert(type_of(x) == float64);

n := 42;
assert(type_of(n) == int);

Foo :: struct {}
f : Foo;
assert(type_of(f) == Foo);
``````

However, when using polymorphic structs, e.g.

``````Bar :: struct(T: Type) {
value: T;
}
``````

we can only compare specializations of said type, in this case

``````b : Bar(int);
assert(type_of(b) == Bar(int));
assert(b.T == int);
``````

It is not possible to compare without specialization:

``````b : Bar(int);
assert(type_of(b) == Bar); // this does not work!
``````

even though

``````print("%\n", type_of(b)); // prints "Bar".
``````

### `\$T/Object` syntax

`\$T/Object` indicates that the `\$T` must be a parameterized struct of the type `Object`. This saves time so that one does not have to type out all the parameters of a parameterized struct. Consider the following example:

``````Hash_Table :: struct (K: Type, V: Type, N: int) {
keys: [N] K;
values: [N] V;
}

function1 :: (table: Hash_Table(\$K, \$V, \$N), key: K, value: V) {
// do stuff
}

function2 :: (table: \$T/Hash_Table, key: T.K, value: T.V) {
// do stuff
}

function3 :: (table: \$T, key: T.K, value: T.V) {
// do stuff
}

``````

All the following ways are correct ways to write functions with parameterized structs. `function1` is slightly more verbose and utilizes pattern matching to specify the type, while `function2` is less verbose but still specifies that the `\$T` must be a Hash_Table. `function3` is the most generic, least verbose, but loses a lot of useful type information. Use whatever way fits ones own programming style.

### Implicit Polymorphism

This is another way of writing `\$T/Object`, called implicit polymorphism. In this example, `Table` is being called directly.

``````function4 :: (table: Table, key: table.K, value: table.V) {
// do stuff
}
``````

### `\$T/interface Object` syntax

`\$T/interface Object` indicates that the `\$T` must have the fields that `Object` has. The changelog has this to say:

New experimental feature: keyword 'interface' for use with polymorphism. Accepts only types that contain members declared in the target struct. Basically, this does duck typing in a straightforward simple way. See uses of the keyword 'interface' in modules/Math/module.jai and modules/Math/matrix.jai.

### `#modify` directive

The `#modify` compiler directive lets one put a block of code that is executed at compile-time each time a call to that procedure is resolved. The `#modify` directive allows one to inspect parameter types at compile-time.

Here is an example for how to use `#modify`.

``````function :: (x: \$T)
#modify {
using Type_Info_Tag;
if T.type != INTEGER {
print("\$T must be an integer!\n");
T = null;
}
}
{  // rest of the function

}
``````

In the example above, setting `T = null` tells the compiler that `\$T` must be an integer type or it will be a compile-time error.

## Context

Jai has a first class concept of context, which is always present and accessible, but beyond being a simple global state variable, a new context can be "pushed", changing the operational context for a duration. But before we get into that, let's look at what a context provides.

In most languages, various system-level services such as memory allocations or logging are done via some common library function. For example, in C, you allocate memory using the `malloc` function. If you want to create your own custom allocator, it has to have a different name and will only be used when explicitly called. This means that libraries that you call out to won't know to use your clever custom allocator. Same is true of other features, like loggers, or what have you. Sometimes this will make you sad because a pesky library is messing up your heap or is slinging undesirable commentary at your terminal.

In Jai, the context is there to guide different parts of your program to use whatever services you desire. The default context comes with good defaults, but you can change them as needed. Among these are the allocator, the temporary allocator, the logger, the assertion failure callback, formatting options for `print`, runtime error logging options, and so on. You can also access your current thread index through the context. But wait, there's more: if for whatever reason it makes sense for your program to have additional context, you can add it yourself!

### `push_context`

Example:

``````my_context: Context;
push_context my_context {
// Do stuff here with this context.
}
``````

TODO.

### `#add_context`

If you want to add something to your context, you use the `#add_context` compiler directive, like so:

``````#add_context this_is_the_way := true;
``````

## Modules

TODO.

### External libraries

Mapping a dynamic library (.dll / .so) is a fairly simple process: you specify the library file, and then provide signatures for the procedures you want to use.

For example:

``````lz4 :: #foreign_library "liblz4";

LZ4_compressBound :: (inputSize: s32) -> s32 #foreign lz4;
LZ4_compress_fast :: (source: *u8, dest: *u8, sourceSize: s32, maxDestSize: s32, acceleration: s32) -> s32 #foreign lz4;
LZ4_sizeofState :: () -> s32 #foreign lz4;
``````
• We can specify a path to the library inside the double-quotes, but You MUST copy the .dll next to the .exe, or it will not work!
• Instead of linking to a local library file, you can link to a system library (built into the OS) with `#foreign_system_library`, e.g. `d3d11 :: #foreign_system_library "d3d11";`

Your procedure name does not need to exactly match the name in the library: you can rename it if you wish. If you do, then add the original name in quotes at the end:

``````compress_bound :: (inputSize: s32) -> s32 #foreign lz4 "LZ4_compressBound";
compress_fast :: (source: *u8, dest: *u8, sourceSize: s32, maxDestSize: s32, acceleration: s32) -> s32 #foreign lz4 "LZ4_compress_fast";
size_of_state :: () -> s32 #foreign lz4 "LZ4_sizeofState";
``````

If you are converting a C `.h` file then some familiarity with C is obviously required, but it can more-or-less be translated mechanically: put in the `::`, move the return type to the end and add the `#foreign <lib>` declaration, and flip the parameter types/names. Things to be aware of:

• A pointer to `char` becomes a pointer to `u8`
• Elide extraneous prefixes (i.e. `const` before parameters, macros, etc.)
• References become pointers (i.e. `&` becomes `*`)
• You should almost always specify a 32-bit size for an `enum`, i.e. `IL_Result :: enum s32 {`, or `D3DCOMPILE_FLAGS :: enum_flags u32 {`.
• The size of `int` and `float` may be hard to discern; if you can't work it out from the code, comments or documentation then go for 32-bit versions; if your data comes out mangled you can re-apprise.
• Rename any parameter which happens to coincide with a Jai keyword. `context` -> `ctx` is common, for instance.

Once you have the code compiling and your program running, you need to check the data that's being passed back and forth from the library: incorrect values will likely indicate incorrectly sized struct members, variables, constants, or parameters. Be especially observant of the types mentioned above.

#### Callbacks

We use two keywords to specify callback types: `#type` and `#c_call`. `#type` lets us specify the expected parameters of the callback (rather than just using a `*void`), and `#c_call` tells the compiler to use the C ABI.

• We need to specify a `void` return type if that's the case.
• When we write an actual callback procedure to use with our definition, we need to push a new context inside it.

For example:

``````IL_Logger_Callback :: #type(level: IL_LoggingLevel, text: *u8, ctx: *void) -> void #c_call;

logger_callback :: (level: IL_LoggingLevel, text: *u8, ctx: *void) #c_call {
new_context : Context;
push_context new_context {
log("%", to_string(text));
}
}
``````

#### Example Conversion

``````IL_C_API IL_Result IL_SetAdapter(IL_Context* context, IL_AdapterFunctions* adapterFunctions);

typedef void(*IL_Logger_Callback)(IL_LoggingLevel level, const char* text, void* context);

typedef struct IL_Logger
{
IL_Logger_Callback callback;
IL_LoggingLevel level;
void* context;
} IL_Logger;

{
``````

Becomes:

``````IL :: #foreign_library "ILlibrary";

// Ditch the IL_C_API macro and rename `context` to `ctx`.

// See above section on callbacks, `const char*` becomes `*u8`.
IL_Logger_Callback :: #type(level: IL_LoggingLevel, text: *u8, ctx: *void) -> void #c_call;

IL_Logger :: struct {
callback : IL_Logger_Callback;
level    : IL_LoggingLevel;
ctx      : *void;
}

// Add `s32` size info to enum
}
``````

A minimal example of how to build a dynamic library (`.dll`) and how to load it can be found in the Advanced Snippets.

TODO.

## Module Parameters

The `#module_parameters` directive can be used to declare parameters that the user can be set when importing a module. Default values can be provided so that the user does not have to know about these parameters in order to import.

When creating a `module`, you can use `#module_parameters` to create user parameters that can be set by the user. Let's create a module called `module.jai` in a folder called `Module`.

``````#module_parameter(VERBOSE := false);

#run {
if VERBOSE {
print("The module is in VERBOSE mode\n");
} else {
print("The module is in NON_VERBOSE mode\n");
}
}

``````

In your `main.jai`, you can import the `Module` using `jai main.jai -import_dir Module`.

``````#import "Module" (VERBOSE=true);

main :: () {

}
``````

## Temporary Storage

`Temporary Storage` is linear allocator with a pointer to the start of free memory. If there is a request for memory, it advances the pointer and returns the result. If it runs out of memory, it asks the OS for more RAM. In `Temporary Storage`, you cannot free individual items, rather all allocated items are freed all at once when `reset_temporary_storage` is called.

The appropriate time to call `reset_temporary_storage` depends from application to application. In a game loop, you could reset temporary storage at either the beginning or end of a game loop:

``````while true {
input();
simulate();
render();
reset_temporary_storage();
}
``````

Here is the struct definition for `Temporary Storage`:

``````Temporary_Storage :: struct {
data: *u8;
size: s64;
occupied: s64;
high_water_mark: s64;
overflow_allocator := __default_allocator;
overflow_allocator_data: *void;
overflow_pages: *Overflow_Page;
original_data: *u8;
original_size: s64;
}
``````

In a debug build, if the high water mark exceeds the temporary storage memory capacity, temporary storage will default back to the default heap allocator to allocate more memory. In a release build, your program might crash, or have memory corruption problems.

### New using Temporary Allocator

You can do a temporary storage allocation `New` using the following code:

``````Node :: struct {
value: int;
name: string;
}

node  := New(Node, allocator=__temporary_allocator);
array := NewArray(10, int, __temporary_allocator);
``````

### Resizable Array w/ Temporary Allocator

You can set the resizable array to use the temporary allocator by setting the `.allocator` field to `__temporary_allocator`.

``````array: [..] int;
array.allocator = __temporary_allocator;
``````

### Push Temporary Allocator

To use the Temporary Allocator as the context allocator, you can use the `push_allocator(temp)` macro to push the temporary allocator to the context. When the scope closes, you get back the allocator prior.

``````push_allocator(temp);
``````

### Using Temporary Allocator as a Stack Allocator

The temporary allocator can act as a stack allocator by using the `auto_release_temp :: ()` macro to set the mark. Allocate whatever you want temporarily, then release all the memory at once when the stack unwinds by setting the mark back to the original location.

``````auto_release_temp();
``````

## Stack Trace

Stack traces are compiled into the program when `build_options.stack_trace = true`, which is `true` by default. These can be turned off for release builds. When enabled, every time a procedure is called, code is generated to output a `Stack_Trace_Node` on the stack and link it up, and unlink it when the procedure returns.

Stack traces are good for writing instrumentation code such as a profiler or memory debugger. The definition for stack traces can be found in `modules/Preload.jai`.

Here is some example code to use stack traces:

``````print_stack_trace :: (node: *Stack_Trace_Node) {
while node {
if node.info {
print("[%] at %:%. call depth %\n",
node.info.name,
node.info.location.fully_pathed_filename,
node.line_number,
node.call_depth);
}
node = node.next;
}
}

f :: (x: int) {
if x < 1 {
print_stack_trace(context.stack_trace);
} else {
f(x-1);
}
}

f(3);
``````

## Compiler directives

`#add_context` adds a declaration to a context.

`#asm` specifies that the next statements in a block are inline assembly.

`#assert` does a compile-time assert. This is useful for debugging compile-time meta-programming bugs.

`#bake_arguments` does a compile-time currying of a function/parameterized struct.

`#c_call` makes the function to use the C calling convention. Used for interacting with libraries written in C.

`#char` makes the next one character string after it into an single ASCII character (e.g. #char "A").

`#code` specifies that the next phases are a code type.

`#complete` directive requires a if-case statement to fill out all the cases for a if-case statement.

`#compiler` is a function that interfaces with the compiler as a library. The function works with compiler internals.

`#cpp_method` directive allows one to specify a C++ calling convention.

`#cpp_return_type_is_non_pod` directive allows one to specify that the return type of a function is a C++ class, for calling convention purposes.

`#deprecated` compiler directive marks a function as deprecated. Calling a deprecated function leads to a compiler warning.

`#dump` dumps out the bytecode and basic blocks used to construct the function. This is useful for viewing the disassembly of the bytecode.

`#expand` directive marks the function as a macro.

`#filepath` gets the current filepath of the program as a string

`#foreign` specifies a foreign procedure

`#foreign_library` specifies file for foreign functions

`#foreign_system_library` specifies system file for foreign functions

`#if` is a compile-time if statement

`#import` takes foreign modules located in the Jai `modules` directory and compile the library into your program.

`#insert` directive inserts a piece of compile-time generated code into a function or a struct.

`#insert_internal` directive functions similar to `#insert`, except it also allows `code` to access variables in the local scope.

`#intrinsic` directive marks a function that is handled specifically by the compiler.

`#load` takes `Jai` code files written by the programmer and adds the files to your project.

`#modify` lets one put a block of code that is executed at compile-time each time a call to that procedure is resolved. One can inspect parameter types at compile-time.

`#module_parameters` specifies the variable as a module parameter.

`#must` requires the caller to get the particular return value of the called function. Used primarily for malloc or opening file handles.

`#no_abc` directive means that in this function, do not do array bounds checking

`#no_context` directive tells the compiler that the function does not use the context.

`#no_padding` directive tells the compiler to do no padding when it comes to structs.

`#no_reset` directive lets one store data in the executable's global data, without having to write it out as text.

`#place` directive is another way of forming a union data type.

`#placeholder` specifies to the compiler that a particular symbol will be defined/generated by the compile-time metaprogram.

`#run` takes the function in question and runs that function at compile time (e.g. `PI :: #run compute_pi();`).

`#scope_export` makes the function accessible to the entire program

`#scope_file` makes the function only callable within the particular file.

`#specificed` keyword requires values of an enum to explicitly be initialized to a specific value. An enum marked specified will not auto-increment, and every value of the enum must be declared explicitly.

`#string x` keyword is used to specify a multi-line string.

`#symmetric` keyword allows someone to swap the 1st and 2nd parameters in a two parameter function. Useful in the case of operator overloading.

`#this` keyword returns the procedure, struct type, or data scope that contains it, as a compile-time constant.

`#type` keyword tells the compiler that the next following syntax is a type. Useful for resolving ambiguous type grammar.

`#type_info_none` directive marks a struct such that the struct will not generate the type information.

`#type_info_procedures_are_void_pointers` directive makes all the member procedures of a struct void pointers when generating type information. See Type_Info_Struct_Member.Flags.PROCEDURE_WITH_VOID_POINTER_TYPE_INFO.

`#type_info_no_size_complaint` directive prevents the compiler from complaining about the size of the type information generated by a struct.

## Program entry point details

As you've seen, the entry point of your program is called `main`, it returns `void` and does not take any arguments. But, wait, shouldn't it be a `main :: (argc : s32, argv : **u8) -> s32` like in other languages instead ? Well not in Jai! Jai has an intermediate step, where it initialize a few things such as the context, and the command line arguments are cached in the `__command_line_arguments` array.
The actual entry point of your program is called `__system_entry_point`, and can be found in `modules/Runtime_Support.jai`:

``````#program_export
__jai_runtime_init :: (argc: s32, argv: **u8) -> *Context #c_call {
__command_line_arguments.count = argc;
__command_line_arguments.data  = argv;

ts.size = TEMPORARY_STORAGE_SIZE;

ts.original_size = TEMPORARY_STORAGE_SIZE;

}

#program_export
__jai_runtime_fini :: (_context: *void) #c_call {
// Nothing here for now!
}

#program_export "main"
__system_entry_point :: (argc: s32, argv: **u8) -> s32 #c_call {
__jai_runtime_init(argc, argv);

__program_main :: () #runtime_support;
__program_main();
}

return 0;
}
``````

So, you can see that this procedure does take a `s32` and a `**u8`, and returns a `s32`. It is also marked as `#c_call`, and is exported as `main` so the OS can find it. This procedure is responsible for initializing the `context`, `temporary_storage`, and the `__command_line_arguments` array by calling `__jai_runtime_init`, defined right before. It then calls `__program_main`, which is the `main` you've defined, after pushing the newly created context.

## Inline Assembly

Inline assembly can be used to specify exactly what machine language instructions need to be executed in order to get the most optimized code, or doing SIMD instructions for parallelizing data transformations. Here is the basic starter code for inline assembly blocks. Currently, the x64 platform is supported, but there are still a lot of holes in the x64 assembly instructions support.

Places where you can find inline assembly examples: `modules/Atomics`, `modules/Bit_Operations`, `modules/Runtime_Support`.

Here is an excerpt of atomic swap from the `Atomics` module that uses assembly language:

``````atomic_swap :: (dest: *\$T, new_value: T) -> (old_value: T) {
SIZE :: size_of(T);
// The Intel documentation says that the lock prefix is ignored
// for xchg, but we'll put it here just in case I guess?
v := new_value;
#if SIZE == 1 {
#asm { lock_xchg.b v, [dest]; }
} else #if SIZE == 2 {
#asm { lock_xchg.w v, [dest]; }
} else #if SIZE == 4 {
#asm { lock_xchg.d v, [dest]; }
} else #if SIZE == 8 {
#asm { lock_xchg.q v, [dest]; }
} else {
#assert false, "Invalid size passed to atomic_swap; argument must be 1, 2, 4, or 8 bytes.";
}
return v;
}
``````

The `lock_xchg` is the `atomic swap` assembly instruction. The `.q`, `.d`, `.w`, and `.b` specifies the size of the assignment. Here is the list of different operations:

`.q` is quad-word (64-bit integer).

`.d` is double-word (32-bit integer).

`.w` is a regular word (16-bit integer).

`.b` is a byte (8-bit integer).

`.x` is the SSE is in the feature set, xmmword (128-bit)

`.y` is the AVX is in the feature set, ymmword (256-bit)

`.z` is the AVX512F is in the feature set, zmmword (512-bit)

### Current Assembly Limitations

There are no `goto` and no `jump` instructions in the current assembly. There are no `call` instructions, and you cannot call a function in the middle of an assembly block.

### Assembly Language Data Types

The data types usable within inline assembly are `gpr`, `str`, `vec`, or `omr`.

`gpr` stands for general purpose register.

`str` stands for stack register, this is used by the fpu and mmx instructions.

`vec` stands for a vector type. This is used for manipulating SIMD instructions

`omr` stands for op-mask register, only available with AVX512

### Pinning a variable to a register

The `===` operator is used to pin variables to general purpose registers. In this simplified byte swap example, result is assigned to a register. The `===` operator can be used to map to registers `a`, `b`, `c`, `d`, `sp`, `bp`, `si`, `di`, or an integer between 0 and 15.

``````byte_swap :: (input: s64) -> s64 {
result := input;
#asm {
result === a;   // result is represented as register a
bswap.q result;
}
return result;
}
``````

### Assembly Memory Operands

In x86, there are several memory operands with the format `base + index * scale + displacement`. Just like in a traditional assembly, you can indicate a memory operand by wrapping it with brackets `[]`. The ordering of the expression is rigid, and must be in the order `base + index * scale + displacement`. You cannot place the displacement first, or the base second, etc. This reduces ambiguity and confusion when fields can be ambiguous identifiers.

``````array: [32] u8;
pointer := array.data;
#asm {
mov a:, [pointer];      // a := array.data
mov i:, 10;             // declare i:=10
mov a,  [pointer + 8];
mov a,  [pointer + i*1];
}
``````

Here is a basic example to do load effective address. Note that in `rax*4`, the constant must go after the register. You can look up what `LEA` does here

``````#asm {lea.q rax, [rdx];}
#asm {lea.q rax, [rdx + rax*4];}

// NOTE: This does not work, 4*rax is wrong, must be rax*4
// #asm {lea.q rax, [rdx + 4*rax];}
``````

### Cross Block `#asm` Referencing

Cross block `#asm` referencing keeps your registers alive across the procedure. LLVM optimizations cound potentially spill them if required.

``````block_1 :: #asm { pxor x:, x; }
block_2 :: #asm { movdqu y:, block_1.x; }
``````

### Assembly Feature Flag Tagging

When you make a block with assembly feature flag tagging, the compiler will error if you use a feature from a feature set you haven't tagged the block with, unless the feature has been enabled globally in a build script. All the assembly feature flag options can be found in `Machine_X64.jai`. Flag options includes flags such as `AVX` (Advanced Vector Extensions), `MMX` (MMX instructinos), `SSE3` (SSE3 instructions), and many other instructions.

``````#asm AVX, AVX2 {

}
``````

### Passing Registers through Macro Arguments

Registers can be passed through macro arguments, giving you the power of macros while using inline assembly.

``````add_regs :: (c: __reg, d: __reg) #expand {
#asm {
}
}

main :: () {
#asm {
mov a:, 10;
mov b:, 7;
}

}
``````

### SIMD Vector Inline Assembly Example

These are some basic SIMD Vector Code for a few 32-bit floats together at the same time. `.x` means to adding 4 floats at the same time, while `.y` indicates adding 8 floats together at the same time.

This example uses `addps.x` to add 4 32-bit floats together at the same time.

``````array := float32.[1, 2, 3, 4];
ptr := array.data;
print("array before: %\n",array); // outputs 1, 2, 3, 4
#asm {
v: vec;
movups.x v, [ptr];
movups.x [ptr], v;
}
print("array after: %\n", array); // outputs 2, 4, 6, 8
``````

This example uses `addps.y` to add 8 32-bit floats together at the same time.

``````array := float32.[1, 2, 3, 4, 5, 6, 7, 8];
ptr := array.data;
print("array before: %\n",array); // outputs 1, 2, 3, 4, 5, 6, 7, 8
#asm {
v: vec;
movups.y v, [ptr];