一键导入
language-syntax
Documentation of Syntax and APIs for Chemical Programming Language, A must read before implementing something in chemical programming language.s
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Documentation of Syntax and APIs for Chemical Programming Language, A must read before implementing something in chemical programming language.s
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Comprehensive guide to the Chemical compiler test infrastructure — how tests are organized, written, and executed. Covers the test framework, @test annotation dispatch, test_env and test libraries, and how compiler plugins get tested via lang/tests/build.lab.
Comprehensive deep-dive into the Chemical build pipeline — how chemical.mod is converted to build.lab, how build scripts are JIT-compiled via TinyCC, how jobs are created and executed, and how ASTProcessor orchestrates the parallel compilation passes.
All documentation related to building and running Project or Tests
Comprehensive guide to the Chemical Compiler Binding Interface (CBI) — how compiler plugins are built, registered, and integrated into the compilation pipeline.
Comprehensive guide to Chemical's compiler intrinsic functions and reflection APIs — how GlobalFunctions.cpp provides interpreter-friendly implementations, compile-time reflection, and metadata access.
The Chemical compiler API bindings in lang/libs/compiler/ and the C++ AST node hierarchy — ASTNode, Value, BaseType, ASTAllocator, and their unsafe casting methods.
| name | Language Syntax |
| description | Documentation of Syntax and APIs for Chemical Programming Language, A must read before implementing something in chemical programming language.s |
This document provides a comprehensive reference for Chemical language syntax, designed to help AI systems generate correct Chemical code. All syntax described here is based on analysis of the parser implementation and existing codebase.
.chchemical.modmodule module_name
source "src" // Include all .ch files in src directory (recursive)
import module_name // Import other modules
Important: No import statements are required at the top of .ch files. Any .ch file can access anything in the current module and from any modules imported in chemical.mod. Import statements are only valid in build.lab or chemical.mod files.
Chemical supports C++-style namespaces for organizing types and functions and for avoiding name collisions.
namespace cool {
struct Pair2 {
var a : int
var b : int
}
func pair2_sum(p : *Pair2) : int {
return p.a + p.b;
}
}
::Use namespace_name::identifier to refer to types/functions inside a namespace from outside that namespace.
var p : cool::Pair2 { a : 0, b : 0 }
var x = cool::pair2_sum(&p)
You must make the namespace public if you want to expose anything inside it to other modules.
This is a hard rule. Without it you'll get symbol resolution errors. By default every namespace is internal, Everything inside it
is only accessible from inside the same module.
Anything inside the namespace (struct/function/variant) must be also made public if you want to expose it to other modules.
The same namespace can appear multiple times in the same file; later blocks extend the namespace and can use earlier declarations.
namespace cool {
func pair2_mul(p : *Pair2) : int {
return p.a * p.b;
}
}
Within a namespace X { ... } block, names inside X can be referenced without X::.
namespace cool {
func pair2_sum_call(p : *Pair2) : int {
return pair2_sum(p);
}
}
using declarationsBring a single symbol into the current scope:
using closed_bro::bring_me_in;
func demo() : int {
return bring_me_in();
}
Bring all symbols from a namespace into the current scope:
using namespace all_closed;
func demo2() : int {
return check_im_closed();
}
X::name in generated code when possible; it reduces ambiguity and avoids name collisions.using sparingly: using namespace X; is convenient, but it can hide where a symbol comes from and can create conflicts if multiple namespaces define the same identifier.cool vs coool) silently creates a different namespace and breaks lookups.:: the same way as types.// Mutable variables
var name : type = value
var name = value // Type inference
// Immutable constants
const name : type = value
const name = value // Type inference
// Compile-time variables
comptime var name : type = value
comptime const name : type = value
const variables must be initialized at declarationvar x : int = 42
var message = "Hello, World!"
const PI = 3.14159
comptime var COMPTIME_VAL = 100
// Chemical integer types
i8, i16, i32, i64, int128
u8, u16, u32, u64, uint128
// C-compatible types
char, short, int, long, longlong
uchar, ushort, uint, ulong, ulonglong
// Floating point
float, double, longdouble, float128
// Other types
bool, void, any
var ptr : *int // Pointer to int
var ptr_ptr : **int // Pointer to pointer to int
var func_ptr : () => int // Function pointer
var ref : &int // Reference to int
Using const in pointer type is not recommended, for example
// Invalid Code (const doesn't exist)
var ptr : *const int
Every pointer is by default non-mutable, you use *mut int for mutability
*char in Chemical means const char* in C
Use &raw obj or &raw mut obj to take a pointer or mutable pointer respectively
func i_take_ptr(ptr : *mut Point) {}
func i_send_ptr(p : Point) {
i_take_ptr(&raw mut p)
}
func i_take_ref(ptr : &mut Point) {}
func i_send_ref(p : Point) {
i_take_ref(&mut p)
}
var arr : [10]int // Fixed-size array
var multi : [10][20]int // Multi-dimensional array
if(condition) {
// then block
} else if(other_condition) {
// else if block
} else {
// else block
}
// If as expression
// must not use braces to specify values
var result = if(condition) value1 else value2
switch(value) {
case1 => {
// case 1 block
// break statement NOT allowed
}
case2 => {
// case 2 block
}
default => {
// default block
}
}
// Switch as expression
var result = switch(value) {
case1, case2 => value
default => default_value
}
// While loop
while(condition) {
// loop body
}
// Do-while loop
do {
// loop body
} while(condition)
// For loop
for(var i = 0; i < 10; i++) {
// loop body
}
// Loop as expression
var result = loop {
// loop body
break value
}
for(var i = 0; i < 10; i++) {
if(condition) {
break
}
if(other_condition) {
continue
}
}
func function_name(param1 : type1, param2 : type2) : return_type {
// function body
return value
}
// Public functions (exposed to other modules)
public func public_function(param : type) : return_type {
// implementation
}
// Regular parameters
func func(param : type) : return_type
// Default values
func func(param : type = default_value) : return_type
// Variadic parameters, only for c extern defined functions
func func(param : type, ...) : return_type
// public before would expose to other modules
struct StructName {
// Members with access specifiers
public var member1 : int
private const member2 : std::string
// Default values
// A member is by default public (like C++ struct)
var member3 : float = 0.0
// Methods
func method_name(&self) : return_type {
// method body
}
}
Chemical has three struct annotation combinations that affect initialization:
| Annotations | T{} works? | T.make() works? | T{field: val} works? |
|---|---|---|---|
@direct_init only | Yes (all fields required) | No | Yes (all fields required) |
@make only | No | Yes | No |
@direct_init + @make | Yes (all fields required) | Yes | Yes (all fields required) |
| Neither | Yes (all fields required) | No | Yes (all fields required) |
Critical: A struct with @make but without @direct_init cannot use {} syntax at all. The compiler errors with "struct has a constructor, use @direct_init to allow direct initialization". You must use T.make() instead.
// @direct_init only:
var s = StructName { member1 : 0, member2 : 0 } // All fields required
// @make only:
var s = StructName.make() // Works
// var s = StructName{} // ERROR: struct has a constructor
// var s = StructName{member1: 0} // ERROR: struct has a constructor
// @direct_init + @make:
var s = StructName{} // Works (all fields zeroed)
var s = StructName{member1: 0} // Works (all fields required)
var s = StructName.make() // Works
When calling the constructor, You must not use the name of the function of the constructor, for example
// compiler will automatically determine the constructor
// like c++
var p = Point(10, 20)
If you use the name of the constructor function, chemical won't complain, but for example library author changes the name of the constructor, that would cause your project to break at compilation.
// this will set all values to zero
// if the struct is destructible or has a constructor, this may not work, and compiler may force you to use annotations
var s = zeroed<StructName>()
When initializing struct, members without a constructor or a default value MUST be initialized, otherwise there would be compilation errors.
vector<T>{} standalone initvector<T>{} aggregate init only works inside @direct_init struct init context. Standalone var x = vector<T>{} fails. Use the constructor:
// WRONG (outside struct init):
// var file_data = vector<u8>{}
// CORRECT:
var file_data = vector<u8>()
var name : type or const name : typefunc name(params) : return_type@constructor or @make annotationstruct ManagedResource {
var resource : *void
@delete
func destruct(&self) {
unsafe {
// dealloc statement just calls free under the hood
// use dealloc instead of free, because it can be optimized out
// when users are using a garbage collected runtime
dealloc self.resource
// even better would be using delete
// delete ptr; which calls the destructor (if any) and then calls free
}
}
}
public
private
internal
protected
By default every top level decl (struct/function/variant/namespace) is internal
by default every struct member/function is public
func unsafe_operation() {
unsafe {
// Unsafe operations here
var ptr = malloc(100) as *int
*ptr = 42
// dealloc statement just calls free under the hood
dealloc ptr;
// even better would be using delete
// delete ptr; which calls the destructor (if any) and then calls free
}
}
func manual_memory() {
unsafe {
var ptr = malloc(100) as *int
*ptr = 42
// Use pointer
// dealloc statement just calls free under the hood
dealloc ptr;
// for structs use delete instead of dealloc
// delete ensures that destructors are called
}
}
func dynamic_allocation() {
unsafe {
var ptr = new int // Allocate and construct
*ptr = 42
dealloc ptr // Deallocate
// for structs use delete instead of dealloc
// delete ensures that destructors are called
}
}
dealloc just calls freedestruct calls destructor only (no free)delete calls the destructor then cals freevariant VariantName {
Case1(param1 : type1, param2 : type2)
Case2(param : type)
Case3() // Empty case
}
Strict Rule: Pattern Matching only works with variants
variant Option<T> {
Some(value : T)
None()
}
func get_value(opt : Option<int>) : int {
var Some(value) = opt else -1
return value
}
func get_value_or_return(opt : Option<int>) : int {
var Some(value) = opt else return 0
return value
}
func unwrap(opt : Option<int>) : int {
var Some(value) = opt else unreachable
return value
}
func check_option(opt : Option<int>) : bool {
if(var Some(value) = opt) {
return value > 0
}
return false
}
func process_variant(variant : MyVariant) : int {
switch(variant) {
Case1(value) => {
return value * 2
}
Case2 => return -1
}
}
isfunc is_some_case(opt : Option<int>) : bool {
return opt is Option.Some
}
func is_none_case(opt : Option<int>) : bool {
return opt is Option.None
}
Note: These core C-like features are sufficient to write good, performant Chemical code. Stick to these features for better reliability and performance.
The Chemical standard library provides essential data structures and utilities. Below are the key APIs that AI systems should know.
Important: You cannot use the + operator between std::string or *char. Chemical doesn't perform support addition of strings with +.
var s = std::string() // Empty string
// Append a single character
s.append('x')
// Append a string view
s.append_view(std::string_view("wow"))
s.append_view("hello world") // string_view has implicit constructor for *char
// Append another std::string
s.append_string(other_string)
// Append another std::string (by converting to view)
s.append_view(other_string.to_view())
Chemical does implicit moves, which means a variable becomes inaccessible if moved.
var s = std::string("hello world")
var y = s
// using s is invalid here
// s.append_view("x") <-- causes compilation error
// because std::string has a destructor
// you can copy a string explicitly using
// var copy = s.copy()
var s = std::string()
s.append('H')
s.append_view("ello")
s.append(' ')
s.append_view("World")
// WRONG - This will not work:
// var result = s + " more text" // + operator not overloaded
// CORRECT:
s.append_view(" more text")
A lightweight view into string data without ownership.
var view = std::string_view("hello") // From *char literal
var view2 = std::string_view(string_obj) // From std::string
func process_text(text : std::string_view) {
// Process text without copying
}
process_text("hello") // Works due to implicit constructor
Dynamic array container similar to C++ std::vector.
var vec = std::vector<int>() // Empty vector of int
var vec2 = std::vector<std::string>() // Empty vector of strings
// Add elements
vec.push(42)
vec.push(100)
// Access elements
var first = vec[0] // No bounds checking
var safe_first = vec.at(0) // With bounds checking
// Size
var size = vec.size()
// Check if empty
var empty = vec.empty()
// Clear all elements
vec.clear()
// Reserve capacity
vec.reserve(100) // Allocate space for 100 elements
var numbers = std::vector<int>()
for(var i = 0; i < 10; i++) {
numbers.push(i * i)
}
var strings = std::vector<std::string>()
strings.push(std::string())
strings[0].append_view("first")
Hash map container for key-value pairs.
Does not support [key] operator for lookups or assignment.
Warning: The iterator() method scans buckets — iteration order is not deterministic. Use ordered_map if you need predictable insertion-order iteration.
var map = std::unordered_map<std::string, int>()
var map2 = std::unordered_map<int, std::string>()
// Insert key-value pairs
map.insert("key", 42)
// Access elements
var value = map.get_ptr("key") // Returns a pointer, null if not found
// Check if key exists
var exists = map.contains("key")
// Remove elements
map.erase("key")
// Size
var size = map.size()
// Clear all elements
map.clear()
var word_count = std::unordered_map<std::string, int>()
word_count.insert("hello", 1)
word_count.insert("world", 2)
if(word_count.contains("hello")) {
word_count.insert("hello", (*word_count.get_ptr("hello")) + 1)
}
Insertion-order-preserving hash map. Same API as unordered_map but iteration follows insertion order via an internal doubly-linked list.
Key constraint: Key : Hashable + Eq (same as unordered_map).
unordered_map) for O(1) lookupsorder_prev / order_next pointers forming a linked list in insertion orderinsert appends new keys to the tail; insert of an existing key updates the value without changing positionerase splices the node out of both the hash chain and the linked listorder_next from head to tail (no bucket scanning)order_prev from tail to headSame as unordered_map: insert, find, contains, get_ptr, erase, clear, size, empty, isEmpty
for(var entry in map) // insertion order
for(var entry, i in map) // with index
for(var& entry in map) // by reference
for(var entry in map reversed) // reverse insertion order
var map = std::ordered_map<std::string, int>()
var map2 = std::ordered_map<int, std::string>()
var map = std::ordered_map<std::string, int>()
map.insert("first", 1)
map.insert("second", 2)
map.insert("third", 3)
// Iteration is guaranteed to yield: first→1, second→2, third→3
for(var entry in map) {
// entry.key, entry.value
}
// Erase a key
map.erase("second") // remaining order: first→1, third→3
// Update (position unchanged)
map.insert("first", 100) // still at position 1
The standard library provides commonly used variant types for error handling and optional values.
// Already available in standard library
var opt = std::Option<int>.Some(42)
var empty = std::Option<int>.None()
// Use with pattern matching
var Some(value) = opt else -1
// Already available in standard library
var success = std::Result<int, std::string>.Ok(42)
var error = std::Result<int, std::string>.Err("failed")
// Use with pattern matching
var Ok(value) = success else -1
*char for C-style string operations when possibleappend_view() instead of + operatorvector for sequential access, unordered_map for key-value lookupThese features provide additional functionality but should be used judiciously. For most use cases, the core C-like features and standard library are sufficient.
struct GenericStruct<T> {
var value : T
}
func <T> generic_func(param : T) : T {
return param
}
func <T : SomeInterface> constrained_func(param : T) : T {
return param
}
struct DefaultGeneric<T = int> {
var value : T
}
func <T = std::string> default_generic_func(param : T) : T {
return param
}
var int_struct = GenericStruct<int> { value : 0 }
var string_struct = GenericStruct<std::string>()
var default_struct = DefaultGeneric{ value : 0 } // Uses int as default
When writing a function type, You should use colon arrow '=>' before the return type
var lambda : (param : type) => return_type = null ✅
When writing the lambda as an expression, You must not write return_type after =>
var lamb = () => int { return 33 } ❌
var lamb = () : int => 33 ✅
var lamb = () : int => { return 33 } ✅
Return type determined from the returned expression
var lamb = () => 33 ✅
var lamb = () => { return 33 } ✅
Here's a lambda with a function type
var lamb : () => int = () => 33;
var lambda = (param : type) : return_type => {
return param * 2
}
The return_type after the colon is optional, You can do this
var lambda = (param : type) => {
return param * 2
}
When using capturing lambda, a container type like std::function is required, The lambda decays into that container type
Without the container type, capturing of variables is not possible.
var x = 10
var capturing_lambda : std::function<(p : int) => int> = |x|(param : int) : int => {
return param + x
}
var no_params = () : int => {
return 42
}
// Function pointer type
var func_ptr : (a : int, b : std::string) => bool
// Lambda type with capture - only capturing functions can capture variables
var lambda_type : std::function<(param : type) => return_type>
@deprecated // Marks item as deprecated
@extern // External definition
@no_mangle // Don't mangle name
@static // Static member
@implicit // Implicit parameter
@constructor // Constructor method
@test // Test function
@inline // Inline function
@noinline // Don't inline
@deprecated("Use new_function instead")
func old_function() {
// implementation
}
@extern public func printf(format : *char, ...) : int
@constructor
func init(&self, param : int) {
// constructor implementation
}
@test
func test_feature() : bool {
return true
}
comptime if(def.windows) {
// windows specific code
// the syntax is still checked
// however type checking is skipped if def.windows is false
}
// only if function can run at compile time
comptime func calculate_at_compile_time() : int {
return 42 * 2
}
const RESULT = calculate_at_compile_time()
comptime if(condition) {
// Compile-time branch
} else {
// Other compile-time branch
}
@extern public func printf(format : *char, ...) : int
@extern public func malloc(size : usize) : *void
@extern public func free(ptr : *void) : void
@extern
struct CStruct {
var field1 : int
var field2 : *char
}
var int_val = 42
var float_val = int_val as float
var ptr_val2 = &raw mut int_val as *mut float
func move_example() {
var original = MyStruct()
// implicit moves
var moved = original // Move ownership
// original is no longer valid here
}
struct GenericStruct<T, U> {
var value1 : T
var value2 : U
func <V> generic_method(param : V) : V {
return param
}
}
variant GenericVariant<T> {
Some(value : T)
None()
}
variant MultiGeneric<T, U> {
First(a : T, b : U)
Second(value : T)
Empty()
}
variant VariantWithDefault<T = int> {
Some(value : T)
None()
}
variant MyVariant {
Case1(value : int)
Case2(text : std::string)
func get_value(&self) : int {
switch(self) {
Case1(value) => return value
Case2 => return -1
}
}
}
These patterns were discovered while implementing pure-Chemical libraries.
.data() Returns Immutable Pointervector<T>.data() returns *T (immutable). To write through the pointer, cast to *mut T:
var sptr = vec.data() as *mut i16
sptr[0] = 10000
sptr[1] = -10000
.size() Not .length()string and vector use .size() — there is no .length() method.
0.5 is double in Chemical. For float parameters, use 0.5f:
public func audio_volume(audio : *mut Audio, factor : float) { ... }
audio_volume(&raw mut a, 0.5f) // WRONG: 0.5 is double
audio_volume(&raw mut a, 0.5) // TypeCheck error: double does not satisfy float
if Expressions Not InlineChemical does not support if as an expression inline in function arguments:
// WRONG:
// var max_samples = if(a > b) { a } else { b }
// CORRECT:
var max_samples : size_t
if(a > b) { max_samples = a } else { max_samples = b }
if Requires elseEvery if block requires an else block. No bare if without else.
append_string(&msg)When capturing a string from a variant pattern, pass it by reference to append_string:
switch(self) {
InvalidFormat(msg) => {
var s = string("Error: ")
s.append_string(&msg) // NOT append_string(msg)
return s
}
}
using Declarations in Test FilesTest files at global scope need using declarations to access standard library types:
using std::Result; // For Result.Err / Result.Ok patterns
using std::string; // For string() constructor
using std::vector; // For vector<T>() constructor
Functions without public (internal by default) cannot be called from test modules in other packages. Mark test-relevant helper functions public:
// archive/src/endian.ch — WRONG: internal, can't be called from tests
// func read_u16_le(data : *u8, offset : size_t) : u16 { ... }
// CORRECT:
public func read_u16_le(data : *u8, offset : size_t) : u16 { ... }
memcpy With Pointer VariablesWhen a variable is already *mut T, never use &raw mut var with memcpy. &raw mut var takes the address of the pointer variable itself (on the stack), not what it points to:
func zip_find_entry(output : *mut ArchiveEntry, ...) {
// WRONG — &raw mut output is *mut (*mut ArchiveEntry), stack corruption!
// memcpy(&raw mut output, &raw entry, sizeof(ArchiveEntry))
// CORRECT — output is already *mut ArchiveEntry:
memcpy(output, &raw entry, sizeof(ArchiveEntry))
}
@test
public func my_test(env : &mut TestEnv) {
var result = some_func()
if(result is Result.Err) { env.error("should succeed"); return }
var Ok(value) = result else unreachable
// Now use value safely
}
const in Pointer Types*const T is not valid Chemical. Use *T for immutable pointers.
The right operand of shift operators must match the left operand type:
var val : u32 = 128u
var shifted = val >> 2u // CORRECT: both u32
// var shifted = val >> 2 // WRONG: int does not satisfy uint
*char. For performant code, stick to C-like features with Chemical syntax.std::string and *char don't support + operator. Use append() functions specifically designed.build.lab or chemical.mod files.&key in parameter means reference, not address-ofWhen a function signature uses &Key as a parameter type, it means reference to Key — pass the value directly, don't prefix with &:
func contains(&self, key : &Key) : bool // key is a reference
// CORRECT:
map.contains(10)
// WRONG — taking address of r-value literal:
map.contains(&10) // ERROR: cannot apply operator '&' to r-value
The same applies to erase(key), get_ptr(key), find(key, &mut out).
Only use explicit & when the parameter type is a raw pointer (*Key or *mut Key).
&arr[0] gives a reference, not a pointer — use &raw for raw pointersArray indexing arr[i] produces a reference to the element (&T), not a raw pointer (*T).
To get a raw pointer for passing to C functions, use &raw or &raw mut:
var buf : char[2048]
// WRONG — produces &char, not *char:
// popen(&buf[0], "r") // TypeCheck error: &char does not satisfy *char
// sprintf(&buf[0], "%s", arg) // TypeCheck error: &char does not satisfy *mut char
// CORRECT — use &raw for raw pointers:
var pipe = popen(&raw buf[0], "r") // *char (immutable)
sprintf(&raw mut buf[0], "%s", arg) // *mut char (mutable)
This applies to all C interop (sprintf, popen, fgets, fwrite, fopen, etc.) and any
function expecting *char or *mut char.
*char (immutable), arrays need &raw mut for *mut charString literals (e.g., "hello") have type *char and can be passed directly to functions
expecting *char. However, char arrays are mutable local variables and require &raw mut
to get *mut char:
@extern public func sprintf(buf : *mut char, fmt : *char, ...) : int
var s = "hello" // *char — pass directly
var buf : char[64]
sprintf(&raw mut buf[0], "%s", s) // buf needs &raw mut for *mut char
The parser errors on expressions spanning multiple lines inside a lambda body:
// WRONG — parser error:
test("name", () => {
return a == 1 && b == 2
&& c == 3 // ERROR here
})
// CORRECT — use if/return statements:
test("name", () => {
if(a != 1) return false
if(b != 2) return false
if(c != 3) return false
return true
})
reversed is a keyword — cannot use as field nameThe reversed keyword used in for(var entry in map reversed) conflicts with user-defined identifiers. If you name a struct field reversed, the compiler errors:
error: couldn't find value for member 'reversed'
Use a different name like reverse_dir or avoid the name entirely.
vector<T> does NOT support operator[]You cannot use vec[0], vec[1], etc. to index into a std::vector. There is no index operator overload. To access elements, use .get(i) or .get_ptr(i):
var vec = std::vector<int>()
vec.push(10)
vec.push(20)
// WRONG:
// var x = vec[0] // ERROR
// CORRECT:
var x = vec.get(0)
var px = vec.get_ptr(0) // returns *mut int
To make a custom type iterable with for(var x in obj), implement core::iterable::Iterable<T, Cursor>:
impl core::iterable::Iterable<MyNode, MyCursor> for MyStruct {
func begin(&self) : MyCursor { ... }
func valid(&self, c : MyCursor) : bool { ... }
func current(&self, c : MyCursor) : &MyNode { ... }
func next(&self, c : MyCursor) : MyCursor { ... }
}
For reversed support, additionally implement ReversibleIterable:
impl core::iterable::ReversibleIterable<MyNode, MyCursor> for MyStruct {
func rbegin(&self) : MyCursor { ... } // start from end
func previous(&self, c : MyCursor) : MyCursor { ... } // walk backward
func count(&self) : size_t { ... }
}
The cursor struct does not need a reversed flag — next() is used for forward iteration, previous() for reverse. They are never called in the same loop.
To build an insertion-order-preserving map:
hash_next) and the order chain (order_prev / order_next)head / tail pointers on the map track the ordered listinsert appends new nodes to the tail (tail.order_next = newNode; tail = newNode)erase splices the node out of the order list (prev.order_next = next; next.order_prev = prev)resize rehashes by walking the order list (not the buckets), preserving the linked list pointers unchanged@delete destructor walks the order list (not buckets) for cleanup, then frees the tableThis is invalid code
take_view(create_string().to_view())
with code like this you get error
error: function call is on a temporary that is destroyed at expression end, please store the temporary in a variable
To fix you must use
var str = create_string()
take_view(str.to_view())
std::Option type is available in standard library
variant Option<T> {
Some(value : T)
None()
}
func <T> unwrap_or(opt : Option<T>, default : T) : T {
var Some(value) = opt else default
return value
}
std::Result type is available in standard library
variant Result<T, E> {
Ok(value : T)
Err(error : E)
}
func <T, E> map_result(result : Result<T, E>, mapper : (T) => T) : Result<T, E> {
switch(result) {
Ok(value) => Result.Ok(mapper(value))
Err(error) => Result.Err(error)
}
}
struct Builder {
var field1 : int = 0
var field2 : std::string = ""
func with_field1(value : int) -> Builder {
field1 = value
return this
}
func with_field2(value : std::string) -> Builder {
field2 = value
return this
}
func build() -> MyStruct {
return MyStruct(field1, field2)
}
}
This syntax reference provides the foundation for generating correct Chemical code. The language emphasizes safety, performance, and C interoperability while maintaining modern language features.