Xag

Dot-Chained SyntaxUnusual & Verbose SyntaxSafeSteep Learning Curve & Could Reject Working ProgramsExcellent Runtime PerformanceSlow Compilation Time

Under development, don't treat this website's info as truth.

A programming language built around high performance, helpful error messages, and Rust-style memory management. There is no int on its own, because there is no size to assume. Programs are compiled ahead of time, either to native code or to a form run by an AOT interpreter.

Reading a program

Items sit next to each other and are used in order. Nothing is concatenated into a third thing, so there is no + for text.

# Chains, defaults, and a loop.

const.int64 'LIMIT' = [*10*];

fn.int64 'sum-to' [int64 'n'] {
    var.mut.int64 'total' = [*0*];
    loop.range.int64 'i' = [*1*, 'n'] {
        set 'total' = ['total' + 'i'];
    }
    give ['total'];
}

START {
    var.int64 's' = [sum-to['LIMIT']];
    print.stdout[str:*sum to * 'LIMIT' str:* = * 's' \n];
}
counting.xagxagc run counting.xag
sum to 10 = 55

What a name owns, and what it lends

Ownership is Rust's, checked when the program is compiled, with no garbage collector under it. A transfer is spelled at the call site, so a reader never has to work out from a function's signature that a value has left.

# Lending for reading, lending for writing, and handing over for good.

fn.int64 'size' [ref.str 'text'] {
    give [count['text']];
}

fn.nothing 'shout' [refmut.str 'text'] {
    set 'text' = ['text' *!*];
}

fn.nothing 'keep' [str 'text'] {
    print.stdout[str:*kept: * 'text' \n];
}

# Two things are lent and one comes back, so the loan is named.
fn.ref.'life'.str 'longer' [ref.'life'.str 'a', ref.'life'.str 'b'] {
    if count['a'] >== count['b'] {
        give ['a'];
    } else {
        give ['b'];
    }
}

START {
    var.mut.str 'greeting' = [*hello*];
    var.str 'reply' = [*hi*];

    # Lent for reading. 'greeting' still holds what it held.
    print.stdout[str:*size: * size[ref 'greeting'] \n];

    # Lent for writing, which is why the chain says `mut`.
    shout[refmut 'greeting'];
    print.stdout[str:*after: * 'greeting' \n];

    # The answer is borrowed from whichever of the two was longer.
    var.ref.str 'winner' = [longer[ref 'greeting', ref 'reply']];
    print.stdout[str:*longer: * 'winner' \n];

    # Handed over for good. 'spare' holds nothing after this line.
    var.str 'spare' = [*spare*];
    keep[move 'spare'];
}
borrowing.xagxagc run borrowing.xag
size: 5
after: hello!
longer: hello!
kept: spare

When it has something to say

Take the program above, hand a value over for good, and then ask for it again. This is what comes back — not a paraphrase of it:

Hello, I think there may be thing(s) wrong with your code. I'm sorry, if I'm wrong.

file: moved.xag, line: 11, column: 18 (moved.xag:11:18)

`'greeting'` was moved, and holds nothing now.

  11 |     print.stdout['greeting' \n];
     |                  ^^^^^^^^^^ used here
  10 |     keep[move 'greeting'];
     |          ^^^^^^^^^^^^^^^ but it was handed over here

Error code: E0403
Rule(s) broken: a name holds its value until it is moved, and then holds nothing
Tip(s): what was moved is somewhere else now, and there is only ever one of it.

1 error.
If I am wrong about any of that, please tell me: https://github.com/Artificial-IntelligenceAI/Xag-lang/issues

A diagnostic that points at the wrong thing, or names a rule the program did not break, is a bug of the same kind as miscompiling — the compiler is telling the reader something untrue either way.

Building it

The compiler is written in C++20 against LLVM's native C++ API. It needs LLVM 23 or newer, CMake and Ninja.

git clone https://github.com/Artificial-IntelligenceAI/Xag-lang.git
cd Xag-lang
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
ninja -C build
./build/xagc run examples/counting.xag

xagc run runs a program on the test interpreter, xagc fast on the fast one, and xagc build compiles it ahead of time and writes an executable beside it. xagc check checks a program without running it.

There is no install yet. Building from source is the way to run it.