The Fog Programming Language

made by Marcell Varga

This documentation aims to provide a simple and easy way to understand the basics of the language. Most of the documentation is subject to change as it covers the earliest release of the language. The documentation is updated per release and it assumes you are using the latest release of the compiler.

The documentation also hosts examples of the code syntax for understandability.

Translations may be available in the future for multiple languages.

Introduction

Welcome to the Documentation of Fog, the statically typed, simple, flexible language.

What is Fog for

Fog was primarily created as a way to get experience with creating programming languages, and more importantly the inner workings of LLVM. It is also extremely useful to create quick programming ideas. We must also mention that the language is not slow even by modern standards due to its performant backend.

Who is Fog for

The language is mostly implemented for personal use for now, as I am sure the language does not hold much value for enterprises especially in this state.

The use of the documentation

The documentation assumes you are using the latest release of the language. It is advisable that you read the documentation from front to back, so that you are familiar with all the concepts the language brings.

Getting Started

The language can be installed and used fairly easily. You can build the binary for the compiler from the source available here. Additionally, prebuilt installers are available for Windows in the Github repository.

It is best advisable to add the binary to PATH, if compiling the binary manually so that it can be used easily later.

After installing the compiler we finally get to work on our first ever project!

Initializing a project

There are multiple commands available for creating a new project.

You can use the commands on Windows as following:

  • For Initializing a project in a pre-existing folder:
$ mkdir /%project-name%
$ cd %project-name%
$ fog init
  • For creating a new folder specifically for the project:
$ fog new %project-name%

Initializing a project

After installing the compiler we finally get to work on our first ever project!

There are multiple commands available for creating a new project.

You can the commands as following on Windows:

  • For Initializing a project in a pre-existing folder:
$ mkdir /%project-name%
$ cd %project-name%
$ fog init
  • For creating a new folder specifically for the project:
$ fog new %project-name%

Primitives

Scalar types

Almost all of the basic scalar types are implemented in this language.

Basic types

BitsSignedUnsignedFloat
8-bit-uintsmall-
16-bitinthalfuinthalffloathalf
32-bitintuintfloat
64-bitintlonguintlongfloatlong

Additional types

bool: Used for storing a boolean value.

void: Used for indicating a function with no returned value

string: A string variable can be used to store text. The language handles strings as a pointer to an array. (This comes into play when interacting with FFI)

array<T, L>: An array can be used to store multiple values in the same variable. An array has a pre-determined type and length, as indicated by the generic T and L. A length can only be an int.

Custom Types

Structs can also be created by the user via the struct keyword. Structs cannot contain themselves. Definining a struct is similar to how one would do it in other languages.

struct my_struct {
    field1: int,
    field2: string,
    field3: bool,
}

Enums are also available and are accessible via the enum keyword. Enums can also serve as a Default value for any type.

enum Weekdays {
    Monday,
    Tuesday,
    Friday,
}

enum FavWords<string> {
    choco = "Chocolate",
    banana = "Banana",
}

Variables

Creating Variables

Since the language is statically typed, every variable has to have its type defined at compile time. Initializing a variable is not crucial, as variables get a default value if left unintialized by the user.

Here is how one can define a variable with the aforementioned types.

int age = 23;
string name = "marci1175";
bool is_male = true;

Defining struct may seem tricky at first, but they are no different from most languages. Every field has to be manually initialized with their own default value.

struct person {
    age: int,
    name: string,
    is_male: bool,
}

person somebody = person { age: 23, name: "marci", is_male: true };

Accessing an enum variable is no different from other languages. The default type for an enum is an int if not defined by the user.

struct Apple {
    color: float,
    name: string
}

enum Apples<Apple> {
    Idared = Apple { color: 1.0, name: "Idared" },
    Granny = Apple { color: 0.5, name: "Granny Smith" }
}

enum Numbers {
    One,
    Two,
    SixtySeven = 67
}

string ida_name = Apples::Idared.name;
int integer_zwei = Numbers::Two;
int float_zwei = Numbers::Two as float;

Functions

Creating functions

For creating functions, the function keyword can be used. This may be familiar to some from other languages which have similar keywords.

Function definition example:

function name(arg1: int, arg2: float) {
    // Function body
}

function name_2(arg1: int, arg2: float): int {
    // Function body

    return 0;
}

Importing functions

We can import functions from other source files, or from libc. For importing function we can use the import keyword.

Here is how to import both types of functions:

//other.f
function return_2(): int {
    return 2;
} 

// main.f
import "other.f";
// You can also import source files on different paths like
// import "foo/bar/faz/test.f";
// import test::some_fn;
import printf(msg: string, ...): void;
import other::return_2;

function main(): int {
    int num = return_2();

    printf("Returned number: %i", num);

    return 0;
}

Note that we can also use variable args when constructing symbols for other functions. VarArgs cannot be used in a fog function.

Logic Gates and Comparisons

Please note that this part of the languge is not finished, I cannot grant the reliability of the code that is provided. This part of the language is subject to change.

Logic Gates work almost perfectly, the issue is with comparisons, as every comparison "trait" is hardcoded into the language. Im aiming to implement traits or something similar to rust's solution so that cmp traits are more flexible and easier to use.

An example for using Logic Gates:

import printf(msg: string): void;

function main(): int {
    if (3 > 8) {
        printf("Oh no! Math broke!");
    }
    else {
        printf("Oh yes! Math didn't break!");
    }

    return 0;
}

The following comparison operators are implemented currently (for all types):

  • !=
  • ==
  • >
  • >=
  • <
  • <=

Hello World!

Writing the code for the project

Fog source files always end with the .f extension. A wide range of naming schemes can be used with fog support them all.

Warning⚠️: File names cannot contain any special characters except "_".

Navigate to: %project-name%/src/main.f

And enter the code:

import puts(msg: string): int;

function main(): int {
    puts("Hello World!");
    
    return 0;
}

Save the file, run the command fog c and navigate to ./output.

Here, you will see your binary's LLVM-IR which can be then parsed by a linker to produce a valid binary. Use your preferred method of linking this file, to create an exe.

My preferred way of linking is via Clang, so I am going to use that.

$ fog c
$ clang %project-name%.ll
$ ./%project-name%.exe
Hello World!

If you can see "Hello World!" in your console, congratulations! You have created your first ever application with Fog.