diff --git a/docs/example.arti b/docs/example.arti new file mode 100644 index 0000000..7760208 --- /dev/null +++ b/docs/example.arti @@ -0,0 +1,240 @@ +/* ============================================================================ + * `artichoke` - Language Overview & Technical Specification + * ============================================================================ + * This file serves as an exhaustive showcase of the Artichoke syntax and + * grammar rules as of the 2025 parser-stabilization phase. + */ + +/* * --- Imports --- + * Imports allow the compiler to pull symbols from other modules into the + * current scope. + */ +import std::memory; /* Import the entire 'memory' module from 'std' */ +import std::*; /* Wildcard: Import all direct child elements of 'std'. + Note: This does not recursively import submodules. */ +import my_module::some_function; /* Import a specific function symbol */ +import my_module::some_typename; /* Import a specific type symbol */ + +/* --- Type & Symbol Aliasing --- + * The `using` keyword creates an alias for an existing symbol. This is + * useful for shortening long namespaced paths or creating domain-specific + * names for primitive types. + */ +using mem = std::memory; +using malloc = mem::mem_alloc; +using my_type = my_module::some_typename; +using my_func = my_module::some_function; + +/* --- Structs & Generics (Definition) --- + * Generics at the definition level use a "clean" `` syntax. + * The Turbofish is NOT used here, only at the call site/instantiation. + */ +struct Point { + x: T, + y: T +} + +struct Rectangle { + /* Usage of a generic type REQUIRES the Turbofish `::<>`. + This disambiguates between the 'less-than' operator and a generic list + within the Pratt expression parser. */ + top: Point::, + bot: Point:: +} + +/* --- Functions --- + * Return types follow the `->` operator. + */ +fn meaning_of_life() -> i32 { + return 42; +} + +/* --- Named Initializers --- + * Structs/Objects are initialized using the designated initializer syntax: + * `.field = expression`. This makes the code self-documenting and order-independent. + */ +fn scale(lhs: *Point::, rhs: T) -> Point:: { + return Point:: { + .x = lhs->x * rhs, + .y = lhs->y * rhs + }; +} + +/* --- Member Functions (Methods) --- + * A function becomes a "member function" if the first parameter follows + * the specific syntax: `this` . + + * Note: No colon is required after the `this` keyword. + + * These can be called as: `expr.fn_name(params...)` + * or as standard functions: `fn_name(expr, params...)`. + */ +fn add(this *Point::, other: *Point::) { + this->x += other->x; + this->y += other->y; +} + +/* --- Tagged Enums (Sum Types) --- + * Enums can hold data. The standard library provides a `Result` + * for robust, explicit error handling. + */ +enum Result { + Ok(T), + Err(E) +} + +/* --- The Main Entry Point --- + * Slices are represented as `[]type`. Argv here is a slice of slices of chars. + */ +fn main(argc: i32, argv: [][]char) -> Result:: { + if (argc < 2) { + /* To initialize an enum with data, use an positional initializer. */ + return Result::::Err{ -1 }; + } + + /* --- Variable Declarations --- + * `let` -> Mutable variable (can be reassigned). + * `def` -> Constant variable (immutable after initialization). + * Type inference is supported when the right-hand side is unambiguous. + */ + let x: i32 = 10; + let do_you_get_it = meaning_of_life(); + def PI: f64 = 3.14159265358979; + + /* --- Pointers, Mutability, and Optionals --- + * The following type qualifiers are used to "extend" the types + * `*` -> Pointer (Non-nullable by default). + * `$` -> Mutability qualifier. + * `?` -> Nullable/Optional qualifier. + * Qualifiers apply to the immediate element to their right. + */ + def ptr: *i32 = &do_you_get_it; /* Const pointer to immutable i32 */ + let mutable_pointer: *$i32 = &x; /* Mutable pointer to mutable i32 */ + + /* A mutable (`let`) pointer (*) to a mutable pointer ($*) to a mutable i32 ($i32) */ + let complex_pointer: *$*$i32 = &mutable_pointer; + + /* Nullable types allow the `null` literal. + Mixing qualifiers allows for complex types like "Nullable pointer to mutable i32". */ + let null_int: ?i32 = null; + def nullable_float: ?f32 = PI; + + /* --- Slices and Array Literals --- + * Slices are the primary way to handle contiguous memory. + * ` { ... }` is an Type-ObjectInitiated Literal (Anonymous construction). + * If the type is an slice type, then is a standard Array Literal. + */ + let arrSlice: ?[]i32 = []i32 { 2, 4, 6, 8, 10 }; + + /* --- Slicing Suffixes --- + * `artichoke` supports Python-like slicing with optional boundaries. + */ + let full = arrSlice[:]; /* Full range copy (can be omitted) */ + let range = arrSlice[1:3]; /* From index 1 to 2 (exclusive of 3) */ + let head = arrSlice[:2]; /* Everything before index 2 */ + let tail = arrSlice[2:]; /* Everything from index 2 to the end */ + + /* --- Specialized Suffix Operators --- + * `.*` -> Unwraps a slice into its raw underlying pointer. + * `.#` -> Retrieves the length of the slice. + * `.[length]` -> Convers a raw pointer into a slice of the given length. + */ + def memPtr = arrSlice.*; + def memLength = arrSlice.#; + def newSlice = memPtr.[memLength]; + + /* --- Control Flow & Error Unwrapping --- + * If statements can "unwrap" Result types using the `|val|` syntax. + */ + if (foo()) |ok_val| { + /* If foo() returned Ok(T), ok_val is available here as type T */ + } else |err_val| { + /* If foo() returned Err(E), err_val is available here as type E */ + } + + /* --- While patterns --- + * While statements can also "unwrap" Result types using the `|val|` syntax. + * The while look will continue running until an Err result is resturned + * which will be unrapped into the `err_val` variable if specified. + */ + while (foo()) |ok_val| { + /* If foo() returned Ok(T), ok_val is available here as type T and the loop + * will continue */ + } else |err_val| { + /* If foo() returned Err(E), err_val is available here as type E */ + } + + /* Normal condition based while loops are also supported + * The other powerful while pattern that `artichoke` provides is a "iterator" + * based while loop, if the return type of the expression provided at the + * condition returns an optional (`?`), then it can unraps the variable by + * using the `|val|` syntax and will continue until an empty optional value is + * returned. + */ + while (foo.next()) |ok_val| { + /* If foo() returned Ok(T), ok_val is available here as type T and the loop + * will continue */ + } + + /* --- Match & Switch --- + * `match` -> Used for complex Pattern Matching (Types, Enums). + * `switch` -> Used for Value-based branching. + * Both must be exhaustive or include a default case `_`. + */ + match (foo()) { + Result::::Ok |v| -> { + std::io::print("Success!"); + } + _ -> { /* Default case */ } + } + + /* --- Loops & Labels --- + * Loops can be named using the `name :=` syntax to allow breaking/continuing + * from nested contexts. + * The loop types that `artichoke` provides are + * * `while` loops + * * `do-while` loops + * * `for` loops with a C-style syntax + * * range `for` loops + */ + outer_loop := while (condition) { + inner_loop := for (let i = 0; i < 10; i += 1) { + if (i == 5) { break outer_loop; } + } + } + + /* `do-while` loop, no else branch is allowed here */ + do { + /* Statements */ + } while (true); + + /* `for` loop with a C-style syntax */ + for (let i = 0; i < 10; i += 1) { + /* Statements */ + } + + /* range `for` loop, type is deduced from expression */ + for (let element := returns_range_function()) { + /* Statements */ + } + + /* * --- Resource Management --- + * `defer` -> Executes at the end of the scope in reverse order. + * `errdefer` -> Executes only if the function returns an Err variant. + */ + defer cleanup(); + errdefer { log_failure(); } + + /* * --- Compile-Time Reflection --- + * The `.@` operator provides access to metadata. + */ + + /* Returns an struct with compile time information */ + def refl_info = foo.@; + + /* Specific properties like alighment, size, offset, name are allowed too */ + def xalign = Point::::x.@alignment; + def type_size = Point::.@size; + + return Result::::Ok{}; +}