Introduction

R2D2 is a programming language designed for building modular JavaScript applications using a clear, explicit, and structured syntax.


It is written in Go and compiles to JavaScript, embracing a module-based architecture where each module can contain variables and functions. These modules are compiled into native JavaScript objects, making it easy to integrate with existing frontend or backend projects.


R2D2 introduces the concept of pseudo-functions — a special type of function that can only contain calls to other functions. This enforces composability and encourages building code through reusable, isolated behaviors.


The language is built with clarity in mind. It avoids hidden behavior and favors explicit patterns, making it approachable for those who want to write structured, maintainable code.


Installation

To install R2D2, run the following command in your terminal:


curl -sSL https://raw.githubusercontent.com/ArturC03/r2d2-cli/main/install.sh | bash

After running on of the commands above, the r2d2 binary should be available in your $PATH.

You can verify the installation by running the following command:


r2d2 version

Hello World!

This example shows how to print text to the terminal in R2D2:


module helloworld {
	export fn main() {
		console.log("Hello World!")
	}
}
  • The console.log function is used to print text to the terminal.
  • The main function is the entry point of the program.

If you want to run this example, you can use the following command:


r2d2 run <your-file-name>.r2d2

If everything was done correctly, you should see the following output:


Hello World!

Comments

Single-line Comments

Use // for single-line comments:


module Example {
    export fn main() {
        // This is a single-line comment
        let x = 5;  // This is also a comment
    }
}

Multi-line Comments

Use /* */ for multi-line comments:


module Example {
    export fn main() {
        /* This is a
           multi-line
           comment */
        let x = 5;
    }
}


Variables

Variable Declaration

Declare variables using either the var or let keyword:


module Example {
    export fn main() {
        var name = "R2D2";
        let age = 42;
        var isActive = true;
        let count = 0;
    }
}

Constants

Declare constants using the const keyword:


module Example {
    export fn main() {
        const PI = 3.14159;
        const MAX_SIZE = 100;
    }
}

Variable Assignment

Assign values to variables:


module Example {
    export fn main() {
        var count = 0;
        count = count + 1;
        count += 1;  // Shorthand
    }
}

If Statements

Basic If Statement

The most basic form of conditional execution:


module Example {
    fn checkNumber(x) {
        if (x > 0) {
            return "positive";
        }
    }
}

If-Else Statement

Adding an else clause for alternative execution:


module Example {
    fn checkNumber(x) {
        if (x > 0) {
            return "positive";
        } else {
            return "negative or zero";
        }
    }
}

Arrow Syntax

For simple conditions, you can use arrow syntax:


module Example {
    fn checkNumber(x) {
        if (x > 0) => return "positive";
        else if (x < 0) => return "negative";
        else => return "zero";
    }
}

Loops

For Loop

The traditional for loop with initialization, condition, and increment:


module Loops {
    fn countToFive() {
        for (let i = 0; i < 5; i++) {
            console.log(i);
        }
    }
}

While Loop

Execute code while a condition is true:


module Loops {
    fn countdown(x) {
        while x > 0 {
            x--;
            console.log(x);
        }
    }
}

Loop Statement

Infinite loop


module Loops {
    fn processItems() {
        loop {
            if condition {
                break;
            }

            if skipCondition {
                continue;
            }
            // loop body
        }
    }
}

Break Statement

Exit a loop prematurely:


module Loops {
    fn findItem() {
        while (true) {
            if (found) {
                break;    // Exit the loop
            }
            // continue searching
        }
    }
}

Continue Statement

Skip to the next iteration of a loop:


module Loops {
    fn printOddNumbers() {
        for (let i = 0; i < 10; i++) {
            if (i % 2 === 0) {
                continue; // Skip even numbers
            }
            console.log(i);
        }
    }
}

Switch Statements

Basic Switch

Simple switch statement with case handling:


module SwitchExamples {
    fn handleValue(value) {
        switch (value) {
            case 1 {
                console.log("One"); 
            }
            case 2 {
                console.log("Two");
            }
            default {
                console.log("Other");
            }
                
        }
    }
}

Arrow Syntax

Using arrow syntax for simple cases:


module SwitchExamples {
    fn handleSimpleValue(value) {
        switch (value) {
            case 1 => console.log("One");
            case 2 => console.log("Two");
            default => console.log("Other");
        }
    }
}

Functions

Function Declaration

Define a function within a module:


module Math {
    fn add(a, b) {
        return a + b;
    }
}

Function Parameters

Functions can take multiple parameters:


module Utils {
    fn greet(name, greeting ) {
        return greeting + ", " + name + "!";
    }
}

Return Values

Functions can return values using the return statement:


module Math {
    fn multiply(a, b) {
        return a * b;
    }

    fn divide(a, b) {
        if (b === 0 && a === 0) {
            return null;
        }
        return a / b;
    }
}

Pseudo-Functions

Pseudo-functions are functions that can only call other functions.


module Utils {

	fn greet(name, greeting) {
		console.log(greeting + ", " + name + "!");
	}

	// it can only call other functions from its module
	pseudo fn main() {
        greet("Artur", "Hello");
    }
}

The objective of pseudo-functions is to incentivize the use of functions and to make the code more readable and modular.

It is particularly well-suited to projects involving multiple contributors, where organization is essential, as well as for solo developers seeking a reliable way to ensure their program remains modular.


Modules

Module Declaration

Define a module with its methods:


module Math {
    fn add(a, b) {
        return a + b;
    }

    fn subtract(a, b) {
        return a - b;
    }
}

Interface Declaration

Define an interface that modules can implement:


interface Calculator {
    fn add(a, b);
    fn subtract(a, b);
}

Module Implementation

Implement an interface in a module:


module BasicCalculator {
    fn add(a, b) {
        return a + b;
    }

    fn subtract(a, b) {
        return a - b;
    }
}

Using R2D2 Files

Import and use functionality from other R2D2 files. Note that use statements must be at the beginning of the file:


use "math.r2d2";

module Main {
    fn run() {
        let result = Math.add(5, 3);
        console.log(result); // 8
    }
}

Module Exports

Export specific functionality from a module:


module Utils {
    export fn formatDate(date) {
        return date.toLocaleDateString();
    }

    fn internalHelper() {
        // Internal implementation
    }
}


Interfaces

Interface Declaration

Define an interface with required methods:


interface Calculator {
    fn add(a, b);
    fn subtract(a, b);
}

Interface Implementation

Implement an interface in a module:


module Basic::Calculator {
    fn add(a, b) {
        return a + b;
    }

    fn subtract(a, b) {
        return a - b;
    }
}

Extended Interfaces

An interface can extend another interface:


interface Printable {
    fn print();
}

interface Serializable::Printable {
    fn serialize();
}

module Document::Serializable {
    fn print() {
        // Print implementation
    }

    fn serialize() {
        // Serialize implementation
    }
}