- Add while, for, and do-while loops with break/continue - Implement assignment statements (prevents if(x=10) bugs) - Keep assignment expressions only for for-loop clauses - Fix critical memory management bug (dangling pointers in cleanup) - Add automatic memory cleanup with conservative reference counting - Consolidate documentation into single reference file - Add comprehensive test coverage for all loop types and edge cases - VSCode extension for bob highlighting and snippets
570 lines
12 KiB
Markdown
570 lines
12 KiB
Markdown
# 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
|
|
|
|
1. [Getting Started](#getting-started)
|
|
2. [Basic Syntax](#basic-syntax)
|
|
3. [Data Types](#data-types)
|
|
4. [Variables](#variables)
|
|
5. [Operators](#operators)
|
|
6. [Control Flow](#control-flow)
|
|
7. [Functions](#functions)
|
|
8. [Standard Library](#standard-library)
|
|
9. [Error Handling](#error-handling)
|
|
10. [Examples](#examples)
|
|
|
|
## Getting Started
|
|
|
|
### Running Bob Code
|
|
```bash
|
|
# 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 `.bob` files
|
|
|
|
## Basic Syntax
|
|
|
|
### Statements
|
|
- **Semicolons**: Required at end of statements
|
|
- **Parentheses**: Required for function calls
|
|
- **Curly braces**: Required for function bodies
|
|
- **Case sensitive**: `var` and `Var` are different
|
|
|
|
### Comments
|
|
```go
|
|
// 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)
|
|
|
|
## Variables
|
|
|
|
### Declaration
|
|
```go
|
|
var name = "Bob";
|
|
var age = 25;
|
|
var isActive = true;
|
|
```
|
|
|
|
### Assignment
|
|
```go
|
|
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 `global` keyword**: Unlike Python, Bob doesn't require explicit global declaration
|
|
|
|
```go
|
|
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
|
|
|
|
```go
|
|
// 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
|
|
|
|
```go
|
|
// 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:**
|
|
```go
|
|
// 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:**
|
|
```go
|
|
// 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:**
|
|
```go
|
|
// 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**: `%`
|
|
|
|
### Comparison Operators
|
|
- **Equal**: `==`
|
|
- **Not equal**: `!=`
|
|
- **Greater than**: `>`
|
|
- **Less than**: `<`
|
|
- **Greater than or equal**: `>=`
|
|
- **Less than or equal**: `<=`
|
|
|
|
### Logical Operators
|
|
- **And**: `&&`
|
|
- **Or**: `||`
|
|
- **Not**: `!`
|
|
|
|
### Conditional (Ternary) Operator
|
|
```go
|
|
// 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:
|
|
|
|
```go
|
|
// 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
|
|
```go
|
|
"hello" * 3; // → "hellohellohello"
|
|
3 * "hello"; // → "hellohellohello"
|
|
```
|
|
|
|
**Note**: String multiplication requires whole numbers.
|
|
|
|
### Number Formatting
|
|
Bob automatically formats numbers to show only significant digits:
|
|
|
|
```go
|
|
"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
|
|
```go
|
|
// 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
|
|
```go
|
|
// 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
|
|
```go
|
|
// 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
|
|
```go
|
|
// 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
|
|
```go
|
|
func add(a, b) {
|
|
return a + b;
|
|
}
|
|
```
|
|
|
|
### Function Call
|
|
```go
|
|
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 `none` if no return statement
|
|
- **Early return**: Functions can return from anywhere
|
|
|
|
### Closures
|
|
Bob supports lexical closures with variable capture:
|
|
|
|
```go
|
|
var outerVar = "Outer";
|
|
|
|
func makeGreeter(greeting) {
|
|
return greeting + " " + outerVar;
|
|
}
|
|
|
|
var greeter = makeGreeter("Hello");
|
|
// greeter captures outerVar from its lexical scope
|
|
```
|
|
|
|
### Nested Functions
|
|
```go
|
|
func outer() {
|
|
func inner() {
|
|
return 42;
|
|
}
|
|
return inner();
|
|
}
|
|
```
|
|
|
|
## Standard Library
|
|
|
|
### Print Function
|
|
```go
|
|
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
|
|
```go
|
|
assert(condition, "optional message");
|
|
```
|
|
|
|
**Usage**:
|
|
- `assert(true)` - passes silently
|
|
- `assert(false)` - throws error and stops execution
|
|
- `assert(condition, "message")` - includes custom error message
|
|
|
|
**Behavior**:
|
|
- Terminates program execution on failure
|
|
- No exception handling mechanism (yet)
|
|
- Useful for testing and validation
|
|
|
|
## 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
|
|
```go
|
|
// 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
|
|
```go
|
|
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
|
|
```go
|
|
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
|
|
```go
|
|
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
|
|
```go
|
|
// 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):
|
|
```go
|
|
var x = 10;
|
|
x = 20; // This is a statement, not an expression
|
|
```
|
|
|
|
**Assignment Expressions** (for loops only):
|
|
```go
|
|
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_ptr` for 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.* |