Files
zxq5 5e575e2cd8 used claude to write a language spec (syntax and simple examples) for
DSC that we can follow as a reference for implementation.
2026-02-10 10:05:13 +00:00

1224 lines
24 KiB
Markdown

# DSC Language Specification v1.0
**Damn Simple C (DSC)** - A systems programming language for the DSA architecture
---
## Table of Contents
1. [Introduction](#introduction)
2. [Lexical Structure](#lexical-structure)
3. [Types](#types)
4. [Variables and Declarations](#variables-and-declarations)
5. [Classes](#classes)
6. [Functions](#functions)
7. [Expressions](#expressions)
8. [Statements](#statements)
9. [Control Flow](#control-flow)
10. [Memory Management](#memory-management)
11. [Generics](#generics)
12. [Modules and Imports](#modules-and-imports)
13. [Keywords](#keywords)
14. [Operators](#operators)
15. [Complete Example Programs](#complete-example-programs)
16. [Grammar Summary](#grammar-summary)
17. [Appendix A: Differences from Rust](#appendix-a-differences-from-rust)
18. [Appendix B: Standard Library Conventions](#appendix-b-standard-library-conventions)
---
## 1. Introduction
DSC is a statically-typed systems programming language designed for the DSA (Damn Simple Architecture). It combines modern syntax with explicit memory management and direct assembly interoperability.
### Design Goals
- **Explicit**: No hidden control flow or implicit conversions
- **Simple**: Easy to understand what the compiler generates
- **Safe**: Scope-based resource management via `defer`
- **Interoperable**: Direct assembly library integration
---
## 2. Lexical Structure
### 2.1 Comments
```rust
// Single-line comment
/* Multi-line
comment */
```
### 2.2 Identifiers
Identifiers must start with a letter or underscore, followed by any number of letters, digits, or underscores.
```rust
valid_identifier
_private
MyClass
get_value_42
```
### 2.3 Reserved Keywords
```
as break class const continue
defer else false field fn
if impl include let loop
mut priv pub return self
static struct true void while
```
### 2.4 Literals
#### Integer Literals
```rust
42 // Decimal
0x2A // Hexadecimal
0b101010 // Binary
0o52 // Octal
```
#### String Literals
```rust
"Hello, world!"
"Escape sequences: \n \t \\ \""
```
#### Boolean Literals
```rust
true
false
```
---
## 3. Types
### 3.1 Primitive Types
#### Integer Types
```rust
i8 // Signed 8-bit integer
i16 // Signed 16-bit integer
i32 // Signed 32-bit integer
i64 // Signed 64-bit integer
u8 // Unsigned 8-bit integer
u16 // Unsigned 16-bit integer
u32 // Unsigned 32-bit integer
u64 // Unsigned 64-bit integer
```
#### Boolean Type
```rust
bool // true or false
```
#### String Type
```rust
str // String literal type (pointer to null-terminated byte array)
```
#### Void Type
```rust
void // Absence of a value (only valid as return type)
```
### 3.2 Pointer Types
Pointers are declared using the `&` prefix:
```rust
&u32 // Pointer to u32
&bool // Pointer to bool
&Point // Pointer to Point class
```
**Note**: Pointers in DSC are raw memory addresses (like C pointers), not Rust-style references with borrow checking.
### 3.3 Array Types
```rust
[u32; 10] // Fixed-size array of 10 u32 values
[bool; 256] // Fixed-size array of 256 bool values
```
### 3.4 Generic Types
```rust
Vec<u32> // Generic type with one type parameter
Map<str, i32> // Generic type with multiple type parameters
```
---
## 4. Variables and Declarations
### 4.1 Variable Declaration
Variables are declared with `let` and are immutable by default:
```rust
let x: u32 = 42;
let name: str = "Alice";
let ptr: &u32 = &x;
```
### 4.2 Mutable Variables
Use `mut` to declare mutable variables:
```rust
let mut count: u32 = 0;
count = count + 1;
```
### 4.3 Type Inference
Type annotations can be omitted when the type can be inferred:
```rust
let x = 42; // Inferred as u32 (default integer type)
let name = "Bob"; // Inferred as str
```
---
## 5. Classes
Classes are DSC's primary means of encapsulation, combining data and behavior.
### 5.1 Class Definition
```rust
class ClassName {
// Class body
}
```
### 5.2 Fields
Fields represent the data members of a class. They must be explicitly marked as `pub` or `priv`:
```rust
class Point {
pub field x: u32;
pub field y: u32;
priv field cached: bool;
}
```
**Syntax**: `[pub|priv] field <name>: <type>;`
### 5.3 Constants
Constants are compile-time values associated with a class:
```rust
class Math {
pub const PI: u32 = 3;
pub const E: u32 = 2;
priv const INTERNAL_CONSTANT: u32 = 42;
}
```
**Syntax**: `[pub|priv] const <NAME>: <type> = <value>;`
**Usage**: `Math::PI`
### 5.4 Static Fields
Static fields are global variables associated with a class:
```rust
class Logger {
pub static mut INSTANCE_COUNT: u32 = 0;
priv static mut INTERNAL_STATE: u32 = 0;
}
```
**Syntax**: `[pub|priv] static mut <name>: <type> = <value>;`
**Usage**:
```rust
Logger::INSTANCE_COUNT = Logger::INSTANCE_COUNT + 1;
```
**Note**: All static fields must be declared `mut` as they represent mutable global state.
### 5.5 Methods
Methods are functions associated with a class. Instance methods take a `self` parameter:
```rust
class Point {
pub field x: u32;
pub field y: u32;
// Constructor (static method)
pub fn new(x: u32, y: u32) -> Point {
return Point { x: x, y: y };
}
// Instance method
pub fn get_x(self: &Point) -> u32 {
return self.x;
}
// Mutable instance method
pub fn set_x(self: &Point, value: u32) {
self.x = value;
}
// Static method
pub fn zero() -> Point {
return Point { x: 0, y: 0 };
}
}
```
**Method Syntax**:
- Instance method: `[pub|priv] fn <name>(self: &<ClassName>, ...) -> <return_type>`
- Static method: `[pub|priv] fn <name>(...) -> <return_type>`
### 5.6 Class Instantiation
```rust
// Using constructor
let p1: Point = Point::new(10, 20);
// Using struct literal syntax
let p2: Point = Point { x: 5, y: 15 };
```
### 5.7 Method Calls
```rust
let p: Point = Point::new(10, 20);
// Method call syntax (preferred)
let x: u32 = p.get_x();
// Explicit syntax (equivalent)
let x: u32 = Point::get_x(&p);
// Static method call
let origin: Point = Point::zero();
```
### 5.8 Field Access
```rust
let p: Point = Point { x: 10, y: 20 };
// Read field
let x: u32 = p.x;
// Write field (if mutable)
let mut p2: Point = Point { x: 0, y: 0 };
p2.x = 42;
```
### 5.9 Complete Class Example
```rust
class Vec {
priv field data: &u32;
priv field len: u32;
priv field capacity: u32;
pub const DEFAULT_CAPACITY: u32 = 16;
pub static mut TOTAL_ALLOCATIONS: u32 = 0;
pub fn new(capacity: u32) -> Vec {
Vec::TOTAL_ALLOCATIONS = Vec::TOTAL_ALLOCATIONS + 1;
return Vec {
data: alloc::malloc(capacity * 4) as &u32,
len: 0,
capacity: capacity
};
}
pub fn with_default_capacity() -> Vec {
return Vec::new(Vec::DEFAULT_CAPACITY);
}
pub fn push(self: &Vec, item: u32) {
if self.len == self.capacity {
self.grow();
}
*(self.data + self.len) = item;
self.len = self.len + 1;
}
pub fn get(self: &Vec, index: u32) -> u32 {
return *(self.data + index);
}
priv fn grow(self: &Vec) {
let new_capacity: u32 = self.capacity * 2;
let new_data: &u32 = alloc::malloc(new_capacity * 4) as &u32;
// Copy old data
let mut i: u32 = 0;
while i < self.len {
*(new_data + i) = *(self.data + i);
i = i + 1;
}
alloc::free(self.data as u32);
self.data = new_data;
self.capacity = new_capacity;
}
pub fn drop(self: &Vec) {
alloc::free(self.data as u32);
}
}
```
---
## 6. Functions
### 6.1 Function Declaration
```rust
fn function_name(param1: Type1, param2: Type2) -> ReturnType {
// Function body
}
```
### 6.2 Return Type
Functions without a return value use `void` or omit the return type:
```rust
fn print_message(msg: str) -> void {
// No return value
}
// Equivalent
fn print_message(msg: str) {
// No return value
}
```
### 6.3 Return Statement
```rust
fn add(a: u32, b: u32) -> u32 {
return a + b;
}
```
### 6.4 Function Parameters
```rust
fn process(value: u32, ptr: &u32, flag: bool) -> u32 {
// ...
}
```
---
## 7. Expressions
### 7.1 Literals
```rust
42 // Integer literal
0xFF // Hex literal
true // Boolean literal
"hello" // String literal
```
### 7.2 Binary Operations
```rust
a + b // Addition
a - b // Subtraction
a * b // Multiplication
a / b // Division
a % b // Modulo
```
### 7.3 Comparison Operations
```rust
a == b // Equal
a != b // Not equal
a < b // Less than
a > b // Greater than
a <= b // Less than or equal
a >= b // Greater than or equal
```
### 7.4 Logical Operations
```rust
a && b // Logical AND
a || b // Logical OR
!a // Logical NOT
```
### 7.5 Bitwise Operations
```rust
a & b // Bitwise AND
a | b // Bitwise OR
a ^ b // Bitwise XOR
~a // Bitwise NOT
a << b // Left shift
a >> b // Right shift
```
### 7.6 Address-of and Dereference
```rust
&x // Address-of (get pointer to x)
*ptr // Dereference (read/write through pointer)
```
### 7.7 Type Casting
```rust
value as u32 // Cast value to u32
ptr as &u8 // Cast pointer type
```
### 7.8 Field Access
```rust
obj.field // Access field of object
ptr.field // Access field through pointer (implicit dereference)
```
### 7.9 Method Call
```rust
obj.method(args) // Instance method call
Class::method(args) // Static method call
```
### 7.10 Array Indexing
```rust
arr[index] // Access array element
```
---
## 8. Statements
### 8.1 Expression Statement
```rust
function_call();
x = y + 1;
```
### 8.2 Variable Declaration
```rust
let x: u32 = 42;
let mut y: u32 = 0;
```
### 8.3 Assignment
```rust
x = 10;
*ptr = 20;
obj.field = 30;
arr[0] = 40;
```
### 8.4 Compound Assignment
```rust
x += 5; // x = x + 5
x -= 3; // x = x - 3
x *= 2; // x = x * 2
x /= 4; // x = x / 4
```
---
## 9. Control Flow
### 9.1 If Statement
```rust
if condition {
// then block
}
if condition {
// then block
} else {
// else block
}
if condition1 {
// block 1
} else if condition2 {
// block 2
} else {
// block 3
}
```
### 9.2 While Loop
```rust
while condition {
// loop body
}
```
### 9.3 Loop (Infinite Loop)
```rust
loop {
// infinite loop
if should_exit {
break;
}
}
```
### 9.4 Break and Continue
```rust
while condition {
if skip_condition {
continue; // Skip to next iteration
}
if exit_condition {
break; // Exit loop
}
}
```
---
## 10. Memory Management
### 10.1 Defer Statement
The `defer` keyword schedules a statement to execute when the current scope exits.
```rust
fn example() {
let ptr: u32 = alloc::malloc(256);
defer alloc::free(ptr);
// Use ptr...
if error {
return; // defer runs here
}
// More work...
} // defer runs here
```
### 10.2 Defer Execution Rules
1. **Scope-based**: Defers execute when their enclosing scope exits
2. **LIFO order**: Multiple defers execute in reverse order of declaration
3. **All exit paths**: Defers run on return, break, continue, or natural scope end
```rust
fn nested_defers() {
let a: u32 = alloc::malloc(100);
defer alloc::free(a); // Runs second
if condition {
let b: u32 = alloc::malloc(200);
defer alloc::free(b); // Runs first (if in this scope)
// ... work ...
} // b's defer runs here
// ... more work ...
} // a's defer runs here
```
### 10.3 Defer with Methods
```rust
class Resource {
priv field handle: u32;
pub fn acquire() -> Resource {
return Resource { handle: alloc::malloc(1024) };
}
pub fn release(self: &Resource) {
alloc::free(self.handle);
}
}
fn use_resource() {
let res: Resource = Resource::acquire();
defer res.release();
// Use resource...
} // res.release() automatically called
```
---
## 11. Generics
### 11.1 Generic Classes
```rust
class Box<T> {
priv field value: T;
pub fn new(value: T) -> Box<T> {
return Box { value: value };
}
pub fn get(self: &Box<T>) -> T {
return self.value;
}
pub fn set(self: &Box<T>, value: T) {
self.value = value;
}
}
```
### 11.2 Generic Usage
```rust
let int_box: Box<u32> = Box::new(42);
let str_box: Box<str> = Box::new("hello");
let value: u32 = int_box.get();
```
### 11.3 Multiple Type Parameters
```rust
class Pair<T, U> {
pub field first: T;
pub field second: U;
pub fn new(first: T, second: U) -> Pair<T, U> {
return Pair { first: first, second: second };
}
}
let p: Pair<u32, str> = Pair::new(42, "answer");
```
### 11.4 Generic Functions
```rust
fn swap<T>(a: &T, b: &T) {
let temp: T = *a;
*a = *b;
*b = temp;
}
let mut x: u32 = 1;
let mut y: u32 = 2;
swap(&x, &y);
```
### 11.5 Generic Constraints
**Note**: DSC does not support trait bounds or where clauses. Generic types are instantiated via monomorphization without constraints.
---
## 12. Modules and Imports
### 12.1 Assembly Imports
DSC can import assembly modules for low-level operations:
```rust
include print: "./lib/io/print.dsa";
include alloc: "./lib/memory/alloc.dsa";
```
**Syntax**: `include <namespace>: "<path>";`
### 12.2 Using Imported Functions
```rust
print::println("Hello, world!");
let ptr: u32 = alloc::malloc(256);
```
---
## 13. Keywords
### 13.1 Complete Keyword List
| Keyword | Purpose |
|---------|---------|
| `as` | Type casting |
| `break` | Exit loop |
| `class` | Class definition |
| `const` | Constant declaration |
| `continue` | Next loop iteration |
| `defer` | Defer statement execution |
| `else` | Alternative branch |
| `false` | Boolean literal |
| `field` | Class field declaration |
| `fn` | Function declaration |
| `if` | Conditional statement |
| `impl` | *Reserved for future use* |
| `include` | Import assembly module |
| `let` | Variable declaration |
| `loop` | Infinite loop |
| `mut` | Mutable binding |
| `priv` | Private visibility |
| `pub` | Public visibility |
| `return` | Return from function |
| `self` | Instance reference |
| `static` | Static field declaration |
| `struct` | *Reserved for future use* |
| `true` | Boolean literal |
| `void` | No return type |
| `while` | While loop |
---
## 14. Operators
### 14.1 Operator Precedence (Highest to Lowest)
| Precedence | Operators | Associativity |
|------------|-----------|---------------|
| 1 | `()` `[]` `.` `::` | Left to right |
| 2 | `!` `~` `&` `*` (unary) `-` (unary) | Right to left |
| 3 | `as` | Left to right |
| 4 | `*` `/` `%` | Left to right |
| 5 | `+` `-` | Left to right |
| 6 | `<<` `>>` | Left to right |
| 7 | `&` | Left to right |
| 8 | `^` | Left to right |
| 9 | `|` | Left to right |
| 10 | `==` `!=` `<` `>` `<=` `>=` | Left to right |
| 11 | `&&` | Left to right |
| 12 | `||` | Left to right |
| 13 | `=` `+=` `-=` `*=` `/=` | Right to left |
### 14.2 Operator Summary
#### Arithmetic Operators
```rust
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulo
```
#### Comparison Operators
```rust
== Equal
!= Not equal
< Less than
> Greater than
<= Less than or equal
>= Greater than or equal
```
#### Logical Operators
```rust
&& Logical AND
|| Logical OR
! Logical NOT
```
#### Bitwise Operators
```rust
& Bitwise AND
| Bitwise OR
^ Bitwise XOR
~ Bitwise NOT
<< Left shift
>> Right shift
```
#### Memory Operators
```rust
& Address-of
* Dereference
```
#### Assignment Operators
```rust
= Assignment
+= Add and assign
-= Subtract and assign
*= Multiply and assign
/= Divide and assign
```
---
## 15. Complete Example Programs
### 15.1 Hello World
```rust
include print: "./lib/io/print.dsa";
fn main() -> void {
print::println("Hello, world!");
}
```
### 15.2 Vector Implementation
```rust
include alloc: "./lib/memory/alloc.dsa";
class Vec<T> {
priv field data: &T;
priv field len: u32;
priv field capacity: u32;
pub const DEFAULT_CAPACITY: u32 = 16;
pub fn new(capacity: u32) -> Vec<T> {
let size: u32 = capacity * 4; // Assume sizeof(T) = 4
return Vec {
data: alloc::malloc(size) as &T,
len: 0,
capacity: capacity
};
}
pub fn push(self: &Vec<T>, item: T) {
if self.len >= self.capacity {
self.resize();
}
*(self.data + self.len) = item;
self.len = self.len + 1;
}
pub fn get(self: &Vec<T>, index: u32) -> T {
return *(self.data + index);
}
pub fn len(self: &Vec<T>) -> u32 {
return self.len;
}
priv fn resize(self: &Vec<T>) {
let new_capacity: u32 = self.capacity * 2;
let new_size: u32 = new_capacity * 4;
let new_data: &T = alloc::malloc(new_size) as &T;
let mut i: u32 = 0;
while i < self.len {
*(new_data + i) = *(self.data + i);
i = i + 1;
}
alloc::free(self.data as u32);
self.data = new_data;
self.capacity = new_capacity;
}
pub fn drop(self: &Vec<T>) {
alloc::free(self.data as u32);
}
}
fn main() -> void {
let vec: Vec<u32> = Vec::new(10);
defer vec.drop();
vec.push(1);
vec.push(2);
vec.push(3);
let mut i: u32 = 0;
while i < vec.len() {
let value: u32 = vec.get(i);
// Use value...
i = i + 1;
}
}
```
### 15.3 Resource Management Example
```rust
include alloc: "./lib/memory/alloc.dsa";
include print: "./lib/io/print.dsa";
class File {
priv field handle: u32;
priv field is_open: bool;
pub fn open(path: str) -> File {
let handle: u32 = 0; // Platform-specific open
return File { handle: handle, is_open: true };
}
pub fn write(self: &File, data: str) {
if !self.is_open {
return;
}
// Write implementation...
}
pub fn close(self: &File) {
if self.is_open {
// Platform-specific close
self.is_open = false;
}
}
}
fn process_file(path: str) -> bool {
let file: File = File::open(path);
defer file.close(); // Ensures file is closed on all exit paths
let buffer: u32 = alloc::malloc(1024);
defer alloc::free(buffer);
if !file.is_open {
print::println("Failed to open file");
return false; // Defers run: free(buffer), file.close()
}
file.write("Hello, file!");
return true; // Defers run: free(buffer), file.close()
}
fn main() -> void {
let success: bool = process_file("output.txt");
if success {
print::println("File processed successfully");
} else {
print::println("File processing failed");
}
}
```
---
## 16. Grammar Summary
### 16.1 EBNF Grammar
```ebnf
program = { import_statement | class_definition | function_definition }
import_statement = "include" identifier ":" string_literal ";"
class_definition = "class" identifier [ generic_params ] "{" { class_member } "}"
class_member = field_declaration
| const_declaration
| static_declaration
| method_declaration
field_declaration = visibility "field" identifier ":" type ";"
const_declaration = visibility "const" IDENTIFIER ":" type "=" expression ";"
static_declaration = visibility "static" "mut" identifier ":" type "=" expression ";"
method_declaration = visibility "fn" identifier [ generic_params ] "(" parameters ")" [ "->" type ] block
function_definition = "fn" identifier [ generic_params ] "(" parameters ")" [ "->" type ] block
generic_params = "<" identifier { "," identifier } ">"
parameters = [ parameter { "," parameter } ]
parameter = identifier ":" type
visibility = "pub" | "priv"
type = primitive_type
| pointer_type
| array_type
| generic_type
| identifier
primitive_type = "u8" | "u16" | "u32" | "u64"
| "i8" | "i16" | "i32" | "i64"
| "bool" | "str" | "void"
pointer_type = "&" type
array_type = "[" type ";" integer_literal "]"
generic_type = identifier "<" type { "," type } ">"
block = "{" { statement } "}"
statement = let_statement
| expression_statement
| if_statement
| while_statement
| loop_statement
| return_statement
| defer_statement
| break_statement
| continue_statement
let_statement = "let" [ "mut" ] identifier ":" type "=" expression ";"
defer_statement = "defer" expression ";"
if_statement = "if" expression block [ "else" ( if_statement | block ) ]
while_statement = "while" expression block
loop_statement = "loop" block
return_statement = "return" [ expression ] ";"
break_statement = "break" ";"
continue_statement = "continue" ";"
expression_statement = expression ";"
expression = assignment_expression
assignment_expression = logical_or_expression [ assignment_operator assignment_expression ]
assignment_operator = "=" | "+=" | "-=" | "*=" | "/="
logical_or_expression = logical_and_expression { "||" logical_and_expression }
logical_and_expression = equality_expression { "&&" equality_expression }
equality_expression = relational_expression { equality_operator relational_expression }
equality_operator = "==" | "!="
relational_expression = bitwise_or_expression { relational_operator bitwise_or_expression }
relational_operator = "<" | ">" | "<=" | ">="
bitwise_or_expression = bitwise_xor_expression { "|" bitwise_xor_expression }
bitwise_xor_expression = bitwise_and_expression { "^" bitwise_and_expression }
bitwise_and_expression = shift_expression { "&" shift_expression }
shift_expression = additive_expression { shift_operator additive_expression }
shift_operator = "<<" | ">>"
additive_expression = multiplicative_expression { additive_operator multiplicative_expression }
additive_operator = "+" | "-"
multiplicative_expression = cast_expression { multiplicative_operator cast_expression }
multiplicative_operator = "*" | "/" | "%"
cast_expression = unary_expression [ "as" type ]
unary_expression = postfix_expression
| unary_operator unary_expression
unary_operator = "!" | "~" | "&" | "*" | "-"
postfix_expression = primary_expression { postfix_operator }
postfix_operator = "." identifier [ call_suffix ]
| "::" identifier [ call_suffix ]
| "[" expression "]"
| call_suffix
call_suffix = "(" [ arguments ] ")"
arguments = expression { "," expression }
primary_expression = identifier
| literal
| "(" expression ")"
| struct_literal
struct_literal = identifier "{" [ field_init { "," field_init } ] "}"
field_init = identifier ":" expression
literal = integer_literal
| string_literal
| boolean_literal
boolean_literal = "true" | "false"
```
---
## Appendix A: Differences from Rust
While DSC uses Rust-like syntax, there are key differences:
| Feature | Rust | DSC |
|---------|------|-----|
| **Encapsulation** | `struct` + `impl` | `class` |
| **Field syntax** | `field: Type` | `field field: Type;` |
| **References** | Borrow-checked `&T` | Raw pointers `&T` |
| **Ownership** | Compile-time borrow checker | Manual with `defer` |
| **Traits** | Supported | Not supported |
| **Lifetimes** | Supported | Not supported |
| **Pattern matching** | Supported | Not supported |
| **Enums** | Sum types with data | Not yet supported |
| **Modules** | Native | Assembly imports only |
---
## Appendix B: Standard Library Conventions
By convention, standard library modules should provide:
### Allocation Module (`alloc`)
```rust
include alloc: "./lib/memory/alloc.dsa";
// Functions:
// alloc::malloc(size: u32) -> u32
// alloc::free(ptr: u32) -> void
```
### Print Module (`print`)
```rust
include print: "./lib/io/print.dsa";
// Functions:
// print::print(msg: str) -> void
// print::println(msg: str) -> void
// print::print_num(n: u32) -> void
// print::print_hex(n: u32) -> void
```
---
*End of DSC Language Specification v1.0*