📚 Contents

Ovie

Ovie Language Guide

Complete reference for the self-hosted programming language

🏆 Self-Hosted Achievement!

This guide covers a programming language that compiles itself! The Ovie compiler is written in Ovie, proving its maturity and production readiness.

Overview

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.

🌍 Natural Syntax

Uses pidgin English keywords that are easy to read and understand.

🏆 Self-Hosted

The compiler is written in Ovie itself, proving language maturity.

🛡️ Memory Safe

Built-in memory safety without garbage collection overhead.

⚡ Deterministic

Identical inputs always produce identical outputs.

Basic Syntax

Ovie's syntax is designed to be readable and natural. Here are the fundamental patterns:

Basic Program Structure
// 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)

Natural Language Keywords

Traditional Languages

print("Hello")
console.log("Hello")
System.out.println("Hello")

Ovie

seeAm "Hello"

The seeAm keyword is derived from pidgin English, making it more accessible to non-native English speakers and beginners.

Variables

Ovie distinguishes between mutable and immutable variables for better code safety:

Variable Declaration
// 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

Variable Naming Rules

  • Must start with a letter or underscore
  • Can contain letters, numbers, and underscores
  • Case-sensitive (name and Name are different)
  • Cannot use reserved keywords

Data Types

Ovie has a simple but powerful type system:

Basic Types
// 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]

Type Inference

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

Functions are first-class citizens in Ovie with clean, readable syntax:

Function Definitions
// 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.")

Higher-Order Functions

// 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)

Control Flow

Ovie provides familiar control flow constructs with natural syntax:

Conditionals
// 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"
}
Loops
// 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
}

Data Structures

Ovie supports structured data through structs:

Struct Definition and Usage
// 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)

Arrays & Collections

Ovie provides powerful array manipulation capabilities:

Array Operations
// 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 })

Error Handling

Ovie uses a Result type for explicit error handling:

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)
}

Modules

Organize code with Ovie's module system:

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)

Testing

Ovie includes a built-in testing framework:

Unit Testing
// 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)
}

Advanced Features

Memory Management

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")
}

Concurrency (Coming Soon)

// 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()
}

Metaprogramming (Coming Soon)

// 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)

🚀 Continuous Evolution

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