chore: Initial wiki push
Signed-off-by: erick-alcachofa <erick@artichoke.dev>
commit
e38e2baf59
286
Home.md
Normal file
286
Home.md
Normal file
@ -0,0 +1,286 @@
|
||||
# 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;
|
||||
```
|
||||
348
grammar.ebnf
Normal file
348
grammar.ebnf
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
================================================================================
|
||||
| |
|
||||
| The Artichoke Programming Language |
|
||||
| Official EBNF Grammar |
|
||||
| |
|
||||
================================================================================
|
||||
*/
|
||||
|
||||
|
||||
/* --- Program Structure --- */
|
||||
/* A program is a sequence of top-level declarations and statements. */
|
||||
|
||||
<program> =
|
||||
( <import_statement>
|
||||
| <module_statement>
|
||||
| <alias_statement>
|
||||
| <struct_declaration>
|
||||
| <enum_declaration>
|
||||
| <function_declaration> )*
|
||||
|
||||
<module_statement> =
|
||||
"export"? "module" <namespaced_identifier> "{"
|
||||
( <module_statement>
|
||||
| <alias_statement>
|
||||
| <struct_declaration>
|
||||
| <enum_declaration>
|
||||
| <function_declaration> )*
|
||||
"}"
|
||||
|
||||
<import_statement> =
|
||||
"import" <import_target> ";"
|
||||
|
||||
<import_target> =
|
||||
<namespaced_identifier>
|
||||
| <namespaced_identifier> "::" "*"
|
||||
|
||||
<alias_statement> =
|
||||
"using" <identifier> "=" <namespaced_identifier> ";"
|
||||
|
||||
|
||||
/* --- Declarations --- */
|
||||
/* Rules for defining functions, structs, enums, and their components. */
|
||||
|
||||
<function_declaration> =
|
||||
"export"? "fn" <identifier> <generic_params> "(" <fn_params> ")" ( "->" <type> )? <code_block>
|
||||
|
||||
<fn_params> =
|
||||
<fn_params_list>?
|
||||
|
||||
<fn_params_list> =
|
||||
"this" <type> ("," <fn_param> ( "," <fn_param> )* )?
|
||||
| <fn_param> ( "," <fn_param> )*
|
||||
|
||||
<fn_param> =
|
||||
<identifier> ":" <type>
|
||||
|
||||
<struct_declaration> =
|
||||
"export"? "struct" <identifier> <generic_params> "{" <struct_members> "}"
|
||||
|
||||
<struct_members> =
|
||||
<struct_member> ( "," <struct_member> )*
|
||||
|
||||
<struct_member> =
|
||||
<identifier> ":" <type>
|
||||
|
||||
<enum_declaration> =
|
||||
"export"? "enum" <identifier> <generic_params> "{" <enum_members> "}"
|
||||
|
||||
<enum_members> =
|
||||
<enum_member> ( "," <enum_member> )*
|
||||
|
||||
<enum_member> =
|
||||
<identifier> ( "(" <type> ")" )?
|
||||
|
||||
<generic_params> =
|
||||
( "<" <generic_params_list> ">" )?
|
||||
|
||||
<generic_params_list> =
|
||||
<generic_param> ( "," <generic_param> )*
|
||||
|
||||
<generic_param> =
|
||||
"typename" <identifier>
|
||||
|
||||
|
||||
/* --- Statements & Control Flow --- */
|
||||
/* Rules for code blocks, variable declarations, and control structures. */
|
||||
|
||||
<code_block> =
|
||||
"{" <statements>? "}"
|
||||
|
||||
<statements> =
|
||||
<statement> ( <statement> )*
|
||||
|
||||
<statement> =
|
||||
<variable_declaration> ";"
|
||||
| <if_statement>
|
||||
| <loop_statement>
|
||||
| <defer_statement> ";"
|
||||
| <errdefer_statement> ";"
|
||||
| <return_statement> ";"
|
||||
| <break_statement> ";"
|
||||
| <continue_statement> ";"
|
||||
| <expression_statement>
|
||||
| <alias_statement>
|
||||
| <match_statement>
|
||||
| <switch_statement>
|
||||
|
||||
<variable_declaration> =
|
||||
<variable_declarator> <identifier> ( ":" <type> )? "=" <expression>
|
||||
| <variable_declarator> <identifier> ":" <type> ( "=" <expression> )?
|
||||
|
||||
<variable_declarator> =
|
||||
"let"
|
||||
| "def"
|
||||
|
||||
<if_statement> =
|
||||
"if" "(" <expression> ")" <variable_unwrapper>? <code_block>
|
||||
<else_statement>?
|
||||
|
||||
<else_statement> =
|
||||
"else" <variable_unwrapper>? <code_block>
|
||||
| "else" <if_statement>
|
||||
|
||||
<variable_unwrapper> =
|
||||
"|" <identifier> "|"
|
||||
|
||||
<loop_statement> =
|
||||
(<identifier> ":=")? (
|
||||
<c_for_statement>
|
||||
| <range_for_statement>
|
||||
| <while_statement>
|
||||
| <do_while_statement>
|
||||
| <inf_loop_statement>
|
||||
)
|
||||
|
||||
<c_for_statement> =
|
||||
"for" "(" <variable_declaration>? ";" <expression> ";" <expression> ")"
|
||||
<code_block>
|
||||
|
||||
<range_for_statement> =
|
||||
"for" "(" <variable_declarator> <identifier> ":=" <expression> ")"
|
||||
<code_block>
|
||||
|
||||
<while_statement> =
|
||||
"while" "(" <expression> ")" <variable_unwrapper>? <code_block>
|
||||
<else_statement>?
|
||||
|
||||
<do_while_statement> =
|
||||
"do" <code_block> "while" "(" <expression> ")"
|
||||
|
||||
<inf_loop_statement> =
|
||||
"loop" <code_block>
|
||||
|
||||
<match_statement> =
|
||||
"match" "(" <expression> ")" "{" <match_case>* <default_case>? "}"
|
||||
|
||||
<switch_statement> =
|
||||
"switch" "(" <expression> ")" "{" <switch_case>* <default_case>? "}"
|
||||
|
||||
<match_case> =
|
||||
( <type_name> | <scoped_access_expression> ) ( "(" <identifier> ")" )? "->" <code_block>
|
||||
|
||||
<switch_case> =
|
||||
<expression> "->" <code_block>
|
||||
|
||||
<default_case> =
|
||||
"_" "->" <code_block>
|
||||
|
||||
<break_statement> =
|
||||
"break" <identifier>?
|
||||
|
||||
<continue_statement> =
|
||||
"continue" <identifier>?
|
||||
|
||||
<defer_statement> =
|
||||
"defer" ( <expression> | <code_block> )
|
||||
|
||||
<errdefer_statement> =
|
||||
"errdefer" ( <expression> | <code_block> )
|
||||
|
||||
<return_statement> =
|
||||
"return" <expression>?
|
||||
|
||||
<expression_statement> =
|
||||
<expression> ";"
|
||||
|
||||
|
||||
/* --- Expressions & Operator Precedence --- */
|
||||
/* The full expression hierarchy, from lowest to highest precedence. */
|
||||
|
||||
<expression> =
|
||||
<assign_expression>
|
||||
|
||||
<assign_expression> =
|
||||
<bool_or_expression> ( ( <assign_op> | <compound_assign_op> ) <expression> )?
|
||||
|
||||
<bool_or_expression> =
|
||||
<bool_and_expression> ( ( "||" | "or" ) <bool_and_expression> )*
|
||||
|
||||
<bool_and_expression> =
|
||||
<compare_expression> ( ( "&&" | "and" ) <compare_expression> )*
|
||||
|
||||
<compare_expression> =
|
||||
<bitwise_expression> ( <compare_op> <bitwise_expression> )?
|
||||
|
||||
<bitwise_expression> =
|
||||
<bitwise_shift_expression> ( <bitwise_op> <bitwise_shift_expression> )*
|
||||
|
||||
<bitwise_shift_expression> =
|
||||
<addition_expression> ( <bitshift_op> <addition_expression> )*
|
||||
|
||||
<addition_expression> =
|
||||
<multiply_expression> ( <addition_op> <multiply_expression> )*
|
||||
|
||||
<multiply_expression> =
|
||||
<prefix_expression> ( <multiply_op> <prefix_expression> )*
|
||||
|
||||
<prefix_expression> =
|
||||
<prefix_op>* <primary_expression>
|
||||
|
||||
<primary_expression> =
|
||||
<primary_type_expression> ( <suffix_op> | <fn_call_arguments> )*
|
||||
|
||||
|
||||
/* --- Primary Expressions & Literals --- */
|
||||
/* The highest-precedence expressions, including literals and grouped expressions. */
|
||||
|
||||
<primary_type_expression> =
|
||||
<char_literal>
|
||||
| <null_literal>
|
||||
| <string_literal>
|
||||
| <number_literal>
|
||||
| <boolean_literal>
|
||||
| <grouped_expression>
|
||||
| <identifier>
|
||||
| <struct_literal>
|
||||
| <scoped_access_expression>
|
||||
| <reflection_expression>
|
||||
|
||||
<grouped_expression> =
|
||||
"(" <expression> ")"
|
||||
|
||||
<scoped_access_expression> =
|
||||
<type_name> "::" <identifier>
|
||||
|
||||
<reflection_expression> =
|
||||
( <primary_expression> | <type_name> | <scoped_access_expression> ) ".@" <identifier>?
|
||||
|
||||
<fn_call_arguments> =
|
||||
"(" <expression_list> ")"
|
||||
|
||||
<expression_list> =
|
||||
(<expression> ",")* <expression>?
|
||||
|
||||
<struct_literal> =
|
||||
<type> "{" ( <named_field_list> | <positional_field_list> )? ","? "}"
|
||||
|
||||
<named_field_list> =
|
||||
<named_field_init> ( "," <named_field_init> )*
|
||||
|
||||
<named_field_init> =
|
||||
<identifier> ":" <expression>
|
||||
|
||||
<positional_field_list> =
|
||||
<expression> ( "," <expression> )*
|
||||
|
||||
<null_literal> =
|
||||
"null"
|
||||
|
||||
<boolean_literal> =
|
||||
"true"
|
||||
| "false"
|
||||
|
||||
<number_literal> = /* Assumed to be defined by the tokenizer */
|
||||
<string_literal> = /* Assumed to be defined by the tokenizer */
|
||||
<char_literal> = /* Assumed to be defined by the tokenizer */
|
||||
|
||||
|
||||
/* --- Operators --- */
|
||||
/* Definitions for all operator token sets. */
|
||||
|
||||
<assign_op> = "="
|
||||
<compound_assign_op> = "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "<<=" | ">>=" | "||=" | "&&="
|
||||
<compare_op> = "==" | "!=" | ">" | "<" | ">=" | "<="
|
||||
<bitwise_op> = "&" | "^" | "|"
|
||||
<bitshift_op> = "<<" | ">>"
|
||||
<addition_op> = "+" | "-"
|
||||
<multiply_op> = "*" | "/" | "%"
|
||||
<prefix_op> = "!" | "-" | "~" | "&" | "*"
|
||||
|
||||
<suffix_op> =
|
||||
"[" <expression>? ":" <expression>? "]"
|
||||
| "[" <expression> "]"
|
||||
| ".[" <expression> "]"
|
||||
| "." <identifier>
|
||||
| "->" <identifier>
|
||||
| ".#"
|
||||
| ".*"
|
||||
|
||||
/* --- Type System --- */
|
||||
/* Rules for defining types, type names, and type qualifiers. */
|
||||
|
||||
<type> =
|
||||
<type_qualifier_chain> <type_name>
|
||||
|
||||
<type_qualifier_chain> =
|
||||
( "*" | "[]" ) <type_qualifier_chain>?
|
||||
| "$" <type_qualifier_chain_after_mutable>?
|
||||
| "?" <type_qualifier_chain_after_optional>?
|
||||
|
||||
<type_qualifier_chain_after_optional> =
|
||||
( "*" | "[]" ) <type_qualifier_chain>?
|
||||
| "$" <type_qualifier_chain_after_mutable>?
|
||||
|
||||
<type_qualifier_chain_after_mutable> =
|
||||
( "*" | "[]" ) <type_qualifier_chain>?
|
||||
| "?" <type_qualifier_chain_after_optional>?
|
||||
|
||||
<type_name> =
|
||||
<namespaced_identifier> ( "<" <types_list> ">" )?
|
||||
|
||||
<namespaced_identifier> =
|
||||
<identifier>
|
||||
| <identifier> "::" <namespaced_identifier>
|
||||
|
||||
<types_list> =
|
||||
<type> ( "," <types_list> )*
|
||||
|
||||
|
||||
/* --- Lexical Tokens & Base Definitions --- */
|
||||
/* The lowest-level building blocks of the language. */
|
||||
|
||||
<identifier> =
|
||||
<nondigit> <identifier_tail>
|
||||
|
||||
<identifier_tail> =
|
||||
<empty>
|
||||
| <nondigit> <identifier_tail>
|
||||
| <digit> <identifier_tail>
|
||||
|
||||
<nondigit> = "_" | [a-z] | [A-Z]
|
||||
<digit> = <zero> | <nonzero_digit>
|
||||
<zero> = "0"
|
||||
<nonzero_digit> = [1-9]
|
||||
|
||||
<empty> = E /* Represents an empty terminal string */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user