Skip to content

nihklas/Flowlang

Repository files navigation

FlowLang

Lines of Code Pipeline Status

A language that is highly inspired by Golang's Goroutines and Channels.

It will be a compiled, garbage collected language implemented in Zig.

It is primarily a personal project to learn how to implement concurrency models on top of threads, as well as how to make and design a toy language from scratch.

Features and Details

Non-exhaustive list of some of the biggest and most important features planned:

  • Easy, Colorless concurrency model
  • Gargabe Collection
  • Byte-Code VM shipped in the final executable
  • Extendable VM (through Zig Modules)
  • Type-Safe

Try it out!

Take a look at the example/ directory. There you can find src/main.flow as a basic starting point to get familiar with the syntax of flow. Additionally, you can look at the different test cases in tests/cases/ to get a feel of how some of the stuff behaves.

If you are using nix, you can start an ad-hoc shell environment including flowc with this command:

nix shell gitlab:flowlang/flowlang

Otherwise, you need to install Flow from source, by cloning this Repository and running zig build. After that, the compiler is located at zig-out/bin/compiler.

Extensions

Flow supports extensions for the runtime and compiler. That means, you can write Zig Modules to implement performance critical tasks and export them to be globally available functions in Flow-Land. For an example on how to write an extension yourself, you can look at betterAdd.

You can fetch the module via Zig's package manager:

zig fetch --save git+https://gitlab.com/flowlang/betteradd

You also need a Zig file, where you re-export all the functions you need. That way, you can also import a Module, but only use a single function, and the rest of the Module will not be included in the compiled output. The exports.zig of the example looks simply like this:

const lib = @import("betterAdd");

pub const betterAdd = lib.betterAdd;

This exports.zig includes all modules exports the functions that are needed. You can define different names for these functions in here as well, to avoid naming collisions.

Here is the build.zig to build the compiler with the extension enabled.

const std = @import("std");
const flow = @import("flow");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const betterAdd = b.dependency("betterAdd", .{});

    const flow_dep = b.dependency("flow", .{});

    const compiler = flow.buildCompiler(b, flow_dep.builder, .{
        .target = target,
        .optimize = optimize,
        .extensions = .{
            .modules = &.{
                .{ .name = "betterAdd", .module = betterAdd.module("betterAdd") },
            },
            .exports_file = b.path("exports.zig"),
        },
    });

    b.installArtifact(compiler);
}

To add more extensions, you just have to add them as a dependency via zig fetch, re-export the functions you want to use and add another entry in the .modules array.

Syntax and Grammar

Current Grammar

Types

  • bool
  • int
  • float
  • string
  • array
  • struct (later)
  • channel (later)

Literals

  • Digits/Numbers (1, 1234, 12.34)
  • String Literals ("String")
  • true/false
  • null

Operators

// arithmetic
+, -, *, /

// Comparison
==, <=, >=, != 

// Logical
and, or

// Unary
!, -

// String concat
.

// shorthands for assignment
+=
-=
*=
/=
%=
.=

Variables / Constants

var x: int = 1;
var y: int;
var z = 1;

const a: string = "hello";
const b: string;
const c = "world";

Control Structures

Blocks:

{
    // This is a block
}

Conditionals:

if condition block

---

if condition block
else block

Loops:

for initializer;condition;continue-expr block

// shorthand for just a condition
for condition block

// infinite loop
for block

Functions:

func identifier(age: int, decimal: float, name: string, flag: bool, chn: int channel) returntype block

---

// closure / anonymous function
func(parameters) use (closure-values) returntype block

---

// method on a struct
meth identifier(parameters) returntype block

Channel:

channel id: int;

--- 

// (chn is a channel "object")

// reading
chn -> variable

// writing
chn <- value

Async function-call / Execution

flow call()

flow {
    a = 1;
}

Errors

err is a keyword, which itself is the value of the current error in a catch block. It can also be used to create or reference an Error

func() catch block

try func()
// this is the same as:
func() catch return err

//Errors must be specified in the return type with an Exclamation Mark (`!`)
func thisMayFail() !void block

//To create an error:
var myError = err.MyErrorName
if myError == err.MyErrorName block

Implementation notes

Byte code is split into 3 simple sections:

  • constants
  • top-level functions
  • main code

About

This a mirror of https://gitlab.com/flowlang/flowlang. If you want to open an issue, please use the Gitlab page for that

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages