18 KiB
Bob Language Reference
Overview
Bob is a dynamically typed programming language focused on safety and clarity. It features automatic type conversion, closures, and a clean syntax inspired by modern programming languages.
Table of Contents
- Getting Started
- Basic Syntax
- Data Types
- Variables
- Operators
- Control Flow
- Functions
- Standard Library
- Error Handling
- Examples
Getting Started
Running Bob Code
# Compile the interpreter
make
# Run a Bob file
./build/bob your_file.bob
# Run the comprehensive test suite
./build/bob test_bob_language.bob
File Extension
.bob: Standard file extension for Bob source code
Interactive Mode
- Not implemented: No REPL (Read-Eval-Print Loop) yet
- File-based: All code must be in
.bobfiles
Basic Syntax
Statements
- Semicolons: Required at end of statements
- Parentheses: Required for function calls
- Curly braces: Required for function bodies
- Case sensitive:
varandVarare different
Comments
// Single line comment
/* Multi-line comment */
Data Types
Numbers
- Integers:
42,-10,0 - Floats:
3.14,2.718,-1.5 - Automatic conversion: Numbers are stored as doubles internally
Strings
- Literal strings:
"Hello, World!" - Empty strings:
"" - Escape sequences: Not currently supported
Booleans
- True:
true - False:
false
None
- Null value:
none(represents absence of value)
Arrays
- Array literals:
[1, 2, 3, 4, 5] - Empty arrays:
[] - Mixed types:
[1, "hello", true, 3.14] - Nested arrays:
[[1, 2], [3, 4]]
Array Access
var arr = [10, 20, 30, 40, 50];
// Basic indexing
print(arr[0]); // 10
print(arr[2]); // 30
// Float indices auto-truncate (like JavaScript/Lua)
print(arr[3.14]); // 40 (truncated to arr[3])
print(arr[2.99]); // 30 (truncated to arr[2])
// Assignment
arr[1] = 25;
print(arr[1]); // 25
// Increment/decrement on array elements
arr[0]++;
print(arr[0]); // 11
++arr[1];
print(arr[1]); // 26
Array Built-in Functions
var arr = [1, 2, 3];
// Get array length
print(len(arr)); // 3
// Add element to end
push(arr, 4);
print(arr); // [1, 2, 3, 4]
// Remove and return last element
var last = pop(arr);
print(last); // 4
print(arr); // [1, 2, 3]
Variables
Declaration
var name = "Bob";
var age = 25;
var isActive = true;
Assignment
var x = 10;
x = 20; // Reassignment
Scoping
- Global scope: Variables declared at top level
- Local scope: Variables declared inside functions
- Shadowing: Local variables can shadow global variables
- No
globalkeyword: Unlike Python, Bob doesn't require explicit global declaration
var globalVar = 100;
func testScope() {
var localVar = 50; // Local variable
return localVar + globalVar; // Can access global
}
Assignment System
Bob uses two assignment systems for safety and practicality:
Assignment Statements
- Purpose: Main way to assign values
- Syntax:
variable = value;(with semicolon) - Context: Standalone statements
// Assignment statements (most common)
var x = 5;
x = 10; // Regular assignment
y += 5; // Compound assignment
z *= 2; // Compound assignment
Assignment Expressions (For Loops Only)
- Purpose: For loop clauses only
- Syntax:
variable = value(without semicolon) - Context: For loop initializers and increment clauses
// Assignment expressions (for loops only)
for (var i = 0; i < 5; i = i + 1) { } // Assignment in increment
for (j = 0; j < 5; j += 1) { } // Assignment in initializer and increment
Why This Design?
Prevents Common Bugs:
// This would be a bug in many languages:
if (x = 10) { } // Parse error - assignment in conditional
// Bob forces you to write:
x = 10;
if (x == 10) { } // Clear comparison
Keeps Expressions Pure:
// Prevents side effects in expressions:
var result = (x = 10) + (y = 20); // Parse error
// Forces clean code:
x = 10;
y = 20;
var result = x + y; // Pure expression
What's Blocked:
// These all cause parse errors:
var result = x = 10; // AssignExpr not allowed in expressions
var result = true ? (x = 10) : 0; // AssignExpr not allowed in ternary
var result = func(x = 10); // AssignExpr not allowed in function calls
var result = (x = 10) + 5; // AssignExpr not allowed in arithmetic
Operators
Arithmetic Operators
- Addition:
+ - Subtraction:
- - Multiplication:
* - Division:
/ - Modulo:
%
Compound Assignment Operators
- Add and assign:
+= - Subtract and assign:
-= - Multiply and assign:
*= - Divide and assign:
/= - Modulo and assign:
%=
var x = 10;
x += 5; // x = 15
x -= 3; // x = 12
x *= 2; // x = 24
x /= 4; // x = 6
x %= 4; // x = 2
Increment and Decrement Operators
- Prefix increment:
++x - Postfix increment:
x++ - Prefix decrement:
--x - Postfix decrement:
x--
var x = 5;
print(++x); // 6 (increments first, then prints)
print(x++); // 6 (prints first, then increments)
print(x); // 7
// Works with array elements
var arr = [1, 2, 3];
arr[0]++;
print(arr[0]); // 2
++arr[1];
print(arr[1]); // 3
Comparison Operators
- Equal:
== - Not equal:
!= - Greater than:
> - Less than:
< - Greater than or equal:
>= - Less than or equal:
<=
Cross-Type Comparisons
Bob supports cross-type comparisons with intuitive behavior:
// Equality operators work with any types
print(none == "hello"); // false (different types)
print(42 == "42"); // false (different types)
print(true == true); // true (same type and value)
// Comparison operators only work with numbers
print(5 > 3); // true
print(5 > "3"); // Error: > not supported between number and string
print(none > 5); // Error: > not supported between none and number
Logical Operators
- And:
&& - Or:
|| - Not:
!
Conditional (Ternary) Operator
// Basic ternary operator
var result = condition ? valueIfTrue : valueIfFalse;
// Examples
var max = x > y ? x : y;
var status = age >= 18 ? "adult" : "minor";
var message = x > 0 ? "positive" : "non-positive";
// Ternary with expressions
var result = x + y > 10 ? x * y : x + y;
// Ternary with function calls
var value = condition ? getValue() : getOtherValue();
// Nested ternary expressions
var result = x == 5 ? (y == 10 ? "both true" : "x true") : "x false";
Precedence: The ternary operator has lower precedence than logical operators (&&, ||) but higher than assignment operators.
String Operators
Concatenation
Bob supports bidirectional string + number concatenation with automatic type conversion:
// String + Number
"Hello " + 42; // → "Hello 42"
"Pi: " + 3.14; // → "Pi: 3.14"
// Number + String
42 + " items"; // → "42 items"
3.14 + " is pi"; // → "3.14 is pi"
String Multiplication
"hello" * 3; // → "hellohellohello"
3 * "hello"; // → "hellohellohello"
Note: String multiplication requires whole numbers.
Number Formatting
Bob automatically formats numbers to show only significant digits:
"Count: " + 2.0; // → "Count: 2" (no trailing zeros)
"Pi: " + 3.14; // → "Pi: 3.14" (exact precision)
"Integer: " + 42; // → "Integer: 42" (no decimal)
Control Flow
If Statements
// Basic if statement
if (x > 10) {
print("x is greater than 10");
}
// If-else statement
if (x > 10) {
print("x is greater than 10");
} else {
print("x is 10 or less");
}
// If-else if-else chain
if (x > 10) {
print("x is greater than 10");
} else if (x > 5) {
print("x is greater than 5");
} else {
print("x is 5 or less");
}
While Loops
// Basic while loop
var i = 0;
while (i < 5) {
print(i);
i = i + 1;
}
// While loop with break (using return)
func countToThree() {
var i = 0;
while (true) {
i = i + 1;
if (i > 3) {
return i;
}
}
}
For Loops
// Basic for loop
for (var i = 0; i < 5; i = i + 1) {
print(i);
}
// For loop with no initializer
var j = 0;
for (; j < 3; j = j + 1) {
// Empty body
}
// For loop with no condition (infinite loop with break)
for (var k = 0; ; k = k + 1) {
if (k >= 2) {
break; // or return
}
}
// For loop with no increment
for (var n = 0; n < 3; ) {
n = n + 1;
}
Do-While Loops
// Basic do-while loop
var i = 0;
do {
print(i);
i = i + 1;
} while (i < 5);
// Do-while with break
var j = 0;
do {
j = j + 1;
if (j == 3) {
break;
}
} while (j < 10);
// Do-while with continue
var k = 0;
var sum = 0;
do {
k = k + 1;
if (k == 2) {
continue;
}
sum = sum + k;
} while (k < 5);
Loop Features
- Nested loops: While, for, and do-while loops can be nested
- Complex conditions: Loops support any boolean expression
- Function calls: Loop conditions and bodies can contain function calls
- Return statements: Loops can be exited using return statements
- Break and continue: All loop types support break and continue statements
- Variable scoping: Variables declared in for loop initializers are scoped to the loop
- Do-while behavior: Do-while loops always execute the body at least once before checking the condition
Functions
Function Declaration
func add(a, b) {
return a + b;
}
Function Call
var result = add(2, 3); // result = 5
Parameters
- Any number of parameters supported
- No default parameters (not implemented)
- No keyword arguments (not implemented)
Return Values
- Explicit return:
return value; - Implicit return: Functions return
noneif no return statement - Early return: Functions can return from anywhere
Closures
Bob supports lexical closures with variable capture:
var outerVar = "Outer";
func makeGreeter(greeting) {
return greeting + " " + outerVar;
}
var greeter = makeGreeter("Hello");
// greeter captures outerVar from its lexical scope
Nested Functions
func outer() {
func inner() {
return 42;
}
return inner();
}
Standard Library
Print Function
print("Hello, World!");
print(42);
print(true);
Usage: print(expression)
- Prints the result of any expression
- Automatically converts values to strings
- Adds newline after output
Assert Function
assert(condition, "optional message");
Usage:
assert(true)- passes silentlyassert(false)- throws error and stops executionassert(condition, "message")- includes custom error message
Behavior:
- Terminates program execution on failure
- No exception handling mechanism (yet)
- Useful for testing and validation
Type Function
type(value);
Usage:
- Returns the type of a value as a string
- Returns:
"number","string","boolean","none","array","function"
Examples:
print(type(42)); // "number"
print(type("hello")); // "string"
print(type(true)); // "boolean"
print(type(none)); // "none"
print(type([1, 2, 3])); // "array"
print(type(func() {})); // "function"
ToString Function
toString(value);
Usage:
- Converts any value to a string
- Works with all data types
Examples:
print(toString(42)); // "42"
print(toString(3.14)); // "3.14"
print(toString(true)); // "true"
print(toString([1, 2, 3])); // "[1, 2, 3]"
ToNumber Function
toNumber(value);
Usage:
- Converts a value to a number
- Returns 0 for non-numeric strings
- Returns 0 for boolean false, 1 for boolean true
Examples:
print(toNumber("42")); // 42
print(toNumber("3.14")); // 3.14
print(toNumber("hello")); // 0
print(toNumber(true)); // 1
print(toNumber(false)); // 0
ToInt Function
toInt(value);
Usage:
- Converts a number to an integer (truncates decimal part)
- Throws error for non-numeric values
- Same result as using bitwise OR with 0 (
value | 0)
Examples:
print(toInt(3.7)); // 3
print(toInt(3.2)); // 3
print(toInt(-3.7)); // -3
print(toInt(3.0)); // 3
Input Function
input();
input("prompt");
Usage:
- Reads a line from standard input
- Optional prompt string
- Returns the input as a string
Examples:
var name = input("Enter your name: ");
print("Hello, " + name + "!");
Time Function
time();
Usage:
- Returns current Unix timestamp (seconds since epoch)
- Useful for timing and random seed generation
Examples:
var start = time();
// ... do some work ...
var end = time();
print("Elapsed: " + (end - start) + " seconds");
Sleep Function
sleep(seconds);
Usage:
- Pauses execution for specified number of seconds
- Useful for animations and timing
Examples:
print("Starting...");
sleep(1);
print("One second later...");
PrintRaw Function
printRaw("text");
Usage:
- Prints text without adding a newline
- Supports ANSI escape codes for colors and cursor control
- Useful for animations and formatted output
Examples:
// Simple output
printRaw("Hello");
printRaw(" World"); // Prints: Hello World
// ANSI colors
printRaw("\e[31mRed text\e[0m"); // Red text
printRaw("\e[32mGreen text\e[0m"); // Green text
// Cursor positioning
printRaw("\e[2J"); // Clear screen
printRaw("\e[H"); // Move cursor to top-left
Random Function
random();
Usage:
- Returns a random number between 0.0 and 1.0
- Uses current time as seed
Examples:
var randomValue = random();
print(randomValue); // 0.0 to 1.0
// Generate random integer 1-10
var randomInt = toInt(random() * 10) + 1;
print(randomInt);
Eval Function
eval("code");
Usage:
- Executes Bob code as a string
- Returns the result of the last expression
- Runs in the current scope (can access variables)
Examples:
var x = 10;
var result = eval("x + 5");
print(result); // 15
var code = "2 + 3 * 4";
var result = eval(code);
print(result); // 14
Error Handling
Current Error Types
- Division by zero:
DivisionByZeroError - Type errors:
Operands must be of same type - String multiplication:
String multiplier must be whole number - Assertion failures:
Assertion failed: condition is false
Error Behavior
- No try-catch: Exception handling not implemented
- Program termination: Errors stop execution immediately
- Error messages: Descriptive error messages printed to console
Common Error Scenarios
// Division by zero
10 / 0; // Error: DivisionByZeroError
// Type mismatch
"hello" - "world"; // Error: Cannot use '-' on two strings
// Invalid string multiplication
"hello" * 3.5; // Error: String multiplier must be whole number
// Undefined variable
undefinedVar; // Error: Undefined variable
Examples
Basic Calculator
func add(a, b) {
return a + b;
}
func multiply(a, b) {
return a * b;
}
var result = add(5, multiply(3, 4));
print("Result: " + result); // Result: 17
String Processing
func greet(name) {
return "Hello, " + name + "!";
}
func repeat(str, count) {
return str * count;
}
var greeting = greet("Bob");
var repeated = repeat("Ha", 3);
print(greeting + " " + repeated); // Hello, Bob! HaHaHa
Variable Scoping Example
var globalCounter = 0;
func increment() {
var localCounter = 1;
globalCounter = globalCounter + localCounter;
return globalCounter;
}
print("Before: " + globalCounter); // Before: 0
increment();
print("After: " + globalCounter); // After: 1
Loop Examples
// Count from 1 to 5
for (var i = 1; i <= 5; i = i + 1) {
print("Count: " + i);
}
// Sum numbers from 1 to 10
var sum = 0;
for (var j = 1; j <= 10; j = j + 1) {
sum = sum + j;
}
print("Sum: " + sum);
// Find first even number
var k = 1;
while (k % 2 != 0) {
k = k + 1;
}
print("First even: " + k);
Implementation Details
Assignment System: Statements vs Expressions
Bob uses a dual assignment system to prevent common programming errors:
Assignment Statements (general use):
var x = 10;
x = 20; // This is a statement, not an expression
Assignment Expressions (for loops only):
for (var i = 0; i < 10; i = i + 1) { // Assignment in increment clause
print(i);
}
Why This Design?
- Prevents
if (x = 10)bugs: Assignment statements can't be used in conditions - Maintains loop functionality: For loops still work with assignment expressions
- Clear intent: Distinguishes between intentional assignments and accidental ones
Memory Management
Bob uses automatic memory management with conservative cleanup:
Reference Counting:
- All objects use
std::shared_ptrfor automatic cleanup - Functions and thunks are tracked by reference count
- Objects are freed when no longer referenced
Automatic Cleanup:
- Functions created in loops are automatically cleaned up when unused
- Cleanup occurs every 1000 function/thunk creations
- Only removes objects with
use_count() == 1(conservative approach)
Safety Guarantees:
- Functions referenced anywhere are never cleaned up
- Only truly unused functions are removed
- No dangling pointers or memory corruption
This documentation covers the current Bob language implementation. For development plans, see ROADMAP.md.