287 lines
7.4 KiB
Markdown
287 lines
7.4 KiB
Markdown
# The `artichoke` Programming Language: A Technical Overview
|
|
|
|
## 1. Introduction
|
|
|
|
`artichoke` is a statically-typed, general-purpose programming language designed
|
|
with an emphasis on performance, safety, and expressive syntax. It combines
|
|
low-level control over memory with modern, high-level features like generics,
|
|
algebraic data types, and integrated error handling. This document provides an
|
|
overview of the language's features as defined by its core grammar.
|
|
|
|
Is highly inspired by C, C++, Rust, and mostly Zig.
|
|
|
|
## 2. Basic Syntax & Structure
|
|
|
|
### Modules, Imports, and Aliases
|
|
|
|
`artichoke` code is organized into modules. The `import` statement is used to bring
|
|
symbols from other modules into the current scope.
|
|
|
|
* **Importing a specific element:** `import my_module::some_function;`
|
|
* **Importing all direct elements of a module:** `import std::*;`
|
|
* **Importing an entire submodule:** `import std::memory;`
|
|
|
|
The `using` keyword creates a local, more convenient alias for a type, function,
|
|
or module name.
|
|
|
|
```
|
|
using mem = std::memory;
|
|
using FileHandle = std::fs::File;
|
|
```
|
|
|
|
### Comments
|
|
|
|
The language uses C-style block comments.
|
|
|
|
```
|
|
/* This is a multi-line
|
|
comment. */
|
|
```
|
|
|
|
## 3. The Type System
|
|
|
|
`artichoke`'s type system is strong and static, with a rich set of features for
|
|
defining complex data structures.
|
|
|
|
### Type Qualifiers
|
|
|
|
Qualifiers modify the type to their immediate right, allowing for precise and
|
|
complex type definitions.
|
|
|
|
* **`*` (Pointer):** Creates a pointer to a type. Pointers cannot be `null`.
|
|
* **`$` (Mutable):** Marks a type as mutable. This is used for function
|
|
parameters, local variables, and struct fields to allow modification.
|
|
* **`?` (Optional):** Marks a type as nullable. An optional type can hold either a
|
|
value of its underlying type or `null`.
|
|
* **`[]` (Slice):** A "fat pointer" representing a view into a contiguous
|
|
sequence of elements. It contains both a pointer to the data and a length.
|
|
|
|
These qualifiers can be combined. For example, `*$?int` defines a **pointer to a
|
|
mutable optional integer**.
|
|
|
|
### Generics
|
|
|
|
Generics allow for writing flexible, reusable code that can operate on multiple
|
|
types. They are defined using `<typename T>`.
|
|
|
|
```
|
|
/* A generic struct */
|
|
struct Point<typename T> {
|
|
x: T,
|
|
y: T
|
|
}
|
|
|
|
/* A generic function */
|
|
fn scale<typename T>(lhs: *Point<T>, rhs: T) -> Point {
|
|
/* ... */
|
|
}
|
|
```
|
|
|
|
|
|
## 4. Declarations
|
|
|
|
### Variables
|
|
|
|
Variables are declared using the `let` (mutable) and `def` (immutable/constant)
|
|
keywords.
|
|
|
|
* **Type inference** is supported when the type can be determined from the initializer.
|
|
* Variables must be initialized with either a type, a value, or both.
|
|
|
|
```
|
|
/* Mutable variable with explicit type */
|
|
let x: i32 = 10;
|
|
|
|
/* Immutable variable with type inference */
|
|
def do_you_get_it = meaning_of_life();
|
|
```
|
|
|
|
### Structs
|
|
|
|
Structs are composite data types that group together variables under one name.
|
|
They support generics.
|
|
|
|
```
|
|
struct Rectangle {
|
|
top: Point<i32>,
|
|
bot: Point<i32>
|
|
}
|
|
```
|
|
|
|
**Initialization:** Structs can be initialized using positional or named fields,
|
|
but not a mix of both.
|
|
|
|
```
|
|
/* Positional initialization */
|
|
def top_left = Point<i32>{ 0, 10 };
|
|
|
|
/* Named-field initialization */
|
|
def top_right = Point<i32>{ x: 10, y: 10 };
|
|
```
|
|
|
|
### Enums (Tagged Unions)
|
|
|
|
Enums define a type that can be one of several different variants. Variants can
|
|
optionally hold data.
|
|
|
|
```
|
|
enum AssetType {
|
|
Texture,
|
|
Model,
|
|
Sound,
|
|
}
|
|
|
|
enum Result<typename T, typename E> {
|
|
Ok(T),
|
|
Err(E)
|
|
}
|
|
```
|
|
|
|
**Initialization:** Enum variants are accessed using scope resolution (`::`).
|
|
|
|
```
|
|
def my_asset = AssetType::Texture;
|
|
def success = Result<i32, string>::Ok(100);
|
|
```
|
|
|
|
### Functions
|
|
|
|
Functions are defined with the fn keyword. The return type is specified after
|
|
the parameter list with `->`.
|
|
|
|
```
|
|
fn meaning_of_life() -> i32 {
|
|
return 42;
|
|
}
|
|
```
|
|
|
|
#### Member Functions (`this` parameter)
|
|
|
|
If the first parameter of a function is declared with the `this` keyword, it can
|
|
be called using "member function" syntax.
|
|
|
|
```
|
|
/* Definition */
|
|
fn add<typename T>(this *$Point<T>, other: *Point<T>) {
|
|
this->x += other->x;
|
|
this->y += other->y;
|
|
}
|
|
|
|
/* Can be called in two ways: */
|
|
/* Member function syntax */
|
|
my_point.add(&other_point);
|
|
|
|
/* Normal function syntax */
|
|
add(&my_point, &other_point);
|
|
```
|
|
|
|
## 5. Control Flow
|
|
|
|
### `if`/`else` Statements
|
|
|
|
`artichoke` supports C-style `if`/`else` and `else if` chains. It also integrates a
|
|
powerful unwrapping feature for handling `Result` and optional (`?`) types.
|
|
|
|
```
|
|
|
|
/* Standard if/else */
|
|
if (argc < 2) {
|
|
return Result::Err(-1);
|
|
}
|
|
|
|
/* Unwrapping a Result */
|
|
if (foo()) |ok| {
|
|
/* `ok` holds the success value */
|
|
}
|
|
else |err| {
|
|
/* `err` holds the error value */
|
|
}
|
|
```
|
|
|
|
### Loops
|
|
|
|
The language provides a comprehensive set of looping constructs.
|
|
|
|
* **C-Style `for`:** `for (let i \= 0; i \< 10; i \+= 1\) { ... }`
|
|
* **Range-based `for`:** `for (let e := arrSlice) { ... }`
|
|
* **`while` Loop:** Can optionally have an `else` block that executes when the loop
|
|
condition is no longer met.
|
|
* **Iterator `while`:** Supports unwrapping `Result`/optional types, executing as
|
|
long as the value is valid.
|
|
* **`do-while` Loop:** Guarantees the body executes at least once.
|
|
* **Infinite `loop`:** `loop { ... }`
|
|
|
|
#### Loop Labels and Control
|
|
|
|
Loops can be labeled. The `break` and `continue` statements can optionally specify a
|
|
label to control nested loops.
|
|
|
|
```
|
|
outer_loop := while (condition) {
|
|
inner_loop := for (...) {
|
|
break outer_loop;
|
|
}
|
|
}
|
|
```
|
|
|
|
## 6. Expressions and Operators
|
|
|
|
### Pointer and Member Access
|
|
|
|
* **`&` (Address-of):** Gets a pointer to a variable.
|
|
* **`*` (Dereference):** Accesses the value a pointer points to.
|
|
* **`.` (Member Access):** Accesses a member of a struct value.
|
|
* **`->` (Pointer Member Access):** Dereferences a pointer and accesses a member
|
|
(`p->x` is shorthand for `(*p).x`).
|
|
|
|
### Slice Operators
|
|
|
|
Slices have a dedicated set of operators for manipulation.
|
|
|
|
* **`[start:end]` (Slicing):** Creates a new slice from an existing one.
|
|
* **`.*` (Pointer Access):** Gets the underlying raw pointer of the slice.
|
|
* **`.#` (Length Access):** Gets the number of elements in the slice.
|
|
* **`.[length]` (Slice from Pointer):** Creates a slice from a raw pointer and a length.
|
|
|
|
### Assignment
|
|
|
|
The language supports simple (`=`) and compound assignment (`+=`, `*=`, etc.)
|
|
operators.
|
|
|
|
## 7. Advanced Features
|
|
|
|
### Resource Management (`defer` and `errdefer`)
|
|
|
|
`artichoke` uses `defer` for deterministic resource management.
|
|
|
|
* **`defer`:** Schedules an expression or code block to be executed when the
|
|
current scope is exited. Deferred calls are executed in Last-In, First-Out
|
|
(LIFO) order.
|
|
* **`errdefer`:** Similar to `defer`, but the code is only executed if the scope is
|
|
exited due to a function returning an error (an `Err` variant of a `Result`).
|
|
|
|
```
|
|
defer call_cleanup();
|
|
|
|
errdefer {
|
|
log("An error occurred!");
|
|
}
|
|
```
|
|
|
|
### Reflection (`.@`)
|
|
|
|
The language provides a compile-time reflection mechanism via the `.@` operator.
|
|
It can be applied to values, types, and static members to query metadata.
|
|
|
|
* **On values:** `my_variable.@type`
|
|
* **On types:** `Point<u32>.@size, Point<u32>.@alignment`
|
|
* **On static members:** `Point<u32>::x.@offset`
|
|
|
|
```
|
|
/* Gets size in bytes */
|
|
def size_bytes = Point<u32>.@size;
|
|
|
|
/* Gets string representation of the type */
|
|
def point_name = Point<u32>.@typename;
|
|
```
|