The Ziv Programming Language

by the Ziv Development Team and Contributors


Welcome to the Ziv Programming Language! This is the official documentation for Ziv, a new programming language designed to be simple, fast, and easy to use. This documentation will guide you through the basics of the language, and help you get started with writing your own Ziv programs.

  1. User Manual: Learn how to use Ziv, from installing the compiler to writing your first program.

  2. Developer Guide: Information for developers who want to contribute to the Ziv project, including how to build the compiler from source and run the test suite.

  3. Language Reference: A detailed reference guide to the Ziv language, including syntax, keywords, and standard library functions.

We hope you enjoy using Ziv, and we welcome your feedback and contributions to the project!

User Manual

Welcome to the Ziv Programming Language User Manual.This section is designed to help you get started with Ziv, understand its core features, and provide examples to illustrate its capabilities.

Table of Contents

Introduction

Ziv is a modern programming language designed to be simple, expressive, and powerful. Drawing inspiration from various programming paradigms, Ziv aims to provide developers a with a versatile toolset while maintaining an easy-to-learn syntax.

Design Goals

  • Simplicity: Ziv is designed to be easy to learn and use, with a minimalistic syntax that is both expressive and readable.

  • Expressiveness: Ziv aims to provide a rich set of features that allow developers to write clean, concise code that is easy to understand.

  • Versatility: Ziv is a multi-paradigm language that supports both functional and object-oriented programming styles, allowing developers to choose the best approach for their needs.

  • Performance: Ziv is designed to be fast and efficient, with a focus on optimizing code execution and memory usage.

  • Extensibility: Ziv is designed to be extensible, with support for modules and extensions that allow developers to add new features and functionality to the language.

Why Ziv?

Ziv combines the best aspects of existing programming languages while introducing unique features that enhance developer productivity and application performance. Whether you're building web applications, system tools, or complex algorithms, Ziv provides the tools you need to succeed.

Getting Started

This section will guide you through the initial steps of using the Ziv programming language, from installation to writing your first program.

Prerequisites

  • Operating System: Ziv is currently supported on Linux and macOS. Windows support is planned for a future release.

  • Dependencies: Ziv requires the following dependencies to be installed on your system:

    • clang (version 10 or later)
    • llvm (version 10 or later)
    • cmake (version 3.10 or later)
    • ninja (version 1.8 or later)

Ensure that these dependencies are installed before proceeding with the installation process.

Installation

Using Pre-built Binaries

Ziv provides pre-built binaries for major operating systems. Follow the steps below to install Ziv using the pre-built binaries:

  1. Download: Visit the Ziv Releases page and download the latest release for your operating system.

  2. Extract: Unzip the downloaded archive to a directory of your choice.

  3. Add to Path: Add the Ziv binary directory to your system's PATH environment variable to make it accessible from the command line.

Building from Source

If you prefer to build Ziv from source, follow the steps below:

  1. Clone the Repository: Clone the Ziv repository from GitHub using the following command:

    git clone https://github.com/ziv-language/ziv.git
    
  2. Build Ziv: Navigate to the cloned repository and run the following commands to build Ziv:

    cd ziv
    cmake -B build -G Ninja -S .
    cmake --build build
    
  3. Add to Path: Add the build/bin directory to your system's PATH environment variable to make the Ziv binary accessible from the command line.

Writing Your First Program

Now that you have installed Ziv, let's write a simple "Hello, World!" program to test your installation.

  1. Create a new file named hello.ziv with the following content:

    # hello.ziv
    fn main() -> void:
        print("Hello, World!")
    
  2. Save the file and run the following command in the terminal to compile and execute the program:

    zivc hello.ziv
    

You should see the output Hello, World! printed to the console. Congratulations! You have successfully written and executed your first Ziv program.

Tutorial

This tutorial will guide you through the basics of the Ziv programming language. By the end of this tutorial, you should have a good understanding of the language's syntax, features, and best practices.

Table of Contents

Hello, World!

Language Features

Ziv is designed to provide a robust set of features that make it easy to write code that is both efficient and easy to read. This document provides an overview of the language features that Ziv provides.

Table of Contents

Simple and Readable Syntax

Ziv emphasizes readability and simplicity, making it easy to write and understand code. The syntax is clean and minimalistic, reducing the likelihood of errors and enhancing the readability of the code.

Example:

fn greet(name: string) -> void:
    print("Hello, " + name + "!")

    if name == "Alice":
        print("You are awesome!")
    else:
        print("Nice to meet you!")

greet("Alice")

Strong Static Typing with Type Inference

Ziv has a robust static type system that catches errors at compile time. It also supports type inference, allowing you to omit explicit type declarations when unnecessary.

Example:

# Explicit typing
let age: int = 25
name: string = "Alice"

# Inferred typing
let age = 25  # Inferred as int

# Compile-time error example
age = "Alice"

Pattern Matching

Ziv provides powerful pattern matching capabilities that allow you to match values against patterns and extract data from them.

Example:

fn is_even(n: int) -> bool:
    when n:
        0 => true
        1 => false
        _ => is_even(n - 2)

Modularity

Ziv supports modularity through the use of modules, allowing you to organize your code into reusable components.

Example:

# math.ziv
module math

fn add(a: int, b: int) -> int:
    return a + b


fn subtract(a: int, b: int) -> int:
    return a - b

end module
# main.ziv
import math

fn main() -> void:
    result: int = math.add(10, 5)
    print(result)

Concurrency and Parallelism

Ziv provides built-in support for concurrency and parallelism, allowing you to write code that can run concurrently and in parallel.

  • Concurrency: Ziv supports lightweight threads that can run concurrently when spawned.

    fn task(id: int) -> void:
        print("Task " + id + " started")
    
    fn main() -> void:
        spawn(task, 1) # Start task 1
        spawn(task, 2) # Start task 2
    
  • Parallelism: Ziv supports parallelism through the use of the parallel keyword, allowing you to execute code in parallel.

    fn task(id: int) -> void:
        print("Task " + id + " started")
    
    fn main() -> void:
        # Start task 1 and task 2 in parallel
        parallel:
            task(1)
            task(2)
    

Functional Programming

Ziv supports functional programming paradigms, including first-class functions, higher-order functions, lambdas, recursion, closures, and immutability.

Example:

  • First-Class Function

    # First-class function
    fn greet(name: string) -> void:
        print("Hello, " + name + "!")
    
    fn main() -> void:
        f: (string) -> void = greet
        f("Alice") # Output: Hello, Alice!
    
  • Higher-Order Function

    # Higher-order function
    fn apply(f: (int) -> int, x: int) -> int:
        return f(x)
    
    fn square(x: int) -> int:
        return x * x
    
    fn main() -> void:
        result: int = apply(square, 5)
        print(result) # Output: 25
    
  • Lambda Expression

    # Lambda expression
    fn main() -> void:
        result: int = apply(|x| x * x, 5)
        print(result) # Output: 25
    
  • Immutability

    # Immutable data structure
    !my_list: list[int] = [1, 2, 3]
    
    fn main() -> void:
        print(my_list) # Output: [1, 2, 3]
        my_list[0] = 4 # This will cause a compile-time error
    
  • Monads

    # Monad using >> operator
    fn add_one(x: int) -> int:
        return x + 1
    
    fn multiply_by_two(x: int) -> int :
        return x * 2
    
    fn main() -> void:
        result: int = 1 >> add_one >> multiply_by_two
        print(result) # Output: 4
    
  • Arrow Functions

    # Arrow function
    fn main() -> void:
        f: (int) -> int = |x| x * x
        result: int = f(5)
        print(result) # Output: 25
    
  • Currying

    # Currying
    fn add(a: int, b: int) -> int:
        return a + b
    
    fn main() -> void:
        add_five: (int) -> int = add(5)
        result: int = add_five(10)
        print(result) # Output: 15
    
  • Partial Application

    # Partial application
    fn add(a: int, b: int) -> int:
        return a + b
    
    fn main() -> void:
        add_five: (int) -> int = add(5, _) # Partial application
        result: int = add_five(10)
        print(result) # Output: 15
    
  • Map, Filter, Reduce

    # Map, filter, reduce
    numbers: list[int] = [1, 2, 3, 4, 5]
    
    # Map
    doubled: list[int] = map(numbers, |x| x * 2)
    print(doubled) # Output: [2, 4, 6, 8, 10]
    
    # Filter
    evens: list[int] = filter(numbers, |x| x % 2 == 0)
    print(evens) # Output: [2, 4]
    
    # Reduce
    sum: int = reduce(numbers, 0, |acc, x| acc + x)
    print(sum) # Output: 15
    
  • Lazy Evaluation

    # Lazy evaluation
    fn main() -> void:
        # infinite list of numbers
        numbers: list[int] = lazy:
            for i in 0.. :
                yield i
    
        # take first 5 numbers
        for n in take(numbers, 5):
            print(n)
    

Error Handling

Ziv provides robust error handling mechanisms that allow you to handle errors gracefully and recover from them.

Example:

fn divide(a: int, b: int) -> int:
    if b == 0:
        error("Division by zero")
    return a / b

fn main() -> void:
    result: int = divide(10, 0)

Generics

Ziv supports generics, allowing you to write code that is generic over types.

Example:

fn swap<T>(a: T, b: T) -> (T, T):
    return (b, a)

fn main() -> void:
    result: (int, int) = swap(10, 20)
    print(result)

Object-Oriented Programming

Ziv supports object-oriented programming features, such as classes, inheritance, and encapsulation.

Example:

  • Class Definition

    # Define a class with private, public, and protected members
    class BankAccount:
        public owner: string
        protected balance: float
        private account_number: string
    
        # Constructor
        fn init(account_number: string, owner: string):
            self.account_number = account_number
            self.owner = owner
            self.balance = 0.0
    
        # Destructor
        fn deinit() -> void:
            print("Account " + self.account_number + " closed")
    
        public fn deposit(amount: float):
            self.balance += amount
    
        # Methods are public by default
        fn withdraw(amount: float):
            self.balance -= amount
    
        protected fn get_balance() -> float:
            return self.balance
    
        private fn get_account_number() -> string:
            return self.account_number
    
  • Inheritance and Protected Access

    # Inheritance
    class SavingsAccount(BankAccount):
        public interest_rate: float
    
        fn init(account_number: string, owner: string, interest_rate: float):
            parent.init(account_number, owner)
            self.interest_rate = interest_rate
    
        public fn calculate_interest() -> float:
            return self.get_balance() * self.interest_rate
    
  • Instance Creation and Method Invocation

    # Instance creation and method invocation
    fn main() -> void:
        account: SavingsAccount = SavingsAccount("12345", "Alice", 0.05)
        account.deposit(1000.0)
        interest: float = account.calculate_interest()
        print(interest) # Output: 50.0
    
  • Polymorphism

    # Base Class
    class Animal:
        public fn speak() -> string:
            return "Animal speaks"
    
    # Derived Class
    class Dog(Animal):
        public fn speak() -> string:
            return "Dog barks"
    
    # Another Derived Class
    class Cat(Animal):
        public fn speak() -> string:
            return "Cat meows"
    
    fn main() -> void:
        dog: Animal = Dog()
        cat: Animal = Cat()
    
        print(dog.speak()) # Output: Dog barks
        print(cat.speak()) # Output: Cat meows
    
  • Abstract Classes

    # Abstract Class
    abstract class Shape:
        public abstract fn area() -> float
    
    # Concrete Class
    class Circle(Shape):
        public radius: float
    
        fn init(radius: float):
            self.radius = radius
    
        # Implement abstract method
        public fn area() -> float:
            return 3.14 * self.radius * self.radius
    
  • Interfaces

    # Interface
    interface Printable:
        public fn print() -> void
    
    # Class implementing the interface
    class Document(Printable):
        public fn print():
            print("Document printed")
    
  • Static Members

    # Static Members
    class Counter:
        public static count: int = 0
    
        public static fn increment():
            Counter.count += 1
    
        public static fn get_count() -> int:
            return Counter.count
    
    fn main():
        Counter.increment()
        Counter.increment()
        count: int = Counter.get_count()
        print(count) # Output: 2
    
  • Operator Overloading

    # Operator Overloading
    class Vector:
        public x: float
        public y: float
    
        fn init(x: float, y: float):
            self.x = x
            self.y = y
    
        public fn +(other: Vector) -> Vector:
            return Vector(self.x + other.x, self.y + other.y)
    

Metaprogramming

Ziv provides metaprogramming capabilities that allow you to generate code at compile time.

Example:

macro repeat(n: int, body: block):
    for i in 0..n :
        body

fn main():
    repeat(5):
        print("Hello")

Interoperability

Ziv provides seamless interoperability with other languages, allowing you to call functions written in other languages from Ziv code.

Example:

# Import a C function
extern fn c_function() -> int

fn main() -> void:
    result: int = c_function()
    print(result)

Testing Support

Ziv has built-in support for testing, enabling you to write and execute test cases directly in your code.

Example:

# This function adds two numbers
fn add(a: int, b: int) -> int:
    return a + b

# Test cases
test "Addition" :
    assert(add(1, 2) == 3)
    assert(add(0, 0) == 0)

Asynchronous Programming

Ziv provides built-in support for asynchronous programming, allowing you to write asynchronous code easily and efficiently.

Example:

async fn fetch_data(url: string) -> string;
    response: string = await http.get(url)
    return response

Advanced Features

Ziv provides a range of advanced features, such as decorators, and more, that allow you to write powerful and expressive code.

  • Decorators:

    Ziv supports decorators, which are functions that modify the behavior of other functions or methods.

    # Decorators
    @log
    fn add(a: int, b: int) -> int:
        return a + b
    
    fn main():
        result: int = add(1, 2)
        print(result) # Output: 3
    
  • Class Decorators:

    Ziv also supports class decorators, which are functions that modify the behavior of classes.

    # Class Decorators
    fn singleton(cls: class) -> class:
        instance: cls = null
    
        fn get_instance() -> cls:
            if instance == null:
                instance = new cls()
            return instance
        return cls
    
    @singleton
    class Database:
        fn init():
            print("Database initialized")
    
    fn main() -> void:
        db1: Database = Database.get_instance()
        db2: Database = Database.get_instance()
    
        print(db1 == db2) # Output: true
    
  • Module Versioning:

    Ziv supports module versioning, allowing you to specify the version of a module that your code depends on.

    # math.ziv
    module math version "1.0.0"
    
    fn add(a: int, b: int) -> int:
        return a + b
    
    end module
    
    # main.ziv
    import math version "1.0.0"
    
    fn main():
        result: int = math.add(10, 5)
        print(result)
    
  • Type Aliases:

    Ziv supports type aliases, allowing you to define custom names for existing types.

    # Type Aliases
    type Point = (int, int)
    
    fn distance(p1: Point, p2: Point) -> float:
        x1, y1 = p1
        x2, y2 = p2
        return sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
    
  • Import Aliases:

    Ziv supports import aliases, allowing you to import modules with custom names.

    # Import Aliases
    import math as m
    
    fn main():
        result: int = m.add(10, 5)
        print(result)``
    

Examples

This section provides examples of Ziv code to help you get started with the language. Each example demonstrates a specific feature or concept of Ziv and includes an explanation of the code.

Table of Contents

Hello, World!

The classic "Hello, World!" program is a simple example that demonstrates how to print text to the console. Here is the Ziv code for the "Hello, World!" program:

fn main():
    print("Hello, World!")

In this example, we define a function called main that prints the text "Hello, World!" to the console using the print function. The print function is a built-in function in Ziv that outputs text to the standard output.

To run this program, save the code to a file with a .ziv extension (e.g., hello.ziv) and use the Ziv interpreter to execute the file:

zivc hello.ziv

This will compile the Ziv code and generate an executable file that you can run to see the output "Hello, World!" printed to the console.

Basic Calculator

This example demonstrates how to create a simple calculator program in Ziv that can perform basic arithmetic operations. Here is the Ziv code for the basic calculator program:

fn add(a: int, b: int) -> int:
    return a + b

fn subtract(a: int, b: int) -> int:
    return a - b

fn multiply(a: int, b: int) -> int:
    return a * b

fn divide(a: int, b: int) -> int:
    if b == 0:
        error("Division by zero is not allowed")
    return a / b

fn main():
    num1: int = 10
    num2: int = 5

    print("Addition: ", add(num1, num2)) # Output: 15
    print("Subtraction: ", subtract(num1, num2)) # Output: 5
    print("Multiplication: ", multiply(num1, num2)) # Output: 50
    print("Division: ", divide(num1, num2)) # Output: 2

In this example, we define four functions for performing basic arithmetic operations: add, subtract, multiply, and divide. These functions take two integer arguments and return the result of the corresponding operation. The divide function also includes a check to prevent division by zero.

Fibonacci Sequence

The Fibonacci sequence is a series of numbers in which each number is the sum of the two preceding ones. This example demonstrates how to generate the Fibonacci sequence in Ziv using a recursive function. Here is the Ziv code for the Fibonacci sequence program:

fn fibonacci(n: int) -> int:
    if n <= 1:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

fn main():
    num_terms: int = 10

    for i: int in range(num_terms):
        print(fibonacci(i))

In this example, we define a recursive function called fibonacci that calculates the nth term of the Fibonacci sequence. The main function generates and prints the first num_terms terms of the Fibonacci sequence using a loop.

List Operations

This example demonstrates how to perform basic operations on lists in Ziv, such as creating a list, adding elements to a list, and iterating over a list. Here is the Ziv code for the list operations program:


fn main():
    # Create a list of integers
    numbers: list[int] = [1, 2, 3, 4, 5]

    # Add an element to the list
    numbers.append(6)

    # Iterate over the list and print each element
    for (num: int in numbers):
        print(num)

    # Output: 1 2 3 4 5 6

Error Handling

This example demonstrates how to handle errors in Ziv using the error function. Here is the Ziv code for the error handling program:


fn read_file(file_path: string) -> string:
    if file_path == "":
        error("File path cannot be empty")
    # Read the file
    return "File content"

In this example, we define a function called read_file that takes a file_path argument. If the file_path is empty, the function calls the error function with an error message. This will terminate the program and print the error message to the console.

Custom Error Types

This example demonstrates how to define custom error types in Ziv to represent different kinds of errors in your programs. Custom error types allow you to create structured error messages with additional information and context, making it easier to handle and report errors in your code. Here is an example of defining custom error types in Ziv:

error DivisionByZero:
    message: string

fn divide(a: int, b: int) -> int:
    if b == 0:
        throw DivisionByZero("Division by zero is not allowed")
    return a / b

In this example, we define a custom error type DivisionByZero with a message field to represent a division by zero error. We then define a function divide that checks for a division by zero condition and throws a DivisionByZero error with an error message if the condition is met. By using custom error types, you can provide more context and information about the error, making it easier to handle and report errors in your programs.

Modules and Extensions

This example demonstrates how to create and use modules and extensions in Ziv. Modules allow you to organize your code into reusable components, while extensions enable you to add new functionality to existing types. Here is an example of creating a module and an extension in Ziv:

  • Module: math.ziv

    # math.ziv
    
    module math version "1.0"
    
    fn add(a: int, b: int) -> int:
        return a + b
    
    fn subtract(a: int, b: int) -> int:
        return a - b
    
    end module
    
    # main.ziv
    
    import math
    
    fn main():
        result: int = math.add(1, 2)
        print(result)  # Output: 3
    
  • Extension: string_extensions.ziv

    # string_extensions.ziv
    
    extension string version "1.0"
    
    fn is_palindrome(s: string) -> bool:
        return s == s.reverse()
    
    end extension
    
    # main.ziv
    
    import string_extensions
    
    fn main():
        text: string = "radar"
        if text.is_palindrome():
            print("Palindrome")
        else:
            print("Not a palindrome")
    

In these examples, we define a module called math that contains functions for basic arithmetic operations and an extension for strings that adds a is_palindrome method. We then import and use these modules and extensions in the main function.

Classes and Objects

This example demonstrates how to define classes and create objects in Ziv. Classes allow you to define custom data types with properties and methods, while objects are instances of classes that hold specific values. Here is an example of defining a class and creating objects in Ziv:


class Point:
    private x: int
    private y: int

    public fn init(x: int, y: int):
        self.x = x
        self.y = y

    public fn + (other: Point) -> Point:
        return Point(self.x + other.x, self.y + other.y)

fn main():
    p1: Point = Point()
    p1.init(1, 2)

    p2: Point = Point()
    p2.init(3, 4)

    p3: Point = p1 + p2

    print(p3.get_x(), p3.get_y())  # Output: 4 6

In this example, we define a class called Point with private properties x and y and a public init method to initialize the object. We also define an overloaded + operator to add two Point objects together. In the main function, we create two Point objects p1 and p2, initialize them with values, add them together, and print the result.

Concurrency

This example demonstrates how to create and run concurrent tasks in Ziv using the spawn keyword. Concurrent tasks allow you to execute multiple operations simultaneously, improving performance and responsiveness. Here is an example of running concurrent tasks in Ziv:

fn task(id: int):
    print("Task " + id + " started.")
    // Simulate work with sleep
    std.time.sleep(2)
    print("Task " + id + " completed.")

fn main():
    spawn(task, 1)
    spawn(task, 2)
    spawn(task, 3)

In this example, we define a function called task that takes an id argument and simulates work by sleeping for 2 seconds. In the main function, we use the spawn keyword to run three concurrent tasks with different IDs. The tasks will execute simultaneously, and the completion messages will be printed to the console.

Parallel Processing

This example demonstrates how to perform parallel processing in Ziv using the parallel keyword. Parallel processing allows you to execute multiple operations concurrently across multiple cores, improving performance for CPU-bound tasks. Here is an example of parallel processing in Ziv:


fn calculate_sum(start: int, end: int) -> int:
    sum: int = 0
    for (i: int = start; i <= end; i = i + 1):
        sum = sum + i
    return sum

fn main():
    parallel:
        sum1: int = calculate_sum(1, 1000)
        sum2: int = calculate_sum(1001, 2000)
        sum3: int = calculate_sum(2001, 3000)
    total_sum: int = sum1 + sum2 + sum3
    print("Total sum: ", total_sum)

File I/O

This example demonstrates how to read and write files in Ziv using the std.fs module. File I/O operations allow you to interact with files on the filesystem, such as reading data from files, writing data to files, and creating new files. Here is an example of file I/O in Ziv:

import std.fs

fn read_file(file_path: string):
    file: std.fs.File =
        std.fs.open(file_path, std.fs.Mode.READ)
    if file.is_open():
        content: string = file.read_all()
        print(content)
        file.close()
        error("Failed to open file")

fn write_file(file_path: string, content: string):
    file: std.fs.File =
        std.fs.open(file_path, std.fs.Mode.WRITE)
    if file.is_open():
        file.write(content)
        file.close()
        error("Failed to open file")

fn main():
    file_path: string = "example.txt"
    content: string = "Hello, World!"

    write_file(file, content)
    read_file(file)

In this example, we define two functions read_file and write_file that read and write files, respectively. The main function demonstrates how to write the text "Hello, World!" to a file called example.txt and then read the contents of the file and print them to the console.

Networking

This example demonstrates how to perform networking operations in Ziv using the std.net module. Networking operations allow you to interact with remote servers, send and receive data over the network, and create network clients and servers. Here is an example of networking in Ziv:

import std.net

fn fetch_url(url: string):
    response: std.net.Response =
        std.net.get(url)
    if response.status_code == 200:
        print(response.body)
        error("Failed to fetch URL")

fn main():
    url: string = "https://example.com"
    fetch_url(url)

In this example, we define a function fetch_url that fetches the contents of a URL using an HTTP GET request. The main function demonstrates how to fetch the contents of the URL https://example.com and print the response body to the console.

Command-Line Arguments

This example demonstrates how to access command-line arguments in Ziv using the std.args module. Command-line arguments allow you to pass input parameters to a Ziv program when running it from the command line. Here is an example of accessing command-line arguments in Ziv:

import std.args

fn main():
    args: list[string] = std.args.get_args()
    for (arg: string in args):
        print(arg)

In this example, we define the main function that retrieves the command-line arguments using the std.args.get_args function and prints each argument to the console. When running the Ziv program from the command line, you can pass arguments that will be printed by the program.

Environment Variables

This example demonstrates how to access environment variables in Ziv using the std.env module. Environment variables allow you to store configuration settings and other information that can be accessed by Ziv programs. Here is an example of accessing environment variables in Ziv:

import std.env

fn main():
    username: string = std.env.get("USERNAME")
    if username != "":
        print("Hello, ", username)
        error("Username not found in environment variables")

In this example, we use the std.env.get function to retrieve the value of the USERNAME environment variable and print a greeting message to the console. If the USERNAME environment variable is not found, the program will print an error message.

JSON Parsing

This example demonstrates how to parse JSON data in Ziv using the std.json module. JSON parsing allows you to read and manipulate JSON data structures in Ziv programs. Here is an example of parsing JSON data in Ziv:


import std.json

fn main():
    data: std.json.Value = std.json.parse(json_data)
    name: string = data.get("name").as_string()
    age: int = data.get("age").as_int()
    print("Name: ", name)
    print("Age: ", age)

In this example, we define the main function that contains a JSON string representing a person's name and age. We use the std.json.parse function to parse the JSON data into a Value object and then extract the name and age values from the object and print them to the console.

Regular Expressions

This example demonstrates how to use regular expressions in Ziv using the std.regex module. Regular expressions allow you to search for patterns in text data and perform string manipulation based on those patterns. Here is an example of using regular expressions in Ziv:

import std.regex

fn main():
    text: string = "The quick brown fox jumps over the lazy dog"
    pattern: string = "fox|dog"
    matches: list[string] = std.regex.find_all(text, pattern)
    for (match: string in matches):
        print(match)

In this example, we define the main function that contains a text string and a regular expression pattern to search for the words "fox" or "dog" in the text. We use the std.regex.find_all function to find all matches of the pattern in the text and print each match to the console.

Unit Testing

This example demonstrates how to write unit tests in Ziv using the test keyword. Unit testing allows you to verify the correctness of individual functions or modules by writing test cases that check the expected behavior of the code. Here is an example of writing unit tests in Ziv:

fn add(a: int, b: int) -> int:
    return a + b

test "Addition":
    assert(add(1, 2) == 3)
    assert(add(0, 0) == 0)
    assert(add(-1, 1) == 0)

fn main():
    run_tests()

In this example, we define a function add that performs addition and a test case for the add function. The test case uses the assert keyword to check the expected results of adding different numbers. The main function calls the run_tests function to execute all test cases defined in the program.

Context Managers

This example demonstrates how to use context managers in Ziv to manage resources and ensure proper cleanup. Context managers allow you to define a block of code that automatically handles resource allocation and deallocation, such as opening and closing files or database connections. Here is an example of using context managers in Ziv:


fn main():
    using std.fs.open("example.txt", std.fs.Mode.WRITE) as file:
        file.write("Hello, World!")

Metaprogramming

This example demonstrates how to use metaprogramming in Ziv to generate code dynamically at compile time. Metaprogramming allows you to write code that generates other code, enabling powerful abstractions and code transformations. Here is an example of metaprogramming in Ziv:

macro repeat(n: int, body: block):
    for (i: int = 0; i < n; i = i + 1):
        body

fn main():
    repeat(3):
        print("Hello, World!")

Custom Attributes

This example demonstrates how to define and use custom attributes in Ziv to annotate code elements with metadata. Custom attributes allow you to add additional information to functions, types, or variables that can be used by the compiler or other tools, without affecting the program's behavior. Here is an example of defining and using custom attributes in Ziv:

attribute deprecated:
    message: string
    level: string = "warning" # Default value

attribute dangerous:
    message: string
    level: string = "error" # Default value

@deprecated("This function is deprecated")
fn old_function():
    # Function implementation

@dangerous("This function is dangerous", level: "error")
fn dangerous_function():
    # Function implementation

fn main():
    old_function() # Warning: This function is deprecated
    dangerous_function() # Error: This function is dangerous

Decorators

This example demonstrates how to use decorators in Ziv to add behavior to functions or methods at runtime. Decorators allow you to wrap or modify the behavior of functions without changing their source code, enabling code reuse and separation of concerns. Here is an example of using decorators in Ziv:

fn uppercase_decorator(fn: fn() -> string) -> string:
    result: string = fn()
    return result.upper()

@uppercase_decorator
fn get_greeting() -> string:
    return "hello"

fn main():
    print(get_greeting())  # Output: HELLO

Generics

This example demonstrates how to use generics in Ziv to write reusable code that works with different types. Generics allow you to define functions, classes, or data structures that can operate on any type, providing flexibility and type safety. Here is an example of using generics in Ziv:


fn print_list<T>(items: list[T]) -> void:
    for (item: T in items):
        print(item)

In this example, we define a generic function print_list that takes a list of items of any type T and prints each item to the console. The function can be used with lists of integers, strings, or any other type, making it versatile and reusable.

Enums

This example demonstrates how to define and use enums in Ziv to represent a set of named constants. Enums allow you to define custom data types with a fixed set of values, making the code more readable and maintainable. Here is an example of using enums in Ziv:

enum Color:
    RED
    GREEN
    BLUE

fn main():
    color: Color = Color.RED
    match color:
        Color.RED => print("Red")
        Color.GREEN => print("Green")
        Color.BLUE => print("Blue")

In this example, we define an enum Color with three constants RED, GREEN, and BLUE. We create a variable color of type Color and use a match expression to print the corresponding color name based on the value of the color variable.

Option Type

This example demonstrates how to use the option type in Ziv to handle nullable values and avoid null pointer exceptions. The option type allows you to represent a value that may or may not be present, providing a safer and more expressive way to handle missing values. Here is an example of using the option type in Ziv:

fn divide(a: int, b: int) -> option[int]:
    if b == 0:
        return none
    return some(a / b)

In this example, we define a function divide that takes two integers a and b and returns an option[int] value representing the result of dividing a by b. If b is zero, the function returns none to indicate a division by zero error. Otherwise, it returns some with the result of the division.

Error Handling with Option Type

This example demonstrates how to use the option type for error handling in Ziv. By combining the option type with pattern matching, you can elegantly handle errors and missing values in a functional and concise way. Here is an example of error handling with the option type in Ziv:

fn parse_int(s: string) -> option[int]:
    try:
        return some(s.to_int())
        return none

fn main():
    num_str: string = "123"
    match parse_int(num_str):
        some(num) => print("Parsed number: ", num)
        none => print("Failed to parse number")
    # Output: Parsed number: 123

    invalid_str: string = "abc"
    match parse_int(invalid_str):
        some(num) => print("Parsed number: ", num)
        none => print("Failed to parse number")
    # Output: Failed to parse number

In this example, we define a function parse_int that attempts to parse a string s into an integer using the to_int method. If the parsing is successful, the function returns some with the parsed integer value. If an error occurs during parsing, the function returns none. In the main function, we use pattern matching to handle the result of the parse_int function and print the parsed number or an error message based on the result.

Standard Library

The Ziv standard library provides a rich set of modules and functions for common programming tasks, such as working with files, networking, data serialization, and more. You can explore the Ziv Standard Library Reference to learn more about the available modules and functions in the standard library.

Modules and Extensions

Ziv's modular system is designed to promote code reusability and maintainability. This section covers how to create, import, and extend modules in Ziv.

Table of Contents

Modules

Ziv's modular system is designed to promote code reusability and maintainability. This section covers how to create, import, and extend modules in Ziv.

Creating a Module

A module is a collection of functions, types, and variables that can be imported and used in other files. To create a module, you need to define a file with the .ziv extension and declare the module using the module keyword.

Here is an example of a simple module for mathematical operations:

# math.ziv

module math

fn add(a: int, b: int) -> int:
    return a + b

fn subtract(a: int, b: int) -> int:
    return a - b

end module

In this example, we define a module called math that contains two functions: add and subtract. These functions can be imported and used in other files.

Exporting and Importing Modules

By default, all functions, types, and variables defined in a module are public and can be accessed from other files. To import a module, you can use the import keyword followed by the module name.

If you want to restrict access to certain functions, types, or variables, you can use the private keyword to mark them as private.

private fn multiply(a: int, b: int) -> int:
    return a * b

Here is an example of importing the math module and using its functions:

# main.ziv

import math

fn main() -> void:
    result: int = math.add(1, 2)
    print(result)  # Output: 3

In this example, we import the math module and use its add function to add two numbers.

Importing Specific Functions

If you only need to import specific functions, types, or variables from a module, you can use the from keyword followed by the module name and the functions you want to import.

from math import add, subtract

Or you can import a specific function and rename it using the as keyword:

import math.add as sum

Creating Libraries

You can organize related modules into a library by creating a directory with the library name and placing the module files inside it. To import a module from a library, you can use the library name followed by the module name.

lib/
  math/
    math.ziv
  string/
    string.ziv
# string/string.ziv

module lib.string

fn capitalize(s: string) -> string:
    return s.capitalize()

end module
# main.ziv

import lib.string

fn main():
    result: string = lib.string.capitalize("hello")
    print(result)  # Output: Hello

In this example, we create a library with two modules: math and string. We import the string module from the library and use its capitalize function to capitalize a string.

Extensions

Extensions allow you to add new functionality to existing types without modifying their source code. This is useful when you want to extend the behavior of a type defined in a library or module.

Creating an Extension

To create an extension, you need to define a file with the .ziv extension and declare the extension using the extension keyword followed by the type you want to extend.

Here is an example of extending the string type with a new method:

# string_extension.ziv

extension string

fn uppercase() -> string:
    return self.upper()

end extension

In this example, we define an extension for the string type that adds a capitalize method to capitalize the string.

Importing Extensions

To use an extension, you need to import it in the file where you want to extend the type. You can import an extension using the import keyword followed by the extension file name.

# main.ziv

import string_extension

fn main():
    s: string = "hello"
    result: string = s.uppercase()
    print(result)  # Output: HELLO

In this example, we import the string_extension extension and use the uppercase method to convert a string to uppercase.

Extension Methods

Extension methods can access the properties and methods of the extended type using the self keyword. You can define extension methods for any type, including built-in types, user-defined types, and library types.


extension int

fn is_even() -> bool:
    return self % 2 == 0

end extension

In this example, we define an extension for the int type that adds an is_even method to check if the integer is even.

import int_extension

fn main():
    n: int = 10
    result: bool = n.is_even()
    print(result)  # Output: true

Developer Guide

Contributing

Code of Conduct

Security Policy

Style Guide

Building Ziv

Language Reference

Overview

Syntax

Types

Operators

Expressions

Statements

Functions

Modules

Extensions

Standard Library

Error Handling

Concurrency

Memory Management

Interoperability

Tooling

Best Practices

FAQ