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!
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
}
}
Comments
Single-line Comments
Use // for single-line comments:
Multi-line Comments
Use /* */ for multi-line comments: