Simple. Embeddable. Yours.
Velo Lang is a functional, strict-typed compilable programming language. It runs on top of lightweight stack virtual machine.
- β Strict Typing - All variables have explicit types
- β Functional Style - Higher-order functions, lambdas and lexical closures
- β Compilable - Code compiles to bytecode for virtual machine
- β Embeddable - Easy integration into other applications
- β Generics - Type-safe generic classes, functions, and methods
- β Operator Overloading - Custom operators for user-defined classes
- β Native Classes - Host classes bound by registration, with two-way callbacks
- β
Actors -
actor class+awaitfor thread-isolated state without locks - β Standard Library - Built-in support for HTTP, file system, terminal I/O, and more
Terminal term = new Terminal();
str hello = "Hello, World!";
term.println(hello);
./gradlew run --args="/path/to/program.vel"str s = "s";
bool b = true;
int i = 1;
int hex = 0xCAFE; # Hexadecimal
int binary = 0b101010; # Binary
byte c = 2y;
float f = 3.0;
array[int] arr = new array[int]{1, 2, 3};
dict[int:str] d = new dict[int:str]{1:"a", 2:"b"};
tuple[int,str] p = new tuple(1, "second");
any value = 42; # Universal type
func add(int a, int b) int {
a + b;
};
# Lambda
any multiply = func(int a, int b) int {
a * b;
};
# Recursive
func fib(int n) int {
if n < 2 then n else fib(n - 1) + fib(n - 2);
};
Functions are first-class values: pass them around, return them, store them. Lambdas capture the variables of the scope they were defined in (lexical closures).
# Higher-order: a function that takes a function
func apply(int x, func[int] f) int {
f(x);
};
# Closure: returned lambda remembers `n` after makeAdder returns
func makeAdder(int n) func[int] {
func(int x) int { x + n; };
};
func[int] add5 = makeAdder(5);
int r = apply(3, add5); # 8
int a = 5;
str result = if a == 2 then "two" else "not two";
# Block form
str grade = if score >= 90 then {
"A"
} else if score >= 80 then {
"B"
} else {
"C"
};
int i = 1;
while (i <= 5) {
term.println(i.str);
i = i + 1;
};
array[int] numbers = new array[int]{37, 58, 25, 17, 19};
println(numbers.len); # 5
println(numbers[3]); # 17
println(numbers.sub(1, 4)[1]); # 25
array[int] doubled = numbers.map(
func(int i, int v) int {
v * 2
}
);
dict[int:str] d = new dict[int:str]{
1:"a",
2:"b",
3:"c"
};
d.set(5, "e");
println(d.del(2)); # true
println(d.len); # 3
println(d[5]); # e
println(d.key(5)); # true
println(d.keys[0]); # first key
str s = "Test String";
println(s.len); # 11
println(s.sub(5, 11)); # String
str combined = "Hello".con(", ").con("World");
tuple[int,str] p = new tuple(1, "second");
println(p.1.str); # 1
println(p.2); # second
p.1 = 42; # Mutating tuple
class Random(int seed) {
int a = 252149039;
int c = 11;
int previous = 0;
func setSeed(int seed) void {
previous = seed;
};
func next() int {
int r = a * previous + c;
previous = r;
r;
}
};
Random random = new Random(12345);
int value = random.next();
# random.previous = 10; # ERROR: fields are read-only from outside
class Vector(int x, int y) {
operator +(Vector other) Vector {
new Vector(x + other.x, y + other.y);
};
operator ==(Vector other) bool {
x == other.x & y == other.y;
};
operator [](int index) int {
if (index == 0) then x else y;
};
};
Vector a = new Vector(1, 2);
Vector b = new Vector(3, 4);
Vector sum = a + b; # Vector(4, 6)
bool eq = a == a; # true
int first = a[0]; # 1
ext(int a) max(int b) int {
if (a > b) then a else b;
};
ext(str a) insert(int index, str s) str {
a.sub(0, index).con(s).con(a.sub(index, a.len));
};
int maxValue = 5.max(10); # 10
str result = "Hello".insert(5, " World"); # "Hello World"
Concurrency without locks: an actor class instance lives on its own daemon thread, fields are private, and every interaction crosses the boundary via async (start) + await (wait).
actor class Counter(int start) {
int n = start;
func bump() int {
n += 1;
n;
};
};
actor[Counter] c = new Counter(0);
term.println((await async c.bump()).str); # 1
term.println((await async c.bump()).str); # 2
# Real parallel work: keep the future, await later.
actor[Counter] d = new Counter(100);
future[int] f1 = async c.bump();
future[int] f2 = async d.bump();
int x = await f1; # β wall time of one bump, not two
int y = await f2;
See Actors for the full model β argument cloning, identity preservation, lifetime management, parallel work patterns.
Host (JVM) classes are bound by registration β no declarations in Velo source. Register a plain Kotlin/Java class on the runtime and its Velo type is synthesized from the class itself; signatures are checked at compile time and linked before the program runs:
val runtime = VeloRuntime().register(Terminal::class)Terminal term = new Terminal();
term.println("Hello, World!");
Two-way integration: a func[(args) void] argument arrives in native code
as a VeloFunction (or a plain Kotlin (Int) -> Unit), and invoking it
from any thread runs the closure back on its owning Velo thread β see
Callbacks.
Terminal term = new Terminal();
term.print("Enter your name: ");
str name = term.input();
term.println("Hello, ".con(name));
Time time = new Time();
time.sleep(1000); # Sleep for 1 second
int unixTime = time.unix(); # Unix timestamp
Http http = new Http();
str response = http.get("https://api.example.com/data");
int status = http.statusCode();
# POST request
str jsonBody = "{\"key\": \"value\"}";
str postResponse = http.post("https://api.example.com/endpoint", jsonBody, "");
FileSystem fs = new FileSystem();
fs.write("file.txt", "Content");
str content = fs.read("file.txt");
fs.append("file.txt", "\nMore content");
bool exists = fs.exists("file.txt");
array[str] files = fs.list(".");
fs.copy("source.txt", "dest.txt");
fs.delete("file.txt");
- No unary
!operator - Use== falsefor negation - No
&&operator - Use&which always evaluates both operands - No
||operator - Use| - No
breakorcontinue- Use conditional statements - No method overloading - Each method name must be unique
- Class fields are read-only from outside - Fields can only be modified inside class methods
# Negation
if (value == false) {
# Execute if value is false
};
# Logical AND (always evaluates both operands)
if (a & b) {
# Both a and b are evaluated
};
# Logical OR
if (a | b) {
# At least one is true
};
The project is split into four Gradle modules so the compiler and the VM can be used independently:
velo-coreβ the contract shared by both sides: theOpinstruction set,VmType, the native-interop registry/descriptors, and the.vbcbytecode format (Bytecode). No execution engine.velo-compilerβ parser and compiler:.velsources βSerializedProgram. Depends only onvelo-core; a build tool can compile bytecode without the VM.velo-vmβ the execution engine: interpreter, records, memory, actors, and the embedding API (VeloRuntime). Depends only onvelo-core; a client application can run.vbcprograms without the compiler.velo-cliβ the command-line tool plus the default native classes (Terminal,Time,FileSystem,Http,Socket). The only module that links the compiler and the VM together.
Embedding the VM in an application:
val runtime = VeloRuntime().register(MyApi::class)
runtime.run(Bytecode.read(File("app.vbc")))Compiling without running:
val compiler = VeloCompiler().register(MyApi::class)
val program = compiler.compile("app.vel") ?: return
Bytecode.write(program, File("app.vbc"))The project includes many example programs in velo-cli/src/main/resources/:
hello.vel- Hello, World programfibonacci-recursive.vel- Recursive Fibonacci algorithmprimes-range.vel- Find prime numbers in a rangelzw.vel- LZW compression algorithmhuffman.vel- Huffman compression algorithmclass.vel- Class usage examplesext.vel- Extension function examplesclosures.vel- Closures, captured state and curryinghigher-order.vel-apply,compose,countand array.map with captureshttp-example.vel- HTTP request examplesfilesystem-example.vel- File system operations examplesgame-of-life.vel- Conway's Game of Life implementation
Run a program from a file:
./gradlew run --args="/path/to/program.vel"Run sample programs from bytecode:
./gradlew run --args="/path/to/bytecode.vbc"# Build the project
./gradlew build
# Run tests
./gradlew test
# Run a program (paths resolve from the repository root)
./gradlew run --args="velo-cli/src/main/resources/hello.vel"For complete documentation, see docs/README.md.
The documentation includes:
- Complete language reference
- All data types and operators
- Standard library reference
- Best practices
- Examples and tutorials
MIT License
Copyright (c) 2025 Igor Solkin
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
