Complete reference for the self-hosted programming language
This guide covers a programming language that compiles itself! The Ovie compiler is written in Ovie, proving its maturity and production readiness.
Ovie is a modern programming language designed with accessibility and clarity in mind. It uses natural language patterns to make programming more intuitive while maintaining the power and performance needed for serious software development.
Uses pidgin English keywords that are easy to read and understand.
The compiler is written in Ovie itself, proving language maturity.
Built-in memory safety without garbage collection overhead.
Identical inputs always produce identical outputs.
Ovie's syntax is designed to be readable and natural. Here are the fundamental patterns:
// Comments start with double slashes
// This is a simple Ovie program
// Output to console
seeAm "Hello, World!"
// Variables
mut name = "Ovie"
mut version = 1.0
// Function definition
fn greet(person) {
seeAm "Hello, " + person + "!"
}
// Function call
greet(name)
print("Hello")
console.log("Hello")
System.out.println("Hello")
seeAm "Hello"
The seeAm keyword is derived from pidgin English, making it more accessible to non-native English speakers and beginners.
Ovie distinguishes between mutable and immutable variables for better code safety:
// Immutable variables (default)
name = "Alice"
age = 25
pi = 3.14159
// Mutable variables (can be changed)
mut counter = 0
mut score = 100
mut active = true
// Changing mutable variables
counter = counter + 1
score = score * 2
active = false
name and Name are different)Ovie has a simple but powerful type system:
// Numbers (integers and floats)
mut age = 25
mut height = 5.9
mut temperature = -10.5
// Strings
mut name = "Alice Johnson"
mut message = 'Single quotes also work'
mut multiline = "This is a
multi-line string"
// Booleans
mut is_active = true
mut is_complete = false
// Arrays
mut numbers = [1, 2, 3, 4, 5]
mut names = ["Alice", "Bob", "Charlie"]
mut mixed = [1, "hello", true, 3.14]
Ovie automatically infers types based on the assigned value:
// These are equivalent
mut count = 42 // Inferred as Number
mut count: Number = 42 // Explicit type annotation
Functions are first-class citizens in Ovie with clean, readable syntax:
// Simple function
fn greet(name) {
seeAm "Hello, " + name + "!"
}
// Function with return value
fn add(a, b) {
return a + b
}
// Function with type annotations
fn multiply(a: Number, b: Number) -> Number {
return a * b
}
// Function with default parameters
fn greet_with_title(name, title = "Mr.") {
seeAm "Hello, " + title + " " + name + "!"
}
// Using functions
greet("World")
mut result = add(5, 3)
mut product = multiply(4, 7)
greet_with_title("Smith")
greet_with_title("Johnson", "Dr.")
// Functions can take other functions as parameters
fn apply_operation(a, b, operation) {
return operation(a, b)
}
// Usage
mut sum = apply_operation(5, 3, add)
mut product = apply_operation(5, 3, multiply)
Ovie provides familiar control flow constructs with natural syntax:
// If-else statements
mut age = 18
if age >= 18 {
seeAm "You are an adult"
} else if age >= 13 {
seeAm "You are a teenager"
} else {
seeAm "You are a child"
}
// Ternary operator
mut status = age >= 18 ? "adult" : "minor"
// Pattern matching (coming soon)
match age {
0..12 => seeAm "Child"
13..17 => seeAm "Teenager"
18..64 => seeAm "Adult"
_ => seeAm "Senior"
}
// For loops with ranges
for i in 0..5 {
seeAm "Count: " + i
}
// For loops with arrays
mut names = ["Alice", "Bob", "Charlie"]
for name in names {
seeAm "Hello, " + name
}
// While loops
mut count = 0
while count < 5 {
seeAm "Count: " + count
count = count + 1
}
// Loop control
for i in 0..10 {
if i == 3 {
continue // Skip this iteration
}
if i == 7 {
break // Exit the loop
}
seeAm i
}
Ovie supports structured data through structs:
// Define a struct
struct Person {
name: String,
age: Number,
email: String,
active: Boolean,
}
// Create struct instances
mut person1 = Person {
name: "Alice Johnson",
age: 30,
email: "alice@example.com",
active: true,
}
// Access struct fields
seeAm "Name: " + person1.name
seeAm "Age: " + person1.age
// Modify struct fields (if mutable)
person1.age = 31
person1.active = false
// Struct methods
struct Rectangle {
width: Number,
height: Number,
}
fn area(rect: Rectangle) -> Number {
return rect.width * rect.height
}
fn perimeter(rect: Rectangle) -> Number {
return 2 * (rect.width + rect.height)
}
// Usage
mut rect = Rectangle { width: 10, height: 5 }
seeAm "Area: " + area(rect)
seeAm "Perimeter: " + perimeter(rect)
Ovie provides powerful array manipulation capabilities:
// Array creation
mut numbers = [1, 2, 3, 4, 5]
mut names = ["Alice", "Bob", "Charlie"]
mut empty = []
// Array access
mut first = array_get(numbers, 0)
mut last = array_get(numbers, array_length(numbers) - 1)
// Array modification
append(numbers, 6) // Add to end
prepend(numbers, 0) // Add to beginning
array_set(numbers, 2, 99) // Set specific index
// Array information
mut length = array_length(numbers)
mut is_empty = array_is_empty(empty)
// Array iteration
for item in numbers {
seeAm "Number: " + item
}
// Array methods
mut doubled = array_map(numbers, fn(x) { return x * 2 })
mut evens = array_filter(numbers, fn(x) { return x % 2 == 0 })
mut sum = array_reduce(numbers, 0, fn(acc, x) { return acc + x })
Ovie uses a Result type for explicit error handling:
// Functions that can fail return Result
fn divide(a, b) -> Result {
if b == 0 {
return error("Division by zero")
}
return ok(a / b)
}
// Handling results
mut result = divide(10, 2)
if is_ok(result) {
seeAm "Result: " + unwrap(result)
} else {
seeAm "Error: " + error_message(result)
}
// Pattern matching with results (coming soon)
match divide(10, 0) {
ok(value) => seeAm "Result: " + value
error(msg) => seeAm "Error: " + msg
}
// Propagating errors
fn safe_calculation(a, b, c) -> Result {
mut step1 = divide(a, b)? // ? operator propagates errors
mut step2 = divide(step1, c)?
return ok(step2)
}
Organize code with Ovie's module system:
// Importing standard library modules
use std/io
use std/math
use std/fs
// Importing specific functions
use std/math { sqrt, pow, pi }
// Importing with aliases
use std/io as input_output
// Using imported functions
seeAm "Square root of 16: " + sqrt(16)
seeAm "Pi value: " + pi
// Creating your own modules
// In file: math_utils.ov
pub fn factorial(n) {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
pub fn fibonacci(n) {
if n <= 1 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
// In main file:
use math_utils { factorial, fibonacci }
seeAm "5! = " + factorial(5)
seeAm "F(10) = " + fibonacci(10)
Ovie includes a built-in testing framework:
// Import testing framework
use std/testing
// Simple test
test "addition works correctly" {
assert_equal(add(2, 3), 5)
assert_equal(add(0, 0), 0)
assert_equal(add(-1, 1), 0)
}
// Test with setup and teardown
test "array operations" {
mut arr = [1, 2, 3]
// Test array_length
assert_equal(array_length(arr), 3)
// Test append
append(arr, 4)
assert_equal(array_length(arr), 4)
assert_equal(array_get(arr, 3), 4)
}
// Property-based testing
property "addition is commutative" {
forall a: Number, b: Number {
assert_equal(add(a, b), add(b, a))
}
}
// Benchmark testing
benchmark "fibonacci performance" {
fibonacci(20)
}
Ovie provides memory safety without garbage collection:
// Automatic memory management
fn create_large_array() {
mut large_data = array_new(1000000)
// Memory is automatically freed when function exits
return array_length(large_data)
}
// Safe memory access
fn safe_access(data, index) {
if index < array_length(data) {
return ok(array_get(data, index))
}
return error("Index out of bounds")
}
// Async functions
async fn fetch_data(url) {
mut response = await http_get(url)
return parse_json(response)
}
// Parallel processing
fn parallel_map(data, func) {
return data.parallel().map(func).collect()
}
// Compile-time code generation
macro generate_getter(field_name) {
fn get_#{field_name}(self) {
return self.#{field_name}
}
}
// Usage
struct Person {
name: String,
age: Number,
}
generate_getter!(name)
generate_getter!(age)
Ovie is actively developed with new features being added regularly. The self-hosted compiler makes it easy to extend the language with new capabilities!
This guide covers Ovie v1.0.0 - Self-hosted since January 30, 2026 🎉
For more examples, visit our Examples Gallery