A basic statically typed systems-level programming language. The compiler is written in rust using LLVM as its backend. A simple unoptimized x86_64 backend is also on it's way.
- Runtime Speed: The language should make it possible to write code about as fast as C.
- Short syntax: Shorter code is more fun to write and easier to read.
- Type inference: Having to write less types makes the code shorter and refactoring easier.
- Compilation speed: Compilation speed over a few seconds makes debugging painfully slow.
- Simplicity: Syntax features are nice but too many of them make the language too complicated.
main :: fn {
std.println("Hello World")
x := 3
y := 2 * x + 3
y += 1
std.c.printf("X is %d and y is %d\n".ptr, x, y)
}
use std.c.printf
add_pointer_values :: fn(x *i32, y *i32) -> i32: x^ + y^
main :: fn {
x := 5
y := 7
printf("Result: %d\n".ptr, add_pointer_values(&x, &y))
}
add :: fn(x i64, y i64) -> i64: x + y
main :: fn {
x := 3 # x is inferred to have type i64
pointer := &x
std.c.printf("Result: %d\n".ptr, if 1 < 2: add(pointer^, 4) else -1)
}
# this constant doesn't have a specific integer type
A :: 42
main :: fn {
std.c.printf("%d\n".ptr, A) # prints 42
# can be assigned to any integer
x: u8 = A
y: i32 = A
# also works with floats
PI :: 3.14
pi: f32 = PI
pi_squared: f64 = PI*PI
}
use std.c
Vec3 :: struct { x f64, y f64, z f64 }
print_vec3 :: fn(v *Vec3) {
c.printf("Vec3: [%.1f, %.1f, %.1f]\n".ptr, v^.x, v^.y, v^.z)
}
main :: fn {
v := c.malloc(12) as *Vec3
v^ = Vec3(x: 1.0, y: 2.0, z: 3.0)
print_vec3(v)
}
Enums can be used locally without a type definition.
main :: fn {
color := .NoColor
inp := std.input("Which color do you want? ")
if inp == "red": color = .Red
else if inp == "green": color = .Green
else if inp == "blue": color = .Blue
if .NoColor := color:
print("You didn't select a valid color")
else {
print("Your color is ")
# match exhaustively checks patterns on a value. Removing any of the
# arms would create an error (even though the enum is completely inferred!)
println(match color {
.Red: "Red",
.Green: "Green",
.Blue: "Blue",
.NoColor: std.panic("unreachable"),
})
}
}
Enum variants can also have arguments. This is known as sum types/algebraic data types in many other languages. Note that implicit enums can infer to explicitly typed enums without having to name the type.
use std.print
use std.println
Fruit :: enum { Apple(i32), Banana, Citrus }
main :: fn {
# f is of type Fruit here because it is passed to print_fruit
f := .Banana
f = .Apple(5)
# This would create a compilation error because Orange is not a valid variant of Fruit
# f = .Orange
print_fruit(f)
print_fruit(.Banana)
}
print_fruit :: fn(f Fruit): match f {
.Apple(radius) {
print("Apple with radius ")
println(std.int_to_str(radius))
}
.Banana: println("A Banana"),
.Citrus: println("A Lemon?")
}
You will need LLVM to build this project. Look at the llvm-sys crate for detailed instructions on how to build or install llvm.
Nightly rust will also be required. I will try to stay mostly up to date with the newest nightly version.
To run a program, use cargo +nightly run -- run example.eye
or install the compiler with cargo install
and use
eye run example.eye
allthough this will require the std library to be present in the same
directory as the binary or the working directory (for now).