summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/copilot-instructions.md87
-rw-r--r--Makefile3
-rw-r--r--README.md180
-rw-r--r--README_ES.md1436
-rw-r--r--README_ZH_CN.md1435
-rw-r--r--README_ZH_TW.md1435
-rw-r--r--docs/lex.md130
-rw-r--r--docs/std/README.md7
-rw-r--r--docs/std/json.md83
-rw-r--r--docs/std/net.md44
-rw-r--r--docs/std/process.md57
-rw-r--r--docs/std/set.md38
-rw-r--r--docs/std/slice.md93
-rw-r--r--docs/std/stack.md38
-rw-r--r--docs/std/string.md4
-rw-r--r--docs/std/thread.md47
-rw-r--r--docs/std/time.md38
-rw-r--r--examples/data_structures/stack.zc8
-rw-r--r--examples/graphics/mandelbrot.zc74
-rw-r--r--examples/networking/echo_server.zc10
-rw-r--r--examples/objc_interop.zc42
-rw-r--r--examples/process/exec.zc20
-rw-r--r--examples/tools/mini_grep.zc14
-rw-r--r--src/ast/ast.c42
-rw-r--r--src/ast/ast.h16
-rw-r--r--src/codegen/codegen.c266
-rw-r--r--src/codegen/codegen.h4
-rw-r--r--src/codegen/codegen_decl.c35
-rw-r--r--src/codegen/codegen_main.c35
-rw-r--r--src/codegen/codegen_stmt.c15
-rw-r--r--src/codegen/codegen_utils.c52
-rw-r--r--src/codegen/compat.h84
-rw-r--r--src/lexer/token.c12
-rw-r--r--src/lsp/lsp_analysis.c71
-rw-r--r--src/lsp/lsp_index.c52
-rw-r--r--src/main.c13
-rw-r--r--src/parser/parser.h29
-rw-r--r--src/parser/parser_core.c32
-rw-r--r--src/parser/parser_decl.c70
-rw-r--r--src/parser/parser_expr.c200
-rw-r--r--src/parser/parser_stmt.c282
-rw-r--r--src/parser/parser_struct.c129
-rw-r--r--src/parser/parser_type.c103
-rw-r--r--src/parser/parser_utils.c67
-rw-r--r--src/repl/repl.c1589
-rw-r--r--src/utils/utils.c223
-rw-r--r--src/zprep.h2
-rw-r--r--std.zc2
-rw-r--r--std/core.zc6
-rw-r--r--std/cuda.zc2
-rw-r--r--std/env.zc29
-rw-r--r--std/fs.zc90
-rw-r--r--std/io.zc49
-rw-r--r--std/json.zc72
-rw-r--r--std/map.zc29
-rw-r--r--std/mem.zc23
-rw-r--r--std/net.zc46
-rw-r--r--std/process.zc136
-rw-r--r--std/set.zc20
-rw-r--r--std/slice.zc40
-rw-r--r--std/string.zc22
-rw-r--r--std/thread.zc14
-rw-r--r--std/time.zc29
-rw-r--r--tests/features/_opaque_alias_lib.zc13
-rw-r--r--tests/features/_opaque_lib.zc15
-rw-r--r--tests/features/test_build_directives.zc21
-rw-r--r--tests/features/test_implicit_fstring.zc19
-rw-r--r--tests/features/test_opaque.zc18
-rw-r--r--tests/features/test_opaque_alias.zc13
-rw-r--r--tests/features/test_traits_suite.zc2
-rw-r--r--tests/memory/test_memory_safety.zc9
-rw-r--r--tests/memory/test_unsafe.zc15
-rwxr-xr-xtests/run_example_transpile.sh39
-rw-r--r--tests/std/test_direct_array_iteration.zc37
-rw-r--r--tests/std/test_env.zc2
-rw-r--r--tests/std/test_json_serialization.zc149
-rw-r--r--tests/std/test_process.zc26
-rw-r--r--tests/std/test_slice_iteration.zc29
78 files changed, 8969 insertions, 793 deletions
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
new file mode 100644
index 0000000..fac102a
--- /dev/null
+++ b/.github/copilot-instructions.md
@@ -0,0 +1,87 @@
+# Zen C Copilot Instructions
+
+These instructions are **MANDATORY** for all code generation and review tasks in the Zen C project.
+
+## 1. Memory Management (Critical)
+* **Arena Allocation**: The compiler uses a bump-pointer arena allocator.
+ * **MUST USE**: `xmalloc`, `xcalloc`, `xrealloc`, `xstrdup` (defined in `src/utils/utils.c`).
+ * **NEVER USE**: Standard `malloc`, `calloc`, `free` (unless interfacing with an external library that strictly requires owned heap memory, like CJSON).
+* **Destructors/Freeing**:
+ * `free(ptr)` is `#defined` to `((void)0)` in `src/zprep.h`. It is a no-op.
+ * Do **NOT** attempt to free AST nodes or types. `ast_free` is a no-op.
+ * Memory is reclaimed only when the process exits. Design your data structures accordingly (append-only is fine).
+
+## 2. AST and Type System
+* **Creation**: Use `ast_create(NODE_TYPE)` to allocate new nodes.
+* **Type Representation**:
+ * Use `Type` struct (defined in `src/ast/ast.h`).
+ * Use `type_new(TYPE_KIND)` helper.
+ * `type_to_string(t)` and `type_to_c_string(t)` return arena-allocated strings. Do not worry about freeing them.
+* **Traversal**:
+ * The compiler uses **Recursive Descent** with **Switch Statements** on `node->type`.
+ * Do NOT introduce Visitor patterns or callback tables unless consistent with existing code.
+
+## 3. Parser Patterns
+* **Context**: `ParserContext *ctx` is the god-object. It MUST be passed to almost every function in parsing, analysis, and codegen.
+ * **Signature Rule**: `ReturnType func_name(ParserContext *ctx, ...)`
+* **Token Consumption**:
+ * Use `expect(lexer, TOKEN_TYPE, "error message")` for mandatory tokens.
+ * For optional tokens, check `l->token.type` and assume `lexer_next(l)` is used to advance (verify specific helper availability).
+* **Error Handling**:
+ * **Fatal**: `zpanic("msg")` or `zpanic_at(token, "msg")`. Exits immediately (or delegates to LSP handler).
+ * **Warning**: `zwarn("msg")` or `zwarn_at(token, "msg")`.
+ * **Semantic Errors**: Prefer `zpanic_at` for type errors to give line/col info.
+
+## 4. Code Generation (C Backend)
+* **Generic Mangling**:
+ * Generic structs (e.g., `Slice<int>`) are mangled to `Slice_int` **IF AND ONLY IF** the instantiated struct exists (checked via `find_struct_def_codegen`).
+ * **Fallback**: If the mangled struct (e.g. `Async_int`) does not exist, use the base name (`Async`). This handles opaque types like `Async<T>` correctly.
+ * See `emit_c_decl` in `src/codegen/codegen_utils.c` for the canonical implementation.
+* **Function Signatures**:
+ * Use `emit_func_signature(ctx, out, node, override_name)` to handle modifiers, return types, and arguments correctly.
+* **Output**: Use `fprintf(out, ...)` where `out` is the `FILE*`.
+
+## 5. Coding Style & Conventions
+* **Formatting**:
+ * Indentation: 4 spaces.
+ * Braces: **ALWAYS** Use braces `{}` for control flow (`if`, `while`, `for`), even for single lines.
+ * Opening brace on the **NEXT** line (Allman style).
+* **Naming**:
+ * Structs/Enums: `PascalCase`.
+ * Functions/Variables: `snake_case`.
+ * Macros/Constants: `SCREAMING_SNAKE_CASE`.
+ * Private/Static: No strict prefix, but `static` keyword is mandatory for internal file-scope functions.
+* **Iterators**:
+ * When implementing iteration in compiler (C code): Use `while (node) { ... node = node->next; }` for linked lists (`ASTNode`, `StructRef`).
+
+## 6. Standard Library (Zen C Definitions)
+* **Arrays**: Use `for val in arr` syntax (direct iteration).
+* **Vectors**: `Vec<T>` is a dynamic array.
+* **Strings**: `string` in Zen C maps to `char*` in C. `kstring` or `zstr` are higher-level wrappers.
+
+## 7. Common Pitfalls
+* **Unused Variables**: The compiler builds with `-Wall -Werror` (or similar strictness). Cast unused vars to void: `(void)var_name;`.
+## 8. Zen C Language Rules (For writing .zc files)
+* **Syntax**:
+ * Variables: `let x = 10;`, `let y: const int = 20;`.
+ * Constants: `def MAX = 100;` (compile-time).
+ * Functions: `fn name(arg: type) -> ret { ... }`.
+ * Structs: `struct Point { x: int; y: int; }`.
+ * Enums: `enum Shape { Circle(float), Rect(float, float) }`.
+* **Memory & Resources**:
+ * **Move Semantics**: Structs/Enums are moved by default on assignment/pass-by-value.
+ * **Defer**: Use `defer stmt;` to run cleanup at scope exit.
+ * **Drop**: Implement `impl Drop for T` for RAII.
+* **Arrays & Slices**:
+ * **Iteration**: Use `for val in arr` (direct iteration supported).
+ * **Slices**: `Slice<T>` is a view. `int[N]` auto-converts to slice in loops.
+* **Generics**:
+ * Syntax: `struct Box<T> { val: T; }`.
+* **Concurrency**:
+ * Use `async fn` and `await` keyword.
+ * `Async<T>` is the opaque future type.
+* **Standard Library**:
+ * Import with `import "std/io.zc"`, `import "std/vec.zc"`.
+ * Use `println "msg"` (shorthand) or `printf`.
+* **Testing**:
+ * Use `test "name" { ... }` blocks for unit tests.
diff --git a/Makefile b/Makefile
index 776581d..b2d8e29 100644
--- a/Makefile
+++ b/Makefile
@@ -188,9 +188,10 @@ clean:
@echo "=> Clean complete!"
# Test
-test: $(TARGET)
+test: $(TARGET) $(PLUGINS)
./tests/run_tests.sh
./tests/run_codegen_tests.sh
+ ./tests/run_example_transpile.sh
# Build with alternative compilers
zig:
diff --git a/README.md b/README.md
index 0c5bd0a..bf4962e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,12 @@
<div align="center">
+[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md)
+
+</div>
+
+<div align="center">
+
# Zen C
**Modern Ergonomics. Zero Overhead. Pure C.**
@@ -43,9 +49,11 @@ Join the discussion, share demos, ask questions, or report bugs in the official
- [Arrays](#arrays)
- [Tuples](#tuples)
- [Structs](#structs)
+ - [Opaque Structs](#opaque-structs)
- [Enums](#enums)
- [Unions](#unions)
- [Type Aliases](#type-aliases)
+ - [Opaque Type Aliases](#opaque-type-aliases)
- [4. Functions & Lambdas](#4-functions--lambdas)
- [Functions](#functions)
- [Const Arguments](#const-arguments)
@@ -91,6 +99,7 @@ Join the discussion, share demos, ask questions, or report bugs in the official
- [Volatile](#volatile)
- [Named Constraints](#named-constraints)
- [15. Build Directives](#15-build-directives)
+ - [16. Keywords](#16-keywords)
- [Standard Library](#standard-library)
- [Tooling](#tooling)
- [Language Server (LSP)](#language-server-lsp)
@@ -100,6 +109,8 @@ Join the discussion, share demos, ask questions, or report bugs in the official
- [Building with Zig](#building-with-zig)
- [C++ Interop](#c-interop)
- [CUDA Interop](#cuda-interop)
+ - [Objective-C Interop](#objective-c-interop)
+ - [C23 Support](#c23-support)
- [Contributing](#contributing)
- [Attributions](#attributions)
@@ -154,7 +165,7 @@ zc repl
### Environment Variables
-You can set `ZC_ROOT` to specify the location of the Standard Library (standard imports like `import "std/vector.zc"`). This allows you to run `zc` from any directory.
+You can set `ZC_ROOT` to specify the location of the Standard Library (standard imports like `import "std/vec.zc"`). This allows you to run `zc` from any directory.
```bash
export ZC_ROOT=/path/to/Zen-C
@@ -187,6 +198,8 @@ let y: const int = 10; // Read-only (Type qualified)
// y = 20; // Error: cannot assign to const
```
+> **Type Inference**: Zen C automatically infers types for initialized variables. It compiles to C23 `auto` on supported compilers, or GCC's `__auto_type` extension otherwise.
+
### 2. Primitive Types
| Type | C Equivalent | Description |
@@ -201,6 +214,8 @@ let y: const int = 10; // Read-only (Type qualified)
| `char` | `char` | Single character |
| `string` | `char*` | C-string (null-terminated) |
| `U0`, `u0`, `void` | `void` | Empty type |
+| `iN` (for example, `i256`) | `_BitInt(N)` | Arbitrary bit-width signed integer (C23) |
+| `uN` (for example, `u42`) | `unsigned _BitInt(N)` | Arbitrary bit-width unsigned integer (C23) |
### 3. Aggregate Types
@@ -261,6 +276,29 @@ struct Flags {
> **Note**: Structs use [Move Semantics](#move-semantics--copy-safety) by default. Fields can be accessed via `.` even on pointers (Auto-Dereference).
+#### Opaque Structs
+You can define a struct as `opaque` to restrict access to its fields to the defining module only, while still allowing the struct to be allocated on the stack (size is known).
+
+```zc
+// In user.zc
+opaque struct User {
+ id: int;
+ name: string;
+}
+
+fn new_user(name: string) -> User {
+ return User{id: 1, name: name}; // OK: Inside module
+}
+
+// In main.zc
+import "user.zc";
+
+fn main() {
+ let u = new_user("Alice");
+ // let id = u.id; // Error: Cannot access private field 'id'
+}
+```
+
#### Enums
Tagged unions (Sum types) capable of holding data.
```zc
@@ -287,6 +325,27 @@ alias ID = int;
alias PointMap = Map<string, Point>;
```
+#### Opaque Type Aliases
+You can define a type alias as `opaque` to create a new type that is distinct from its underlying type outside of the defining module. This provides strong encapsulation and type safety without the runtime overhead of a wrapper struct.
+
+```zc
+// In library.zc
+opaque alias Handle = int;
+
+fn make_handle(v: int) -> Handle {
+ return v; // Implicit conversion allowed inside module
+}
+
+// In main.zc
+import "library.zc";
+
+fn main() {
+ let h: Handle = make_handle(42);
+ // let i: int = h; // Error: Type validation failed
+ // let h2: Handle = 10; // Error: Type validation failed
+}
+```
+
### 4. Functions & Lambdas
#### Functions
@@ -435,8 +494,15 @@ for i in 0..<10 { ... } // Exclusive (Explicit)
for i in 0..=10 { ... } // Inclusive (0 to 10)
for i in 0..10 step 2 { ... }
-// Iterator (Vec, Array, or custom Iterable)
-for item in collection { ... }
+// Iterator (Vec or custom Iterable)
+for item in vec { ... }
+
+// Iterate over fixed-size arrays directly
+let arr: int[5] = [1, 2, 3, 4, 5];
+for val in arr {
+ // val is int
+ println "{val}";
+}
// While
while x < 10 { ... }
@@ -478,6 +544,11 @@ Zen C supports operator overloading for user-defined structs by implementing spe
| **Index** | `a[i]` | `get(a, i)` |
| | `a[i] = v` | `set(a, i, v)` |
+> **Note on String Equality**:
+> - `string == string` performs **value comparison** (equivalent to `strcmp`).
+> - `char* == char*` performs **pointer comparison** (checks memory addresses).
+> - Mixed comparisons (e.g. `string == char*`) default to **pointer comparison**.
+
**Example:**
```zc
impl Point {
@@ -543,7 +614,7 @@ Zen C supports a shorthand for prompting user input using the `?` prefix.
- `? "Enter age: " (age)`: Prints prompt and scans input into the variable `age`.
- Format specifiers are automatically inferred based on variable type.
-```c
+```zc
let age: int;
? "How old are you? " (age);
println "You are {age} years old.";
@@ -875,9 +946,10 @@ Decorate functions and structs to modify compiler behavior.
| `@host` | Fn | CUDA: Host function (`__host__`). |
| `@comptime` | Fn | Helper function available for compile-time execution. |
| `@derive(...)` | Struct | Auto-implement traits. Supports `Debug`, `Eq` (Smart Derive), `Copy`, `Clone`. |
+| `@ctype("type")` | Fn Param | Overrides generated C type for a parameter. |
| `@<custom>` | Any | Passes generic attributes to C (e.g. `@flatten`, `@alias("name")`). |
-### Custom Attributes
+#### Custom Attributes
Zen C supports a powerful **Custom Attribute** system that allows you to use any GCC/Clang `__attribute__` directly in your code. Any attribute that is not explicitly recognized by the Zen C compiler is treated as a generic attribute and passed through to the generated C code.
@@ -889,7 +961,7 @@ Zen C attributes are mapped directly to C attributes:
- `@name(args)` → `__attribute__((name(args)))`
- `@name("string")` → `__attribute__((name("string")))`
-### Smart Derives
+#### Smart Derives
Zen C provides "Smart Derives" that respect Move Semantics:
@@ -955,12 +1027,33 @@ Zen C supports special comments at the top of your source file to configure the
| `//> link:` | `-lfoo` or `path/to/lib.a` | Link against a library or object file. |
| `//> lib:` | `path/to/libs` | Add a library search path (`-L`). |
| `//> include:` | `path/to/headers` | Add an include search path (`-I`). |
+| `//> framework:` | `Cocoa` | Link against a macOS framework. |
| `//> cflags:` | `-Wall -O3` | Pass arbitrary flags to the C compiler. |
| `//> define:` | `MACRO` or `KEY=VAL` | Define a preprocessor macro (`-D`). |
| `//> pkg-config:` | `gtk+-3.0` | Run `pkg-config` and append `--cflags` and `--libs`. |
| `//> shell:` | `command` | Execute a shell command during the build. |
| `//> get:` | `http://url/file` | Download a file if specific file does not exist. |
+#### Features
+
+**1. OS Guarding**
+Prefix directives with an OS name to apply them only on specific platforms.
+Supported prefixes: `linux:`, `windows:`, `macos:` (or `darwin:`).
+
+```zc
+//> linux: link: -lm
+//> windows: link: -lws2_32
+//> macos: framework: Cocoa
+```
+
+**2. Environment Variable Expansion**
+Use `${VAR}` syntax to expand environment variables in your directives.
+
+```zc
+//> include: ${HOME}/mylib/include
+//> lib: ${ZC_ROOT}/std
+```
+
#### Examples
```zc
@@ -975,6 +1068,29 @@ import "raylib.h"
fn main() { ... }
```
+### 16. Keywords
+
+The following keywords are reserved in Zen C.
+
+#### Declarations
+`alias`, `def`, `enum`, `fn`, `impl`, `import`, `let`, `module`, `opaque`, `struct`, `trait`, `union`, `use`
+
+#### Control Flow
+`async`, `await`, `break`, `catch`, `continue`, `defer`, `else`, `for`, `goto`, `guard`, `if`, `loop`, `match`, `return`, `try`, `unless`, `while`
+
+#### Special
+`asm`, `assert`, `autofree`, `comptime`, `const`, `embed`, `launch`, `ref`, `sizeof`, `static`, `test`, `volatile`
+
+#### Constants
+`true`, `false`, `null`
+
+#### C Reserved
+The following identifiers are reserved because they are keywords in C11:
+`auto`, `case`, `char`, `default`, `do`, `double`, `extern`, `float`, `inline`, `int`, `long`, `register`, `restrict`, `short`, `signed`, `switch`, `typedef`, `unsigned`, `void`, `_Atomic`, `_Bool`, `_Complex`, `_Generic`, `_Imaginary`, `_Noreturn`, `_Static_assert`, `_Thread_local`
+
+#### Operators
+`and`, `or`
+
---
## Standard Library
@@ -997,6 +1113,13 @@ Zen C includes a standard library (`std`) covering essential functionality.
| **`std/result.zc`** | Error handling (`Ok`/`Err`). | [Docs](docs/std/result.md) |
| **`std/path.zc`** | Cross-platform path manipulation. | [Docs](docs/std/path.md) |
| **`std/env.zc`** | Process environment variables. | [Docs](docs/std/env.md) |
+| **`std/net.zc`** | TCP networking (Sockets). | [Docs](docs/std/net.md) |
+| **`std/thread.zc`** | Threads and Synchronization. | [Docs](docs/std/thread.md) |
+| **`std/time.zc`** | Time measurement and sleep. | [Docs](docs/std/time.md) |
+| **`std/json.zc`** | JSON parsing and serialization. | [Docs](docs/std/json.md) |
+| **`std/stack.zc`** | LIFO Stack `Stack<T>`. | [Docs](docs/std/stack.md) |
+| **`std/set.zc`** | Generic Hash Set `Set<T>`. | [Docs](docs/std/set.md) |
+| **`std/process.zc`** | Process execution and management. | [Docs](docs/std/process.md) |
---
@@ -1185,7 +1308,7 @@ fn add_kernel(a: float*, b: float*, c: float*, n: int) {
}
fn main() {
- const N = 1024;
+ def N = 1024;
let d_a = cuda_alloc<float>(N);
let d_b = cuda_alloc<float>(N);
let d_c = cuda_alloc<float>(N);
@@ -1227,6 +1350,45 @@ let tid = local_id();
> **Note:** The `--cuda` flag sets `nvcc` as the compiler and implies `--cpp` mode. Requires the NVIDIA CUDA Toolkit.
+### C23 Support
+
+Zen C supports modern C23 features when using a compatible backend compiler (GCC 14+, Clang 14+, TCC (partial)).
+
+- **`auto`**: Zen C automatically maps type inference to standard C23 `auto` if `__STDC_VERSION__ >= 202300L`.
+- **`_BitInt(N)`**: Use `iN` and `uN` types (e.g., `i256`, `u12`, `i24`) to access C23 arbitrary-width integers.
+
+### Objective-C Interop
+
+Zen C can compile to Objective-C (`.m`) using the `--objc` flag, allowing you to use Objective-C frameworks (like Cocoa/Foundation) and syntax.
+
+```bash
+# Compile with clang (or gcc/gnustep)
+zc app.zc --objc --cc clang
+```
+
+#### Using Objective-C in Zen C
+
+Use `include` for headers and `raw` blocks for Objective-C syntax (`@interface`, `[...]`, `@""`).
+
+```zc
+//> macos: framework: Foundation
+//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS
+//> linux: link: -lgnustep-base -lobjc
+
+include <Foundation/Foundation.h>
+
+fn main() {
+ raw {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSLog(@"Hello from Objective-C!");
+ [pool drain];
+ }
+ println "Zen C works too!";
+}
+```
+
+> **Note:** Zen C string interpolation works with Objective-C objects (`id`) by calling `debugDescription` or `description`.
+
---
## Contributing
@@ -1267,10 +1429,8 @@ make test
## Attributions
-This project uses the following third-party libraries:
-
+This project uses third-party libraries. Full license texts can be found in the `LICENSES/` directory.
* **[cJSON](https://github.com/DaveGamble/cJSON)** (MIT License): Used for JSON parsing and generation in the Language Server.
- * Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
* **[zc-ape](https://github.com/OEvgeny/zc-ape)** (MIT License): The original Actually Portable Executable port of Zen-C by [Eugene Olonov](https://github.com/OEvgeny).
* **[Cosmopolitan Libc](https://github.com/jart/cosmopolitan)** (ISC License): The foundational library that makes APE possible.
diff --git a/README_ES.md b/README_ES.md
new file mode 100644
index 0000000..d73e9ca
--- /dev/null
+++ b/README_ES.md
@@ -0,0 +1,1436 @@
+
+<div align="center">
+
+[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md)
+
+</div>
+
+<div align="center">
+
+# Zen C
+
+**Ergonomía Moderna. Cero Sobrecarga. C Puro.**
+
+[![Estado de la Construcción](https://img.shields.io/badge/build-passing-brightgreen)]()
+[![Licencia](https://img.shields.io/badge/license-MIT-blue)]()
+[![Versión](https://img.shields.io/badge/version-0.1.0-orange)]()
+[![Plataforma](https://img.shields.io/badge/platform-linux-lightgrey)]()
+
+*Escribe como un lenguaje de alto nivel, ejecuta como C.*
+
+</div>
+
+---
+
+## Descripción General
+
+**Zen C** es un lenguaje de programación de sistemas moderno que se compila a `GNU C`/`C11` legible por humanos. Proporciona un conjunto rico de características que incluyen inferencia de tipos, coincidencia de patrones (pattern matching), genéricos, traits, async/await y gestión manual de memoria con capacidades RAII, todo manteniendo una compatibilidad total con el ABI de C.
+
+## Comunidad
+
+¡Únete a la discusión, comparte demos, haz preguntas o reporta errores en el servidor oficial de Discord de Zen C!
+
+- Discord: [Únete aquí](https://discord.com/invite/q6wEsCmkJP)
+
+---
+
+## Índice
+
+- [Descripción General](#descripción-general)
+- [Comunidad](#comunidad)
+- [Inicio Rápido](#inicio-rápido)
+ - [Instalación](#instalación)
+ - [Uso](#uso)
+ - [Variables de Entorno](#variables-de-entorno)
+- [Referencia del Lenguaje](#referencia-del-lenguaje)
+ - [1. Variables y Constantes](#1-variables-y-constantes)
+ - [2. Tipos Primitivos](#2-tipos-primitivos)
+ - [3. Tipos Agregados](#3-tipos-agregados)
+ - [Arrays](#arrays)
+ - [Tuplas](#tuplas)
+ - [Structs](#structs)
+ - [Structs Opacos](#structs-opacos)
+ - [Enums](#enums)
+ - [Uniones](#uniones)
+ - [Alias de Tipos](#alias-de-tipos)
+ - [Alias de Tipos Opacos](#alias-de-tipos-opacos)
+ - [4. Funciones y Lambdas](#4-funciones-y-lambdas)
+ - [Funciones](#funciones)
+ - [Argumentos Const](#argumentos-const)
+ - [Argumentos por Defecto](#argumentos-por-defecto)
+ - [Lambdas (Clausuras)](#lambdas-clausuras)
+ - [Punteros a Funciones Crudos](#punteros-a-funciones-crudos)
+ - [Funciones Variádicas](#funciones-variádicas)
+ - [5. Flujo de Control](#5-flujo-de-control)
+ - [Condicionales](#condicionales)
+ - [Coincidencia de Patrones](#coincidencia-de-patrones)
+ - [Bucles](#bucles)
+ - [Control Avanzado](#control-avanzado)
+ - [6. Operadores](#6-operadores)
+ - [Operadores Sobrecargables](#operadores-sobrecargables)
+ - [Azúcar Sintáctico](#azúcar-sintáctico)
+ - [7. Impresión e Interpolación de Cadenas](#7-impresión-e-interpolación-de-cadenas)
+ - [Palabras Clave](#palabras-clave)
+ - [Abreviaturas](#abreviaturas)
+ - [Interpolación de Cadenas (F-strings)](#interpolación-de-cadenas-f-strings)
+ - [Prompts de Entrada (`?`)](#prompts-de-entrada-)
+ - [8. Gestión de Memoria](#8-gestión-de-memoria)
+ - [Defer](#defer)
+ - [Autofree](#autofree)
+ - [Semántica de Recursos (Movimiento por Defecto)](#semántica-de-recursos-movimiento-por-defecto)
+ - [RAII / Drop Trait](#raii--drop-trait)
+ - [9. Programación Orientada a Objetos](#9-programación-orientada-a-objetos)
+ - [Métodos](#métodos)
+ - [Traits](#traits)
+ - [Traits Estándar](#traits-estándar)
+ - [Composición](#composición)
+ - [10. Genéricos](#10-genéricos)
+ - [11. Concurrencia (Async/Await)](#11-concurrencia-asyncawait)
+ - [12. Metaprogramación](#12-metaprogramación)
+ - [Comptime](#comptime)
+ - [Embed](#embed)
+ - [Plugins](#plugins)
+ - [Macros de C Genéricas](#macros-de-c-genéricas)
+ - [13. Atributos](#13-atributos)
+ - [Atributos Personalizados](#atributos-personalizados)
+ - [Derivaciones Inteligentes](#derivaciones-inteligentes)
+ - [14. Ensamblador Inline](#14-ensamblador-inline)
+ - [Uso Básico](#uso-básico)
+ - [Volatile](#volatile)
+ - [Restricciones con Nombre](#restricciones-con-nombre)
+ - [15. Directivas de Construcción](#15-directivas-de-construcción)
+ - [16. Palabras Clave](#16-palabras-clave)
+- [Biblioteca Estándar](#biblioteca-estándar)
+- [Herramientas](#herramientas)
+ - [Servidor de Lenguaje (LSP)](#servidor-de-lenguaje-lsp)
+ - [REPL](#repl)
+- [Soporte del Compilador y Compatibilidad](#soporte-del-compilador-y-compatibilidad)
+ - [Estado de la Suite de Pruebas](#estado-de-la-suite-de-pruebas)
+ - [Construyendo con Zig](#construyendo-con-zig)
+ - [Interop con C++](#interop-con-c)
+ - [Interop con CUDA](#interop-con-cuda)
+ - [Interop con Objective-C](#interop-con-objective-c)
+- [Contribuyendo](#contribuyendo)
+- [Atribuciones](#atribuciones)
+
+---
+
+## Inicio Rápido
+
+### Instalación
+
+```bash
+git clone https://github.com/z-libs/Zen-C.git
+cd Zen-C
+make
+sudo make install
+```
+
+### Construcción Portable (APE)
+
+Zen C puede compilarse como un **Ejecutable Realmente Portable (APE)** usando [Cosmopolitan Libc](https://github.com/jart/cosmopolitan). Esto produce un único binario (`.com`) que se ejecuta de forma nativa en Linux, macOS, Windows, FreeBSD, OpenBSD y NetBSD en arquitecturas x86_64 y aarch64.
+
+**Prerrequisitos:**
+- Toolchain `cosmocc` (debe estar en tu PATH)
+
+**Construcción e Instalación:**
+```bash
+make ape
+sudo env "PATH=$PATH" make install-ape
+```
+
+**Artefactos:**
+- `out/bin/zc.com`: El compilador Zen-C portable. Incluye la biblioteca estándar embebida dentro del ejecutable.
+- `out/bin/zc-boot.com`: Un instalador bootstrap autónomo para configurar nuevos proyectos Zen-C.
+
+**Uso:**
+```bash
+# Ejecutar en cualquier SO compatible
+./out/bin/zc.com build hello.zc -o hello
+```
+
+### Uso
+
+```bash
+# Compilar y ejecutar
+zc run hello.zc
+
+# Construir ejecutable
+zc build hello.zc -o hello
+
+# Shell Interactiva
+zc repl
+```
+
+### Variables de Entorno
+
+Puedes configurar `ZC_ROOT` para especificar la ubicación de la Biblioteca Estándar (importaciones estándar como `import "std/vector.zc"`). Esto te permite ejecutar `zc` desde cualquier directorio.
+
+```bash
+export ZC_ROOT=/ruta/a/Zen-C
+```
+
+---
+
+## Referencia del Lenguaje
+
+### 1. Variables y Constantes
+
+Zen C distingue entre constantes en tiempo de compilación y variables en tiempo de ejecución.
+
+#### Constantes Manifiestas (`def`)
+Valores que existen solo en tiempo de compilación (se pliegan en el código). Úsalos para tamaños de arrays, configuración fija y números mágicos.
+
+```zc
+def MAX_SIZE = 1024;
+let buffer: char[MAX_SIZE]; // Tamaño de array válido
+```
+
+#### Variables (`let`)
+Ubicaciones de almacenamiento en memoria. Pueden ser mutables o de solo lectura (`const`).
+
+```zc
+let x = 10; // Mutable
+x = 20; // OK
+
+let y: const int = 10; // Solo lectura (Calificado por tipo)
+// y = 20; // Error: no se puede asignar a una constante
+```
+
+> **Inferencia de tipos**: Zen C infiere automáticamente los tipos para variables inicializadas. Se compila a `auto` de C23 en compiladores compatibles, o a la extensión `__auto_type` de GCC en otros casos.
+
+### 2. Tipos Primitivos
+
+| Tipo | Equivalente en C | Descripción |
+|:---|:---|:---|
+| `int`, `uint` | `int`, `unsigned int` | Entero estándar de la plataforma |
+| `I8` .. `I128` o `i8` .. `i128` | `int8_t` .. `__int128_t` | Enteros con signo de ancho fijo |
+| `U8` .. `U128` o `u8` .. `u128` | `uint8_t` .. `__uint128_t` | Enteros sin signo de ancho fijo |
+| `isize`, `usize` | `ptrdiff_t`, `size_t` | Enteros del tamaño de un puntero |
+| `byte` | `uint8_t` | Alias para U8 |
+| `F32`, `F64` o `f32`, `f64` | `float`, `double` | Números de coma flotante |
+| `bool` | `bool` | `true` o `false` |
+| `char` | `char` | Carácter único |
+| `string` | `char*` | Cadena de C (terminada en null) |
+| `U0`, `u0`, `void` | `void` | Tipo vacío |
+| `iN` (ej. `i256`) | `_BitInt(N)` | Entero con signo de ancho arbitrario (C23) |
+| `uN` (ej. `u42`) | `unsigned _BitInt(N)` | Entero sin signo de ancho arbitrario (C23) |
+
+### 3. Tipos Agregados
+
+#### Arrays
+Arrays de tamaño fijo con semántica de valor.
+```zc
+def SIZE = 5;
+let ints: int[SIZE] = [1, 2, 3, 4, 5];
+let zeros: [int; SIZE]; // Inicializado a cero
+```
+
+#### Tuplas
+Agrupa múltiples valores, accede a los elementos por índice.
+```zc
+let pair = (1, "Hola");
+let x = pair.0; // 1
+let s = pair.1; // "Hola"
+```
+
+**Múltiples Valores de Retorno**
+
+Las funciones pueden retornar tuplas para proporcionar múltiples resultados:
+```zc
+fn sumar_y_restar(a: int, b: int) -> (int, int) {
+ return (a + b, a - b);
+}
+
+let resultado = sumar_y_restar(3, 2);
+let suma = resultado.0; // 5
+let resta = resultado.1; // 1
+```
+
+**Desestructuración**
+
+Las tuplas pueden desestructurarse directamente en variables:
+```zc
+let (suma, resta) = sumar_y_restar(3, 2);
+// suma = 5, resta = 1
+```
+
+#### Structs
+Estructuras de datos con campos de bits opcionales.
+```zc
+struct Point {
+ x: int;
+ y: int;
+}
+
+// Inicialización de struct
+let p = Point { x: 10, y: 20 };
+
+// Campos de bits
+struct Flags {
+ valid: U8 : 1;
+ mode: U8 : 3;
+}
+```
+
+> **Nota**: Los structs usan [Semántica de Movimiento](#semántica-de-recursos-movimiento-por-defecto) por defecto. Los campos se pueden acceder mediante `.` incluso en punteros (Auto-Dereferencia).
+
+#### Structs Opacos
+Puedes definir un struct como `opaque` para restringir el acceso a sus campos solo al módulo que lo define, permitiendo aún que el struct sea asignado en el stack (el tamaño es conocido).
+
+```zc
+// En user.zc
+opaque struct User {
+ id: int;
+ name: string;
+}
+
+fn new_user(name: string) -> User {
+ return User{id: 1, name: name}; // OK: Dentro del módulo
+}
+
+// En main.zc
+import "user.zc";
+
+fn main() {
+ let u = new_user("Alice");
+ // let id = u.id; // Error: No se puede acceder al campo privado 'id'
+}
+```
+
+#### Enums
+Uniones etiquetadas (Tipos suma) capaces de contener datos.
+```zc
+enum Shape {
+ Circle(float), // Contiene el radio
+ Rect(float, float), // Contiene ancho y alto
+ Point // Sin datos
+}
+```
+
+#### Uniones
+Uniones estándar de C (acceso inseguro).
+```zc
+union Data {
+ i: int;
+ f: float;
+}
+```
+
+#### Alias de Tipos
+Crea un nuevo nombre para un tipo existente.
+```zc
+alias ID = int;
+alias PointMap = Map<string, Point>;
+```
+
+#### Alias de Tipos Opacos
+Puedes definir un alias de tipo como `opaque` para crear un nuevo tipo que sea distinto de su tipo subyacente fuera del módulo que lo define. Esto proporciona una fuerte encapsulación y seguridad de tipos sin la sobrecarga en tiempo de ejecución de un struct envoltorio.
+
+```zc
+// En library.zc
+opaque alias Handle = int;
+
+fn make_handle(v: int) -> Handle {
+ return v; // Conversión implícita permitida dentro del módulo
+}
+
+// En main.zc
+import "library.zc";
+
+fn main() {
+ let h: Handle = make_handle(42);
+ // let i: int = h; // Error: Falló la validación de tipos
+ // let h2: Handle = 10; // Error: Falló la validación de tipos
+}
+```
+
+### 4. Funciones y Lambdas
+
+#### Funciones
+```zc
+fn suma(a: int, b: int) -> int {
+ return a + b;
+}
+
+// Argumentos con nombre soportados en las llamadas
+suma(a: 10, b: 20);
+```
+
+> **Nota**: Los argumentos con nombre deben seguir estrictamente el orden de los parámetros definidos. `suma(b: 20, a: 10)` es inválido.
+
+#### Argumentos Const
+Los argumentos de las funciones pueden marcarse como `const` para imponer una semántica de solo lectura. Este es un calificador de tipo, no una constante manifiesta.
+
+```zc
+fn print_val(v: const int) {
+ // v = 10; // Error: No se puede asignar a una variable const
+ println "{v}";
+}
+```
+
+#### Argumentos por Defecto
+Las funciones pueden definir valores por defecto para los argumentos finales. Estos pueden ser literales, expresiones o código válido de Zen C (como constructores de structs).
+```zc
+// Valor por defecto simple
+fn incrementar(val: int, cantidad: int = 1) -> int {
+ return val + cantidad;
+}
+
+// Valor por defecto por expresión (evaluado en el sitio de la llamada)
+fn offset(val: int, pad: int = 10 * 2) -> int {
+ return val + pad;
+}
+
+// Valor por defecto de tipo struct
+struct Config { debug: bool; }
+fn init(cfg: Config = Config { debug: true }) {
+ if cfg.debug { println "Modo Debug"; }
+}
+
+fn main() {
+ incrementar(10); // 11
+ offset(5); // 25
+ init(); // Imprime "Modo Debug"
+}
+```
+
+#### Lambdas (Clausuras)
+Funciones anónimas que pueden capturar su entorno.
+```zc
+let factor = 2;
+let doble = x -> x * factor; // Sintaxis de flecha
+let completo = fn(x: int) -> int { return x * factor; }; // Sintaxis de bloque
+```
+
+#### Punteros a Funciones Crudos
+Zen C soporta punteros a funciones de C crudos usando la sintaxis `fn*`. Esto permite una interoperabilidad perfecta con bibliotecas de C que esperan punteros a funciones sin la sobrecarga de las clausuras.
+
+```zc
+// Función que recibe un puntero a función crudo
+fn set_callback(cb: fn*(int)) {
+ cb(42);
+}
+
+// Función que retorna un puntero a función crudo
+fn get_callback() -> fn*(int) {
+ return mi_manejador;
+}
+
+// Se soportan punteros a punteros de funciones (fn**)
+let pptr: fn**(int) = &ptr;
+```
+
+#### Funciones Variádicas
+Las funciones pueden aceptar un número variable de argumentos usando `...` y el tipo `va_list`.
+```zc
+fn log(lvl: int, fmt: char*, ...) {
+ let ap: va_list;
+ va_start(ap, fmt);
+ vprintf(fmt, ap); // Usa stdio de C
+ va_end(ap);
+}
+```
+
+### 5. Flujo de Control
+
+#### Condicionales
+```zc
+if x > 10 {
+ print("Grande");
+} else if x > 5 {
+ print("Mediano");
+} else {
+ print("Pequeño");
+}
+
+// Ternario
+let y = x > 10 ? 1 : 0;
+```
+
+#### Coincidencia de Patrones (Pattern Matching)
+Una alternativa potente al `switch`.
+```zc
+match val {
+ 1 => { print "Uno" },
+ 2 || 3 => { print "Dos o Tres" }, // OR con ||
+ 4 or 5 => { print "Cuatro o Cinco" }, // OR con 'or'
+ 6, 7, 8 => { print "Seis a Ocho" }, // OR con coma
+ 10 .. 15 => { print "10 a 14" }, // Rango exclusivo (Legado)
+ 10 ..< 15 => { print "10 a 14" }, // Rango exclusivo (Explícito)
+ 20 ..= 25 => { print "20 a 25" }, // Rango inclusivo
+ _ => { print "Otro" },
+}
+
+// Desestructuración de Enums
+match shape {
+ Shape::Circle(r) => println "Radio: {r}",
+ Shape::Rect(w, h) => println "Área: {w*h}",
+ Shape::Point => println "Punto"
+}
+```
+
+#### Vinculación por Referencia (Reference Binding)
+Para inspeccionar un valor sin tomar posesión de él (sin moverlo), usa la palabra clave `ref` en el patrón. Esto es esencial para tipos que implementan la Semántica de Movimiento (como `Option`, `Result`, structs que no son Copy).
+
+```zc
+let opt = Some(ValorNoCopy{...});
+match opt {
+ Some(ref x) => {
+ // 'x' es un puntero al valor dentro de 'opt'
+ // 'opt' NO se mueve ni se consume aquí
+ println "{x.field}";
+ },
+ None => {}
+}
+```
+
+#### Bucles
+```zc
+// Rango
+for i in 0..10 { ... } // Exclusivo (0 al 9)
+for i in 0..<10 { ... } // Exclusivo (Explícito)
+for i in 0..=10 { ... } // Inclusivo (0 al 10)
+for i in 0..10 step 2 { ... }
+
+// Iterador (Vec o Iterable personalizado)
+for item in vec { ... }
+
+// Iterar sobre arrays de tamaño fijo directamente
+let arr: int[5] = [1, 2, 3, 4, 5];
+for val in arr {
+ // val es int
+ println "{val}";
+}
+
+// While
+while x < 10 { ... }
+
+// Infinito con etiqueta
+externo: loop {
+ if terminado { break externo; }
+}
+
+// Repetir N veces
+for _ in 0..5 { ... }
+```
+
+
+#### Control Avanzado
+```zc
+// Guard: Ejecuta else y retorna si la condición es falsa
+guard ptr != NULL else { return; }
+
+// Unless: Si no es verdadero
+unless es_valido { return; }
+```
+
+### 6. Operadores
+
+Zen C soporta la sobrecarga de operadores para structs definidos por el usuario implementando nombres de métodos específicos.
+
+#### Operadores Sobrecargables
+
+| Categoría | Operador | Nombre del Método |
+|:---|:---|:---|
+| **Aritméticos** | `+`, `-`, `*`, `/`, `%` | `add`, `sub`, `mul`, `div`, `rem` |
+| **Comparación** | `==`, `!=` | `eq`, `neq` |
+| | `<`, `>`, `<=`, `>=` | `lt`, `gt`, `le`, `ge` |
+| **Bitwise** | `&`, `|`, `^` | `bitand`, `bitor`, `bitxor` |
+| | `<<`, `>>` | `shl`, `shr` |
+| **Unarios** | `-` | `neg` |
+| | `!` | `not` |
+| | `~` | `bitnot` |
+| **Índice** | `a[i]` | `get(a, i)` |
+| | `a[i] = v` | `set(a, i, v)` |
+
+> **Nota sobre la igualdad de cadenas**:
+> - `string == string` realiza una **comparación de valores** (equivalente a `strcmp`).
+> - `char* == char*` realiza una **comparación de punteros** (comprueba direcciones de memoria).
+> - Comparaciones mixtas (ej. `string == char*`) por defecto realizan una **comparación de punteros**.
+
+**Ejemplo:**
+```zc
+impl Point {
+ fn add(self, other: Point) -> Point {
+ return Point{x: self.x + other.x, y: self.y + other.y};
+ }
+}
+
+let p3 = p1 + p2; // Llama a p1.add(p2)
+```
+
+#### Azúcar Sintáctico
+
+Estos operadores son características integradas del lenguaje y no pueden sobrecargarse directamente.
+
+| Operador | Nombre | Descripción |
+|:---|:---|:---|
+| `|>` | Pipeline | `x |> f(y)` se desazucara a `f(x, y)` |
+| `??` | Null Coalescing | `val ?? default` retorna `default` si `val` es NULL (punteros) |
+| `??=` | Null Assignment | `val ??= init` asigna si `val` es NULL |
+| `?.` | Navegación Segura | `ptr?.campo` accede al campo solo si `ptr` no es NULL |
+| `?` | Operador Try | `res?` retorna el error si está presente (tipos Result/Option) |
+
+**Auto-Dereferencia**:
+El acceso a campos por puntero (`ptr.campo`) y las llamadas a métodos (`ptr.metodo()`) dereferencian automáticamente el puntero, equivalente a `(*ptr).campo`.
+
+### 7. Impresión e Interpolación de Cadenas
+
+Zen C proporciona opciones versátiles para imprimir en la consola, incluyendo palabras clave y abreviaturas concisas.
+
+#### Palabras Clave
+
+- `print "texto"`: Imprime en `stdout` sin un salto de línea al final.
+- `println "texto"`: Imprime en `stdout` con un salto de línea al final.
+- `eprint "texto"`: Imprime en `stderr` sin un salto de línea al final.
+- `eprintln "texto"`: Imprime en `stderr` con un salto de línea al final.
+
+#### Abreviaturas
+
+Zen C permite usar literales de cadena directamente como sentencias para una impresión rápida:
+
+- `"Hola Mundo"`: Equivalente a `println "Hola Mundo"`. (Añade salto de línea implícito)
+- `"Hola Mundo"..`: Equivalente a `print "Hola Mundo"`. (Sin salto de línea final)
+- `!"Error"`: Equivalente a `eprintln "Error"`. (Salida a stderr)
+- `!"Error"..`: Equivalente a `eprint "Error"`. (Salida a stderr, sin salto de línea)
+
+#### Interpolación de Cadenas (F-strings)
+
+Puedes embeber expresiones directamente dentro de literales de cadena usando la sintaxis `{}`. Esto funciona con todos los métodos de impresión y abreviaturas de cadena.
+
+```zc
+let x = 42;
+let nombre = "Zen";
+println "Valor: {x}, Nombre: {nombre}";
+"Valor: {x}, Nombre: {nombre}"; // abreviatura println
+```
+
+#### Prompts de Entrada (`?`)
+
+Zen C soporta una abreviatura para solicitar entrada al usuario usando el prefijo `?`.
+
+- `? "Texto del prompt"`: Imprime el prompt (sin salto de línea) y espera la entrada (lee una línea).
+- `? "Ingresa la edad: " (edad)`: Imprime el prompt y escanea la entrada en la variable `edad`.
+ - Los especificadores de formato se infieren automáticamente según el tipo de variable.
+
+```zc
+let edad: int;
+? "¿Cuántos años tienes? " (edad);
+println "Tienes {edad} años.";
+```
+
+### 8. Gestión de Memoria
+
+Zen C permite la gestión manual de memoria con ayudas ergonómicas.
+
+#### Defer
+Ejecuta código cuando el ámbito actual finaliza. Las sentencias defer se ejecutan en orden LIFO (último en entrar, primero en salir).
+```zc
+let f = fopen("archivo.txt", "r");
+defer fclose(f);
+```
+
+> Para prevenir comportamientos indefinidos, las sentencias de flujo de control (`return`, `break`, `continue`, `goto`) **no están permitidas** dentro de un bloque `defer`.
+
+#### Autofree
+Libera automáticamente la variable cuando finaliza el ámbito.
+```zc
+autofree let tipos = malloc(1024);
+```
+
+#### Semántica de Recursos (Movimiento por Defecto)
+Zen C trata los tipos con destructores (como `File`, `Vec` o punteros de malloc) como **Recursos**. Para prevenir errores de doble liberación (double-free), los recursos no pueden duplicarse implícitamente.
+
+- **Movimiento por Defecto**: La asignación de una variable de recurso transfiere la posesión. La variable original se vuelve inválida (Movida).
+- **Tipos Copy**: Los tipos sin destructores pueden optar por el comportamiento `Copy`, haciendo que la asignación sea una duplicación.
+
+**Diagnóstico y Filosofía**:
+Si ves un error "Use of moved value", el compilador te está diciendo: *"Este tipo posee un recurso (como memoria o un manejador) y copiarlo a ciegas es inseguro."*
+
+> **Contraste:** A diferencia de C/C++, Zen C no duplica implícitamente los valores que poseen recursos.
+
+**Argumentos de Función**:
+Pasar un valor a una función sigue las mismas reglas que la asignación: los recursos se mueven a menos que se pasen por referencia.
+
+```zc
+fn procesar(r: Recurso) { ... } // 'r' se mueve dentro de la función
+fn mirar(r: Recurso*) { ... } // 'r' es prestado (referencia)
+```
+
+**Clonación Explícita**:
+Si *realmente* quieres dos copias de un recurso, hazlo explícito:
+
+```zc
+let b = a.clone(); // Llama al método 'clone' del trait Clone
+```
+
+**Optar por Copy (Tipos de Valor)**:
+Para tipos pequeños sin destructores:
+
+```zc
+struct Point { x: int; y: int; }
+impl Copy for Point {} // Optar por la duplicación implícita
+
+fn main() {
+ let p1 = Point { x: 1, y: 2 };
+ let p2 = p1; // Copiado. p1 sigue siendo válido.
+}
+```
+
+#### RAII / Drop Trait
+Implementa `Drop` para ejecutar lógica de limpieza automáticamente.
+```zc
+impl Drop for MiEstructura {
+ fn drop(self) {
+ self.free();
+ }
+}
+```
+
+### 9. Programación Orientada a Objetos
+
+#### Métodos
+Define métodos en los tipos usando `impl`.
+```zc
+impl Point {
+ // Método estático (convención de constructor)
+ fn new(x: int, y: int) -> Self {
+ return Point{x: x, y: y};
+ }
+
+ // Método de instancia
+ fn dist(self) -> float {
+ return sqrt(self.x * self.x + self.y * self.y);
+ }
+}
+```
+
+#### Traits
+Define un comportamiento compartido.
+```zc
+struct Circle { radio: f32; }
+
+trait Dibujable {
+ fn dibujar(self);
+}
+
+impl Dibujable for Circle {
+ fn dibujar(self) { ... }
+}
+
+let circulo = Circle{};
+let dibujable: Dibujable = &circulo;
+```
+
+#### Traits Estándar
+Zen C incluye traits estándar que se integran con la sintaxis del lenguaje.
+
+**Iterable**
+
+Implementa `Iterable<T>` para habilitar bucles `for-in` para tus tipos personalizados.
+
+```zc
+import "std/iter.zc"
+
+// Define un Iterador
+struct MiIter {
+ actual: int;
+ final: int;
+}
+
+impl MiIter {
+ fn next(self) -> Option<int> {
+ if self.actual < self.final {
+ self.actual += 1;
+ return Option<int>::Some(self.actual - 1);
+ }
+ return Option<int>::None();
+ }
+}
+
+// Implementa Iterable
+impl MiRango {
+ fn iterator(self) -> MiIter {
+ return MiIter{actual: self.inicio, final: self.fin};
+ }
+}
+
+// Uso en un Bucle
+for i in mi_rango {
+ println "{i}";
+}
+```
+
+**Drop**
+
+Implementa `Drop` para definir un destructor que se ejecuta cuando el objeto sale de ámbito (RAII).
+
+```zc
+import "std/mem.zc"
+
+struct Recurso {
+ ptr: void*;
+}
+
+impl Drop for Recurso {
+ fn drop(self) {
+ if self.ptr != NULL {
+ free(self.ptr);
+ }
+ }
+}
+```
+
+> **Nota:** Si una variable es movida, no se llama a `drop` en la variable original. Se adhiere a la [Semántica de Recursos](#semántica-de-recursos-movimiento-por-defecto).
+
+**Copy**
+
+Trait marcador para optar por el comportamiento `Copy` (duplicación implícita) en lugar de la semántica de movimiento. Se usa mediante `@derive(Copy)`.
+
+> **Regla:** Los tipos que implementan `Copy` no deben definir un destructor (`Drop`).
+
+```zc
+@derive(Copy)
+struct Point { x: int; y: int; }
+
+fn main() {
+ let p1 = Point{x: 1, y: 2};
+ let p2 = p1; // ¡Copiado! p1 sigue siendo válido.
+}
+```
+
+**Clone**
+
+Implementa `Clone` para permitir la duplicación explícita de tipos que poseen recursos.
+
+```zc
+import "std/mem.zc"
+
+struct MiBox { val: int; }
+
+impl Clone for MiBox {
+ fn clone(self) -> MiBox {
+ return MiBox{val: self.val};
+ }
+}
+
+fn main() {
+ let b1 = MiBox{val: 42};
+ let b2 = b1.clone(); // Copia explícita
+}
+```
+
+#### Composición
+Usa `use` para embeber otros structs. Puedes mezclarlos (aplanar campos) o nombrarlos (anidar campos).
+
+```zc
+struct Entity { id: int; }
+
+struct Player {
+ // Mezcla (Mixin - Sin nombre): Aplana los campos
+ use Entity; // Añade 'id' a Player directamente
+ nombre: string;
+}
+
+struct Match {
+ // Composición (Con nombre): Anida los campos
+ use p1: Player; // Accedido mediante match.p1
+ use p2: Player; // Accedido mediante match.p2
+}
+```
+
+### 10. Genéricos
+
+Plantillas seguras para tipos para Structs y Funciones.
+
+```zc
+// Struct Genérico
+struct Box<T> {
+ item: T;
+}
+
+// Función Genérica
+fn identidad<T>(val: T) -> T {
+ return val;
+}
+
+// Genéricos con múltiples parámetros
+struct Par<K, V> {
+ llave: K;
+ valor: V;
+}
+```
+
+### 11. Concurrencia (Async/Await)
+
+Construido sobre pthreads.
+
+```zc
+async fn obtener_datos() -> string {
+ // Se ejecuta en segundo plano
+ return "Datos";
+}
+
+fn main() {
+ let futuro = obtener_datos();
+ let resultado = await futuro;
+}
+```
+
+### 12. Metaprogramación
+
+#### Comptime
+Ejecuta código en tiempo de compilación para generar código fuente o imprimir mensajes.
+```zc
+comptime {
+ // Genera código en tiempo de compilación (escrito en stdout)
+ println "let fecha_compilacion = \"2024-01-01\";";
+}
+
+println "Fecha de compilación: {fecha_compilacion}";
+```
+
+#### Embed
+Embebe archivos como los tipos especificados.
+```zc
+// Por defecto (Slice_char)
+let datos = embed "assets/logo.png";
+
+// Embed tipado
+let texto = embed "shader.glsl" as string; // Embebe como C-string
+let rom = embed "bios.bin" as u8[1024]; // Embebe como array fijo
+let wav = embed "sound.wav" as u8[]; // Embebe como Slice_u8
+```
+
+#### Plugins
+Importa plugins del compilador para extender la sintaxis.
+```zc
+import plugin "regex"
+let re = regex! { ^[a-z]+$ };
+```
+
+#### Macros de C Genéricas
+Pasa macros del preprocesador directamente a C.
+
+> **Consejo**: Para constantes simples, usa `def` en su lugar. Usa `#define` cuando necesites macros del preprocesador de C o flags de compilación condicional.
+
+```zc
+#define MAX_BUFFER 1024
+```
+
+### 13. Atributos
+
+Decora funciones y structs para modificar el comportamiento del compilador.
+
+| Atributo | Ámbito | Descripción |
+|:---|:---|:---|
+| `@must_use` | Fn | Advierte si el valor de retorno es ignorado. |
+| `@deprecated("msg")` | Fn/Struct | Advierte sobre el uso con un mensaje. |
+| `@inline` | Fn | Sugiere al compilador hacer inlininig. |
+| `@noinline` | Fn | Previene el inlining. |
+| `@packed` | Struct | Elimina el padding entre campos. |
+| `@align(N)` | Struct | Fuerza el alineamiento a N bytes. |
+| `@constructor` | Fn | Se ejecuta antes de main. |
+| `@destructor` | Fn | Se ejecuta después de que main termine. |
+| `@unused` | Fn/Var | Suprime advertencias de variables no usadas. |
+| `@weak` | Fn | Enlace de símbolo débil (weak symbol linkage). |
+| `@section("nombre")` | Fn | Coloca el código en una sección específica. |
+| `@noreturn` | Fn | La función no retorna (ej. exit). |
+| `@pure` | Fn | La función no tiene efectos secundarios (sugestión de optimización). |
+| `@cold` | Fn | Es poco probable que la función se ejecute (sugestión de predicción de saltos). |
+| `@hot` | Fn | La función se ejecuta frecuentemente (sugestión de optimización). |
+| `@export` | Fn/Struct | Exporta el símbolo (visibilidad por defecto). |
+| `@global` | Fn | CUDA: Punto de entrada del kernel (`__global__`). |
+| `@device` | Fn | CUDA: Función de dispositivo (`__device__`). |
+| `@host` | Fn | CUDA: Función de host (`__host__`). |
+| `@comptime` | Fn | Función auxiliar disponible para ejecución en tiempo de compilación. |
+| `@derive(...)` | Struct | Implementa traits automáticamente. Soporta `Debug`, `Eq` (Derivación Inteligente), `Copy`, `Clone`. |
+| `@ctype("tipo")` | Parámetro Fn | Sobrescribe el tipo C generado para un parámetro. |
+| `@<custom>` | Cualquier | Pasa atributos genéricos a C (ej. `@flatten`, `@alias("nombre")`). |
+
+#### Atributos Personalizados
+
+Zen C soporta un potente sistema de **Atributos Personalizados** que te permite usar cualquier `__attribute__` de GCC/Clang directamente en tu código. Cualquier atributo que no sea reconocido explícitamente por el compilador de Zen C es tratado como un atributo genérico y se pasa al código C generado.
+
+Esto proporciona acceso a características avanzadas del compilador, optimizaciones y directivas del enlazador sin necesidad de soporte explícito en el núcleo del lenguaje.
+
+#### Mapeo de Sintaxis
+Los atributos de Zen C se mapean directamente a atributos de C:
+- `@nombre` → `__attribute__((nombre))`
+- `@nombre(args)` → `__attribute__((nombre(args)))`
+- `@nombre("string")` → `__attribute__((nombre("string")))`
+
+#### Derivaciones Inteligentes
+
+Zen C proporciona "Derivaciones Inteligentes" que respetan la Semántica de Movimiento:
+
+- **`@derive(Eq)`**: Genera un método de igualdad que recibe los argumentos por referencia (`fn eq(self, other: T*)`).
+ - Al comparar dos structs que no son Copy (`a == b`), el compilador pasa automáticamente `b` por referencia (`&b`) para evitar moverlo.
+ - Las comprobaciones de igualdad recursivas en los campos también prefieren el acceso por puntero para prevenir la transferencia de posesión.
+
+### 14. Ensamblador Inline
+
+Zen C proporciona soporte de primera clase para ensamblador inline, transpilando directamente a `asm` extendido de estilo GCC.
+
+#### Uso Básico
+Escribe ensamblador crudo dentro de bloques `asm`. Las cadenas se concatenan automáticamente.
+```zc
+asm {
+ "nop"
+ "mfence"
+}
+```
+
+#### Volatile
+Previene que el compilador optimice y elimine el ensamblador que tiene efectos secundarios.
+```zc
+asm volatile {
+ "rdtsc"
+}
+```
+
+#### Restricciones con Nombre
+Zen C simplifica la compleja sintaxis de restricciones de GCC con vinculaciones con nombre.
+
+```zc
+// Sintaxis: : out(variable) : in(variable) : clobber(reg)
+// Usa la sintaxis de marcador de posición {variable} para legibilidad
+
+fn sumar(a: int, b: int) -> int {
+ let resultado: int;
+ asm {
+ "add {resultado}, {a}, {b}"
+ : out(resultado)
+ : in(a), in(b)
+ : clobber("cc")
+ }
+ return resultado;
+}
+```
+
+| Tipo | Sintaxis | Equivalente GCC |
+|:---|:---|:---|
+| **Salida** | `: out(variable)` | `"=r"(variable)` |
+| **Entrada** | `: in(variable)` | `"r"(variable)` |
+| **Clobber** | `: clobber("rax")` | `"rax"` |
+| **Memoria** | `: clobber("memory")` | `"memory"` |
+
+> **Nota:** Cuando uses la sintaxis de Intel (mediante `-masm=intel`), debes asegurarte de que tu construcción esté configurada correctamente (por ejemplo, `//> cflags: -masm=intel`). TCC no soporta el ensamblador con sintaxis Intel.
+
+### 15. Directivas de Construcción
+
+Zen C soporta comentarios especiales en la parte superior de tu archivo fuente para configurar el proceso de construcción sin necesidad de un complejo sistema de construcción o Makefile.
+
+| Directiva | Argumentos | Descripción |
+|:---|:---|:---|
+| `//> link:` | `-lfoo` o `ruta/a/lib.a` | Enlaza contra una biblioteca o archivo objeto. |
+| `//> lib:` | `ruta/a/libs` | Añade una ruta de búsqueda de biblioteca (`-L`). |
+| `//> include:` | `ruta/a/headers` | Añade una ruta de búsqueda de cabeceras (`-I`). |
+| `//> framework:` | `Cocoa` | Enlaza contra un framework de macOS. |
+| `//> cflags:` | `-Wall -O3` | Pasa flags arbitrarios al compilador de C. |
+| `//> define:` | `MACRO` o `LLAVE=VAL` | Define una macro del preprocesador (`-D`). |
+| `//> pkg-config:` | `gtk+-3.0` | Ejecuta `pkg-config` y añade `--cflags` y `--libs`. |
+| `//> shell:` | `comando` | Ejecuta un comando de shell durante la construcción. |
+| `//> get:` | `http://url/archivo` | Descarga un archivo si el archivo específico no existe. |
+
+#### Características
+
+**1. Protección de SO (OS Guarding)**
+Prefija las directivas con el nombre de un SO para aplicarlas solo en plataformas específicas.
+Prefijos soportados: `linux:`, `windows:`, `macos:` (o `darwin:`).
+
+```zc
+//> linux: link: -lm
+//> windows: link: -lws2_32
+//> macos: framework: Cocoa
+```
+
+**2. Expansión de Variables de Entorno**
+Usa la sintaxis `${VAR}` para expandir variables de entorno en tus directivas.
+
+```zc
+//> include: ${HOME}/mylib/include
+//> lib: ${ZC_ROOT}/std
+```
+
+#### Ejemplos
+
+```zc
+//> include: ./include
+//> lib: ./libs
+//> link: -lraylib -lm
+//> cflags: -Ofast
+//> pkg-config: gtk+-3.0
+
+import "raylib.h"
+
+fn main() { ... }
+```
+
+### 16. Palabras Clave
+
+Las siguientes palabras clave están reservadas en Zen C.
+
+#### Declaraciones
+`alias`, `def`, `enum`, `fn`, `impl`, `import`, `let`, `module`, `opaque`, `struct`, `trait`, `union`, `use`
+
+#### Flujo de Control
+`async`, `await`, `break`, `catch`, `continue`, `defer`, `else`, `for`, `goto`, `guard`, `if`, `loop`, `match`, `return`, `try`, `unless`, `while`
+
+#### Especiales
+`asm`, `assert`, `autofree`, `comptime`, `const`, `embed`, `launch`, `ref`, `sizeof`, `static`, `test`, `volatile`
+
+#### Constantes
+`true`, `false`, `null`
+
+#### Reservadas de C
+Los siguientes identificadores están reservados porque son palabras clave en C11:
+`auto`, `case`, `char`, `default`, `do`, `double`, `extern`, `float`, `inline`, `int`, `long`, `register`, `restrict`, `short`, `signed`, `switch`, `typedef`, `unsigned`, `void`, `_Atomic`, `_Bool`, `_Complex`, `_Generic`, `_Imaginary`, `_Noreturn`, `_Static_assert`, `_Thread_local`
+
+#### Operadores
+`and`, `or`
+
+---
+
+## Biblioteca Estándar
+
+Zen C incluye una biblioteca estándar (`std`) que cubre las funcionalidades esenciales.
+
+[Explorar la Documentación de la Biblioteca Estándar](docs/std/README.md)
+
+### Módulos Clave
+
+| Módulo | Descripción | Docs |
+| :--- | :--- | :--- |
+| **`std/vec.zc`** | Array dinámico creíble `Vec<T>`. | [Docs](docs/std/vec.md) |
+| **`std/string.zc`** | Tipo `String` asignado en el heap con soporte UTF-8. | [Docs](docs/std/string.md) |
+| **`std/queue.zc`** | Cola FIFO (Ring Buffer). | [Docs](docs/std/queue.md) |
+| **`std/map.zc`** | Mapa Hash Genérico `Map<V>`. | [Docs](docs/std/map.md) |
+| **`std/fs.zc`** | Operaciones del sistema de archivos. | [Docs](docs/std/fs.md) |
+| **`std/io.zc`** | Entrada/Salida estándar (`print`/`println`). | [Docs](docs/std/io.md) |
+| **`std/option.zc`** | Valores opcionales (`Some`/`None`). | [Docs](docs/std/option.md) |
+| **`std/result.zc`** | Gestión de errores (`Ok`/`Err`). | [Docs](docs/std/result.md) |
+| **`std/path.zc`** | Manipulación de rutas multiplataforma. | [Docs](docs/std/path.md) |
+| **`std/env.zc`** | Variables de entorno del proceso. | [Docs](docs/std/env.md) |
+| **`std/net.zc`** | Redes TCP (Sockets). | [Docs](docs/std/net.md) |
+| **`std/thread.zc`** | Hilos y Sincronización. | [Docs](docs/std/thread.md) |
+| **`std/time.zc`** | Medición de tiempo y espera (sleep). | [Docs](docs/std/time.md) |
+| **`std/json.zc`** | Parseo y serialización de JSON. | [Docs](docs/std/json.md) |
+| **`std/stack.zc`** | Pila LIFO `Stack<T>`. | [Docs](docs/std/stack.md) |
+| **`std/set.zc`** | Conjunto Hash Genérico `Set<T>`. | [Docs](docs/std/set.md) |
+| **`std/process.zc`** | Ejecución y gestión de procesos. | [Docs](docs/std/process.md) |
+
+---
+
+## Herramientas
+
+Zen C proporciona un Servidor de Lenguaje y un REPL integrados para mejorar la experiencia de desarrollo.
+
+### Servidor de Lenguaje (LSP)
+
+El Servidor de Lenguaje de Zen C (LSP) soporta las características estándar de LSP para integración con editores, proporcionando:
+
+* **Ir a la Definición**
+* **Encontrar Referencias**
+* **Información al pasar el ratón (Hover)**
+* **Autocompletado** (Nombres de funciones/structs, autocompletado tras punto para métodos/campos)
+* **Símbolos del Documento** (Esquema)
+* **Ayuda de Firma**
+* **Diagnósticos** (Errores sintácticos/semánticos)
+
+Para iniciar el servidor de lenguaje (normalmente configurado en los ajustes de LSP de tu editor):
+
+```bash
+zc lsp
+```
+
+Se comunica mediante I/O estándar (JSON-RPC 2.0).
+
+### REPL
+
+El bucle Read-Eval-Print te permite experimentar con el código de Zen C de forma interactiva.
+
+```bash
+zc repl
+```
+
+#### Características
+
+* **Codificación Interactiva**: Escribe expresiones o sentencias para su evaluación inmediata.
+* **Historial Persistente**: Los comandos se guardan en `~/.zprep_history`.
+* **Script de Inicio**: Carga automáticamente comandos desde `~/.zprep_init.zc`.
+
+#### Comandos
+
+| Comando | Descripción |
+|:---|:---|
+| `:help` | Muestra los comandos disponibles. |
+| `:reset` | Limpia el historial de la sesión actual (variables/funciones). |
+| `:vars` | Muestra las variables activas. |
+| `:funcs` | Muestra las funciones definidas por el usuario. |
+| `:structs` | Muestra los structs definidos por el usuario. |
+| `:imports` | Muestra las importaciones activas. |
+| `:history` | Muestra el historial de entrada de la sesión. |
+| `:type <expr>` | Muestra el tipo de una expresión. |
+| `:c <stmt>` | Muestra el código C generado para una sentencia. |
+| `:time <expr>` | Benchmark de una expresión (ejecuta 1000 iteraciones). |
+| `:edit [n]` | Edita el comando `n` (por defecto: el último) en `$EDITOR`. |
+| `:save <file>` | Guarda la sesión actual en un archivo `.zc`. |
+| `:load <file>` | Carga y ejecuta un archivo `.zc` en la sesión. |
+| `:watch <expr>` | Observa una expresión (se revalúa tras cada entrada). |
+| `:unwatch <n>` | Elimina una observación. |
+| `:undo` | Elimina el último comando de la sesión. |
+| `:delete <n>` | Elimina el comando en el índice `n`. |
+| `:clear` | Limpia la pantalla. |
+| `:quit` | Sale del REPL. |
+| `! <cmd>` | Ejecuta un comando de shell (ej. `!ls`). |
+
+---
+
+
+## Soporte del Compilador y Compatibilidad
+
+Zen C está diseñado para funcionar con la mayoría de los compiladores C11. Algunas características dependen de extensiones de GNU C, pero estas suelen funcionar en otros compiladores. Usa la flag `--cc` para cambiar de backend.
+
+```bash
+zc run app.zc --cc clang
+zc run app.zc --cc zig
+```
+
+### Estado de la Suite de Pruebas
+
+| Compilador | Tasa de Acierto | Características Soportadas | Limitaciones Conocidas |
+|:---|:---:|:---|:---|
+| **GCC** | **100%** | Todas las Características | Ninguna. |
+| **Clang** | **100%** | Todas las Características | Ninguna. |
+| **Zig** | **100%** | Todas las Características | Ninguna. Usa `zig cc` como reemplazo directo del compilador C. |
+| **TCC** | **~70%** | Sintaxis Básica, Genéricos, Traits | Sin `__auto_type`, Sin ASM Intel, Sin funciones anidadas. |
+
+> **Recomendación:** Usa **GCC**, **Clang** o **Zig** para construcciones de producción. TCC es excelente para el prototipado rápido debido a su velocidad de compilación, pero le faltan algunas extensiones de C avanzadas en las que confía Zen C para el soporte total de características.
+
+### Construyendo con Zig
+
+El comando `zig cc` de Zig proporciona un reemplazo directo para GCC/Clang con un excelente soporte de compilación cruzada (cross-compilation). Para usar Zig:
+
+```bash
+# Compilar y ejecutar un programa Zen C con Zig
+zc run app.zc --cc zig
+
+# Construir el propio compilador Zen C con Zig
+make zig
+```
+
+### Interop con C++
+
+Zen C puede generar código compatible con C++ con la flag `--cpp`, permitiendo una integración perfecta con bibliotecas de C++.
+
+```bash
+# Compilación directa con g++
+zc app.zc --cpp
+
+# O transpilar para construcción manual
+zc transpile app.zc --cpp
+g++ out.c mi_lib_cpp.o -o app
+```
+
+#### Usando C++ en Zen C
+
+Incluye cabeceras de C++ y usa bloques `raw` para el código C++:
+
+```zc
+include <vector>
+include <iostream>
+
+raw {
+ std::vector<int> hacer_vec(int a, int b) {
+ return {a, b};
+ }
+}
+
+fn main() {
+ let v = hacer_vec(1, 2);
+ raw { std::cout << "Tamaño: " << v.size() << std::endl; }
+}
+```
+
+> **Nota:** La flag `--cpp` cambia el backend a `g++` y emite código compatible con C++ (usa `auto` en lugar de `__auto_type`, sobrecarga de funciones en lugar de `_Generic`, y casts explícitos para `void*`).
+
+#### Interop con CUDA
+
+Zen C soporta la programación de GPU transpilando a **CUDA C++**. Esto te permite aprovechar las potentes características de C++ (plantillas, constexpr) dentro de tus kernels mientras mantienes la sintaxis ergonómica de Zen C.
+
+```bash
+# Compilación directa con nvcc
+zc run app.zc --cuda
+
+# O transpilar para construcción manual
+zc transpile app.zc --cuda -o app.cu
+nvcc app.cu -o app
+```
+
+#### Atributos Específicos de CUDA
+
+| Atributo | Equivalente CUDA | Descripción |
+|:---|:---|:---|
+| `@global` | `__global__` | Función de kernel (se ejecuta en GPU, se llama desde el host) |
+| `@device` | `__device__` | Función de dispositivo (se ejecuta en GPU, se llama desde GPU) |
+| `@host` | `__host__` | Función de host (explícitamente solo CPU) |
+
+#### Sintaxis de Lanzamiento de Kernel
+
+Zen C proporciona una sentencia `launch` limpia para invocar kernels de CUDA:
+
+```zc
+launch nombre_del_kernel(args) with {
+ grid: num_bloques,
+ block: hilos_por_bloque,
+ shared_mem: 1024, // Opcional
+ stream: mi_stream // Opcional
+};
+```
+
+Esto se transpila a: `nombre_del_kernel<<<grid, bloque, compartido, stream>>>(args);`
+
+#### Escribiendo Kernels de CUDA
+
+Usa la sintaxis de funciones de Zen C con `@global` y la sentencia `launch`:
+
+```zc
+import "std/cuda.zc"
+
+@global
+fn kernel_suma(a: float*, b: float*, c: float*, n: int) {
+ let i = thread_id();
+ if i < n {
+ c[i] = a[i] + b[i];
+ }
+}
+
+fn main() {
+ def N = 1024;
+ let d_a = cuda_alloc<float>(N);
+ let d_b = cuda_alloc<float>(N);
+ let d_c = cuda_alloc<float>(N);
+ defer cuda_free(d_a);
+ defer cuda_free(d_b);
+ defer cuda_free(d_c);
+
+ // ... inicialización de datos ...
+
+ launch kernel_suma(d_a, d_b, d_c, N) with {
+ grid: (N + 255) / 256,
+ block: 256
+ };
+
+ cuda_sync();
+}
+```
+
+#### Biblioteca Estándar (`std/cuda.zc`)
+Zen C proporciona una biblioteca estándar para operaciones comunes de CUDA para reducir los bloques `raw`:
+
+```zc
+import "std/cuda.zc"
+
+// Gestión de memoria
+let d_ptr = cuda_alloc<float>(1024);
+cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
+defer cuda_free(d_ptr);
+
+// Sincronización
+cuda_sync();
+
+// Indexación de hilos (usar dentro de kernels)
+let i = thread_id(); // Índice global
+let bid = block_id();
+let tid = local_id();
+```
+
+
+> **Nota:** La flag `--cuda` establece `nvcc` como el compilador e implica el modo `--cpp`. Requiere el NVIDIA CUDA Toolkit.
+
+### Soporte C23
+
+Zen C soporta características modernas de C23 cuando se utiliza un compilador backend compatible (GCC 14+, Clang 14+).
+
+- **`auto`**: Zen C mapea automáticamente la inferencia de tipos a `auto` estándar de C23 si `__STDC_VERSION__ >= 202300L`.
+- **`_BitInt(N)`**: Use tipos `iN` y `uN` (ej. `i256`, `u12`, `i24`) para acceder a enteros de ancho arbitrario de C23.
+
+### Interop con Objective-C
+
+Zen C puede compilarse a Objective-C (`.m`) usando la flag `--objc`, permitiéndote usar frameworks de Objective-C (como Cocoa/Foundation) y su sintaxis.
+
+```bash
+# Compilar con clang (o gcc/gnustep)
+zc app.zc --objc --cc clang
+```
+
+#### Usando Objective-C en Zen C
+
+Usa `include` para las cabeceras y bloques `raw` para la sintaxis de Objective-C (`@interface`, `[...]`, `@""`).
+
+```zc
+//> macos: framework: Foundation
+//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS
+//> linux: link: -lgnustep-base -lobjc
+
+include <Foundation/Foundation.h>
+
+fn main() {
+ raw {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSLog(@"¡Hola desde Objective-C!");
+ [pool drain];
+ }
+ println "¡Zen C también funciona!";
+}
+```
+
+> **Nota:** La interpolación de cadenas de Zen C funciona con objetos de Objective-C (`id`) llamando a `debugDescription` o `description`.
+
+---
+
+## Contribuyendo
+
+¡Damos la bienvenida a las contribuciones! Ya sea corrigiendo errores, añadiendo documentación o proponiendo nuevas características.
+
+### Cómo Contribuir
+1. **Haz un Fork del Repositorio**: flujo de trabajo estándar de GitHub.
+2. **Crea una Rama de Característica**: `git checkout -b feature/NuevaCosa`.
+3. **Guías de Código**:
+ * Sigue el estilo de C existente.
+ * Asegúrate de que todas las pruebas pasen: `make test`.
+ * Añade nuevas pruebas para tu característica en `tests/`.
+4. **Envía un Pull Request**: Describe tus cambios claramente.
+
+### Ejecutando Pruebas
+La suite de pruebas es tu mejor amiga.
+
+```bash
+# Ejecutar todas las pruebas (GCC)
+make test
+
+# Ejecutar una prueba específica
+./zc run tests/test_match.zc
+
+# Ejecutar con un compilador diferente
+./tests/run_tests.sh --cc clang
+./tests/run_tests.sh --cc zig
+./tests/run_tests.sh --cc tcc
+```
+
+### Extendiendo el Compilador
+* **Parser**: `src/parser/` - Parser de descenso recursivo.
+* **Codegen**: `src/codegen/` - Lógica del transpilador (Zen C -> GNU C/C11).
+* **Biblioteca Estándar**: `std/` - Escrita en el propio Zen C.
+
+---
+
+## Atribuciones
+
+Este proyecto utiliza bibliotecas de terceros. Los textos completos de las licencias pueden encontrarse en el directorio `LICENSES/`.
+
+* **[cJSON](https://github.com/DaveGamble/cJSON)** (Licencia MIT): Usado para el parseo y generación de JSON en el Servidor de Lenguaje.
+* **[zc-ape](https://github.com/OEvgeny/zc-ape)** (Licencia MIT): El port original de Ejecutable Realmente Portable de Zen-C por [Eugene Olonov](https://github.com/OEvgeny).
+* **[Cosmopolitan Libc](https://github.com/jart/cosmopolitan)** (Licencia ISC): La biblioteca fundamental que hace posible APE.
diff --git a/README_ZH_CN.md b/README_ZH_CN.md
new file mode 100644
index 0000000..51689f6
--- /dev/null
+++ b/README_ZH_CN.md
@@ -0,0 +1,1435 @@
+
+<div align="center">
+
+[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md)
+
+</div>
+
+<div align="center">
+
+# Zen C
+
+**现代开发体验。零开销。纯净 C。**
+
+[![构建状态](https://img.shields.io/badge/build-passing-brightgreen)]()
+[![许可证](https://img.shields.io/badge/license-MIT-blue)]()
+[![版本](https://img.shields.io/badge/version-0.1.0-orange)]()
+[![平台](https://img.shields.io/badge/platform-linux-lightgrey)]()
+
+*像高级语言一样编写,像 C 一样运行。*
+
+</div>
+
+---
+
+## 概述
+
+**Zen C** 是一种现代系统编程语言,可编译为人类可读的 `GNU C`/`C11`。它提供了一套丰富的特性,包括类型推断、模式匹配、泛型、Trait、async/await 以及具有 RAII 能力的手动内存管理,同时保持 100% 的 C ABI 兼容性。
+
+## 社区
+
+加入官方 Zen C Discord 服务器,参与讨论、展示 Demo、提问或报告 Bug!
+
+- Discord: [点击加入](https://discord.com/invite/q6wEsCmkJP)
+
+---
+
+## 目录
+
+- [概述](#概述)
+- [社区](#社区)
+- [快速入门](#快速入门)
+ - [安装](#安装)
+ - [用法](#用法)
+ - [环境变量](#环境变量)
+- [语言参考](#语言参考)
+ - [1. 变量与常量](#1-变量与常量)
+ - [2. 原始类型](#2-原始类型)
+ - [3. 复合类型](#3-复合类型)
+ - [数组](#数组)
+ - [元组](#元组)
+ - [结构体](#结构体)
+ - [不透明结构体](#不透明结构体)
+ - [枚举](#枚举)
+ - [联合体](#联合体)
+ - [类型别名](#类型别名)
+ - [不透明类型别名](#不透明类型别名)
+ - [4. 函数与 Lambda](#4-函数与-lambda)
+ - [函数](#函数)
+ - [常量参数](#常量参数)
+ - [默认参数](#默认参数)
+ - [Lambda (闭包)](#lambda-闭包)
+ - [原始函数指针](#原始函数指针)
+ - [变参函数](#变参函数)
+ - [5. 控制流](#5-控制流)
+ - [条件语句](#条件语句)
+ - [模式匹配](#模式匹配)
+ - [循环](#循环)
+ - [高级控制](#高级控制)
+ - [6. 运算符](#6-运算符)
+ - [可重载运算符](#可重载运算符)
+ - [语法糖](#语法糖)
+ - [7. 打印与字符串插值](#7-打印与字符串插值)
+ - [关键字](#关键字)
+ - [简写形式](#简写形式)
+ - [字符串插值 (F-strings)](#字符串插值-f-strings)
+ - [输入提示 (`?`)](#输入提示-)
+ - [8. 内存管理](#8-内存管理)
+ - [Defer](#defer)
+ - [Autofree](#autofree)
+ - [资源语义 (默认移动)](#资源语义-默认移动)
+ - [RAII / Drop Trait](#raii--drop-trait)
+ - [9. 面向对象编程](#9-面向对象编程)
+ - [方法](#方法)
+ - [Trait](#trait)
+ - [标准 Trait](#标准-trait)
+ - [组合](#组合)
+ - [10. 泛型](#10-泛型)
+ - [11. 并发 (Async/Await)](#11-并发-asyncawait)
+ - [12. 元编程](#12-元编程)
+ - [Comptime](#comptime)
+ - [Embed](#embed)
+ - [插件](#插件)
+ - [泛型 C 宏](#泛型-c-宏)
+ - [13. 属性](#13-属性)
+ - [自定义属性](#自定义属性)
+ - [智能派生](#智能派生)
+ - [14. 内联汇编](#14-内联汇编)
+ - [基本用法](#基本用法)
+ - [Volatile](#volatile)
+ - [命名约束](#命名约束)
+ - [15. 构建指令](#15-构建指令)
+ - [16. 关键字](#16-关键字)
+- [标准库](#标准库)
+- [工具链](#工具链)
+ - [语言服务器 (LSP)](#语言服务器-lsp)
+ - [REPL](#repl)
+- [编译器支持与兼容性](#编译器支持与兼容性)
+ - [测试套件状态](#测试套件状态)
+ - [使用 Zig 构建](#使用-zig-构建)
+ - [C++ 互操作](#c-互操作)
+ - [CUDA 互操作](#cuda-互操作)
+ - [Objective-C 互操作](#objective-c-互操作)
+- [贡献](#贡献)
+- [致谢与归属](#致谢与归属)
+
+---
+
+## 快速入门
+
+### 安装
+
+```bash
+git clone https://github.com/z-libs/Zen-C.git
+cd Zen-C
+make
+sudo make install
+```
+
+### 便携式构建 (APE)
+
+Zen C 可以通过 [Cosmopolitan Libc](https://github.com/jart/cosmopolitan) 编译为 **Actually Portable Executable (APE)**。这将生成一个单个的可执行文件 (`.com`),能够原生运行在 Linux, macOS, Windows, FreeBSD, OpenBSD, 和 NetBSD 上的 x86_64 和 aarch64 架构上。
+
+**前提条件:**
+- `cosmocc` 工具链(必须在 PATH 中)
+
+**构建与安装:**
+```bash
+make ape
+sudo env "PATH=$PATH" make install-ape
+```
+
+**产物:**
+- `out/bin/zc.com`: 便携式 Zen-C 编译器。已将标准库嵌入到可执行文件中。
+- `out/bin/zc-boot.com`: 一个自包含的引导安装程序,用于设置新的 Zen-C 项目。
+
+**用法:**
+```bash
+# 在任何支持的操作系统上运行
+./out/bin/zc.com build hello.zc -o hello
+```
+
+### 用法
+
+```bash
+# 编译并运行
+zc run hello.zc
+
+# 构建可执行文件
+zc build hello.zc -o hello
+
+# 交互式 Shell
+zc repl
+```
+
+### 环境变量
+
+你可以设置 `ZC_ROOT` 来指定标准库的位置(标准导入如 `import "std/vector.zc"`)。这允许你从任何目录运行 `zc`。
+
+```bash
+export ZC_ROOT=/path/to/Zen-C
+```
+
+---
+
+## 语言参考
+
+### 1. 变量与常量
+
+Zen C 区分编译时常量和运行时变量。
+
+#### 清单常量 (`def`)
+仅在编译时存在的值(折叠到代码中)。用于数组大小、固定配置和魔术数字。
+
+```zc
+def MAX_SIZE = 1024;
+let buffer: char[MAX_SIZE]; // 有效的数组大小
+```
+
+#### 变量 (`let`)
+内存中的存储位置。可以是可变的或只读的 (`const`)。
+
+```zc
+let x = 10; // 可变
+x = 20; // 允许
+
+let y: const int = 10; // 只读 (类型修饰)
+// y = 20; // 错误:无法赋值给 const 变量
+```
+
+> **类型推导**:Zen C 自动推导初始化变量的类型。在支持的编译器上编译为 C23 的 `auto`,否则使用 GCC 的 `__auto_type` 扩展。
+
+### 2. 原始类型
+
+| 类型 | C 等效类型 | 描述 |
+|:---|:---|:---|
+| `int`, `uint` | `int`, `unsigned int` | 平台标准整数 |
+| `I8` .. `I128` 或 `i8` .. `i128` | `int8_t` .. `__int128_t` | 有符号固定宽度整数 |
+| `U8` .. `U128` 或 `u8` .. `u128` | `uint8_t` .. `__uint128_t` | 无符号固定宽度整数 |
+| `isize`, `usize` | `ptrdiff_t`, `size_t` | 指针大小的整数 |
+| `byte` | `uint8_t` | U8 的别名 |
+| `F32`, `F64` 或 `f32`, `f64` | `float`, `double` | 浮点数 |
+| `bool` | `bool` | `true` 或 `false` |
+| `char` | `char` | 单个字符 |
+| `string` | `char*` | C-string (以 null 结尾) |
+| `U0`, `u0`, `void` | `void` | 空类型 |
+| `iN` (例 `i256`) | `_BitInt(N)` | 任意位宽有符号整数 (C23) |
+| `uN` (例 `u42`) | `unsigned _BitInt(N)` | 任意位宽无符号整数 (C23) |
+
+### 3. 复合类型
+
+#### 数组
+具有值语义的固定大小数组。
+```zc
+def SIZE = 5;
+let ints: int[SIZE] = [1, 2, 3, 4, 5];
+let zeros: [int; SIZE]; // 零初始化的
+```
+
+#### 元组
+将多个值组合在一起,通过索引访问元素。
+```zc
+let pair = (1, "Hello");
+let x = pair.0; // 1
+let s = pair.1; // "Hello"
+```
+
+**多个返回值**
+
+函数可以返回元组以提供多个结果:
+```zc
+fn add_and_subtract(a: int, b: int) -> (int, int) {
+ return (a + b, a - b);
+}
+
+let result = add_and_subtract(3, 2);
+let sum = result.0; // 5
+let diff = result.1; // 1
+```
+
+**解构**
+
+元组可以直接解构为多个变量:
+```zc
+let (sum, diff) = add_and_subtract(3, 2);
+// sum = 5, diff = 1
+```
+
+#### 结构体
+带有可选位域的数据结构。
+```zc
+struct Point {
+ x: int;
+ y: int;
+}
+
+// 结构体初始化
+let p = Point { x: 10, y: 20 };
+
+// 位域
+struct Flags {
+ valid: U8 : 1;
+ mode: U8 : 3;
+}
+```
+
+> **注意**:结构体默认使用 [移动语义](#资源语义-默认移动)。即使是指针,也可以通过 `.` 访问字段(自动解引用)。
+
+#### 不透明结构体
+你可以将结构体定义为 `opaque`,以将对其字段的访问限制在定义该结构体的模块内部,同时仍允许在栈上分配该结构体(大小已知)。
+
+```zc
+// 在 user.zc 中
+opaque struct User {
+ id: int;
+ name: string;
+}
+
+fn new_user(name: string) -> User {
+ return User{id: 1, name: name}; // 允许:在模块内部
+}
+
+// 在 main.zc 中
+import "user.zc";
+
+fn main() {
+ let u = new_user("Alice");
+ // let id = u.id; // 错误:无法访问私有字段 'id'
+}
+```
+
+#### 枚举
+能够持有数据的标签联合 (Sum types)。
+```zc
+enum Shape {
+ Circle(float), // 持有半径
+ Rect(float, float), // 持有宽、高
+ Point // 不带数据
+}
+```
+
+#### 联合体
+标准 C 联合体(不安全访问)。
+```zc
+union Data {
+ i: int;
+ f: float;
+}
+```
+
+#### 类型别名
+为现有类型创建新名称。
+```zc
+alias ID = int;
+alias PointMap = Map<string, Point>;
+```
+
+#### 不透明类型别名
+你可以将类型别名定义为 `opaque`,从而在定义模块之外创建一个与基础类型不同的新类型。这提供了强大的封装和类型安全性,而没有包装结构体的运行时开销。
+
+```zc
+// 在 library.zc 中
+opaque alias Handle = int;
+
+fn make_handle(v: int) -> Handle {
+ return v; // 允许在模块内部进行隐式转换
+}
+
+// 在 main.zc 中
+import "library.zc";
+
+fn main() {
+ let h: Handle = make_handle(42);
+ // let i: int = h; // 错误:类型验证失败
+ // let h2: Handle = 10; // 错误:类型验证失败
+}
+```
+
+### 4. 函数与 Lambda
+
+#### 函数
+```zc
+fn add(a: int, b: int) -> int {
+ return a + b;
+}
+
+// 调用时支持命名参数
+add(a: 10, b: 20);
+```
+
+> **注意**:命名参数必须严格遵循定义的参数顺序。`add(b: 20, a: 10)` 是无效的。
+
+#### 常量参数
+函数参数可以标记为 `const` 以强制执行只读语义。这是一个类型修饰符,而不是清单常量。
+
+```zc
+fn print_val(v: const int) {
+ // v = 10; // 错误:无法赋值给 const 变量
+ println "{v}";
+}
+```
+
+#### 默认参数
+函数可以为尾部参数定义默认值。这些值可以是字面量、表达式或有效的 Zen C 代码(如结构体构造函数)。
+```zc
+// 简单默认值
+fn increment(val: int, amount: int = 1) -> int {
+ return val + amount;
+}
+
+// 表达式默认值(在调用处计算)
+fn offset(val: int, pad: int = 10 * 2) -> int {
+ return val + pad;
+}
+
+// 结构体默认值
+struct Config { debug: bool; }
+fn init(cfg: Config = Config { debug: true }) {
+ if cfg.debug { println "调试模式"; }
+}
+
+fn main() {
+ increment(10); // 11
+ offset(5); // 25
+ init(); // 打印 "调试模式"
+}
+```
+
+#### Lambda (闭包)
+可以捕获环境的匿名函数。
+```zc
+let factor = 2;
+let double = x -> x * factor; // 箭头语法
+let full = fn(x: int) -> int { return x * factor; }; // 块语法
+```
+
+#### 原始函数指针
+Zen C 使用 `fn*` 语法支持原始 C 函数指针。这允许与期望函数指针且没有闭包开销的 C 库进行无缝互操作。
+
+```zc
+// 接受原始函数指针的函数
+fn set_callback(cb: fn*(int)) {
+ cb(42);
+}
+
+// 返回原始函数指针的函数
+fn get_callback() -> fn*(int) {
+ return my_handler;
+}
+
+// 支持指向函数指针的指针 (fn**)
+let pptr: fn**(int) = &ptr;
+```
+
+#### 变参函数
+函数可以使用 `...` 和 `va_list` 类型接受可变数量的参数。
+```zc
+fn log(lvl: int, fmt: char*, ...) {
+ let ap: va_list;
+ va_start(ap, fmt);
+ vprintf(fmt, ap); // 使用 C stdio
+ va_end(ap);
+}
+```
+
+### 5. 控制流
+
+#### 条件语句
+```zc
+if x > 10 {
+ print("Large");
+} else if x > 5 {
+ print("Medium");
+} else {
+ print("Small");
+}
+
+// 三元运算符
+let y = x > 10 ? 1 : 0;
+```
+
+#### 模式匹配
+`switch` 的强大替代方案。
+```zc
+match val {
+ 1 => { print "One" },
+ 2 || 3 => { print "Two or Three" }, // 使用 || 进行 或 操作
+ 4 or 5 => { print "Four or Five" }, // 使用 'or' 进行 或 操作
+ 6, 7, 8 => { print "Six to Eight" }, // 使用逗号进行 或 操作
+ 10 .. 15 => { print "10 to 14" }, // 左闭右开区间 (旧语法)
+ 10 ..< 15 => { print "10 to 14" }, // 左闭右开区间 (显式)
+ 20 ..= 25 => { print "20 to 25" }, // 全闭区间
+ _ => { print "Other" },
+}
+
+// 解构枚举
+match shape {
+ Shape::Circle(r) => println "半径: {r}",
+ Shape::Rect(w, h) => println "面积: {w*h}",
+ Shape::Point => println "点"
+}
+```
+
+#### 引用绑定
+为了在不获取所有权(移动)的情况下检查一个值,在模式中使用 `ref` 关键字。这对于实现了移动语义的类型(如 `Option`, `Result`, 非 Copy 结构体)至关重要。
+
+```zc
+let opt = Some(NonCopyVal{...});
+match opt {
+ Some(ref x) => {
+ // 'x' 是指向 'opt' 内部值的指针
+ // 'opt' 在此处不会被移动/消耗
+ println "{x.field}";
+ },
+ None => {}
+}
+```
+
+#### 循環
+```zc
+// 區間迭代
+for i in 0..10 { ... } // 左閉右開 (0 到 9)
+for i in 0..<10 { ... } // 左閉右開 (顯式)
+for i in 0..=10 { ... } // 全閉 (0 到 10)
+for i in 0..10 step 2 { ... }
+
+// 迭代器 (Vec 或自定義 Iterable)
+for item in vec { ... }
+
+// 直接迭代固定大小数组
+let arr: int[5] = [1, 2, 3, 4, 5];
+for val in arr {
+ // val 是 int
+ println "{val}";
+}
+
+// While 循環
+while x < 10 { ... }
+
+// 帶標籤的無限循環
+outer: loop {
+ if done { break outer; }
+}
+
+// 重複 N 次
+for _ in 0..5 { ... }
+```
+
+#### 高级控制
+```zc
+// Guard: 如果条件为假,则执行 else 块并返回
+guard ptr != NULL else { return; }
+
+// Unless: 除非为真(即如果为假)
+unless is_valid { return; }
+```
+
+### 6. 运算符
+
+Zen C 通过实现特定的方法名来支持用户定义结构体的运算符重载。
+
+#### 可重载运算符
+
+| 类别 | 运算符 | 方法名 |
+|:---|:---|:---|
+| **算术** | `+`, `-`, `*`, `/`, `%` | `add`, `sub`, `mul`, `div`, `rem` |
+| **比较** | `==`, `!=` | `eq`, `neq` |
+| | `<`, `>`, `<=`, `>=` | `lt`, `gt`, `le`, `ge` |
+| **位运算** | `&`, `|`, `^` | `bitand`, `bitor`, `bitxor` |
+| | `<<`, `>>` | `shl`, `shr` |
+| **一元** | `-` | `neg` |
+| | `!` | `not` |
+| | `~` | `bitnot` |
+| **索引** | `a[i]` | `get(a, i)` |
+| | `a[i] = v` | `set(a, i, v)` |
+
+> **关于字符串相等性的说明**:
+> - `string == string` 进行 **值比较**(等同于 `strcmp`)。
+> - `char* == char*` 进行 **指针比较**(检查内存地址)。
+> - 混合比较(例如 `string == char*`)默认为 **指针比较**。
+
+**示例:**
+```zc
+impl Point {
+ fn add(self, other: Point) -> Point {
+ return Point{x: self.x + other.x, y: self.y + other.y};
+ }
+}
+
+let p3 = p1 + p2; // 调用 p1.add(p2)
+```
+
+#### 语法糖
+
+这些运算符是内置语言特性,不能直接重载。
+
+| 运算符 | 名称 | 描述 |
+|:---|:---|:---|
+| `|>` | 管道 | `x |> f(y)` 脱糖为 `f(x, y)` |
+| `??` | 空合并 | 如果 `val` 为 NULL,`val ?? default` 返回 `default` (用于指针) |
+| `??=` | 空赋值 | 如果 `val` 为 NULL 则赋值 |
+| `?.` | 安全导航 | 仅当 `ptr` 不为 NULL 时访问字段 |
+| `?` | Try 运算符 | 如果存在错误则返回 (用于 Result/Option 类型) |
+
+**自动解引用**:
+指针字段访问 (`ptr.field`) 和方法调用 (`ptr.method()`) 会自动解引用指针,等同于 `(*ptr).field`。
+
+### 7. 打印与字符串插值
+
+Zen C 提供了多种控制台打印选项,包括关键字和简洁的简写形式。
+
+#### 关键字
+
+- `print "text"`: 打印到 `stdout`,不带尾随换行符。
+- `println "text"`: 打印到 `stdout`,带尾随换行符。
+- `eprint "text"`: 打印到 `stderr`,不带尾随换行符。
+- `eprintln "text"`: 打印到 `stderr`,带尾随换行符。
+
+#### 简写形式
+
+Zen C 允许直接将字符串字面量用作语句来进行快速打印:
+
+- `"Hello World"`: 等同于 `println "Hello World"`。(隐式添加换行符)
+- `"Hello World"..`: 等同于 `print "Hello World"`。(不带尾随换行符)
+- `!"Error"`: 等同于 `eprintln "Error"`。(输出到 stderr)
+- `!"Error"..`: 等同于 `eprint "Error"`。(输出到 stderr,不带换行符)
+
+#### 字符串插值 (F-strings)
+
+你可以使用 `{}` 语法将表达式直接嵌入到字符串字面量中。这适用于所有打印方法和字符串简写。
+
+```zc
+let x = 42;
+let name = "Zen";
+println "值: {x}, 名称: {name}";
+"值: {x}, 名称: {name}"; // 简写形式的 println
+```
+
+#### 输入提示 (`?`)
+
+Zen C 支持使用 `?` 前缀进行用户输入提示的简写。
+
+- `? "提示文本"`: 打印提示信息(不换行)并等待输入(读取一行)。
+- `? "输入年龄: " (age)`: 打印提示并扫描输入到变量 `age` 中。
+ - 格式说明符会根据变量类型自动推断。
+
+```zc
+let age: int;
+? "你多大了? " (age);
+println "你 {age} 岁了。";
+```
+
+### 8. 内存管理
+
+Zen C 允许带有符合人体工程学辅助的手动内存管理。
+
+#### Defer
+在当前作用域退出时执行代码。Defer 语句按照后进先出 (LIFO) 的顺序执行。
+```zc
+let f = fopen("file.txt", "r");
+defer fclose(f);
+```
+
+> 为了防止未定义行为,`defer` 块内不允许使用控制流语句(`return`, `break`, `continue`, `goto`)。
+
+#### Autofree
+在作用域退出时自动释放变量。
+```zc
+autofree let types = malloc(1024);
+```
+
+#### 资源语义 (默认移动)
+Zen C 将带有析构函数(如 `File`, `Vec`, 或 malloc 的指针)的类型视为 **资源**。为了防止双重释放错误,资源不能被隐式复制。
+
+- **默认移动**:分配资源变量会转移所有权。原始变量变得无效(已移动)。
+- **复制类型**:没有析构函数的类型可以申请参与 `Copy` 行为,使赋值变成复制。
+
+**诊断与哲学**:
+如果你看到错误 "Use of moved value",编译器是在告诉你:*"此类型拥有一个资源(如内存或句柄),盲目复制它是不安全的。"*
+
+> **对比:** 与 C/C++ 不同,Zen C 不会隐式复制拥有资源的值。
+
+**函数参数**:
+将值传递给函数遵循与赋值相同的规则:资源会被移动,除非通过引用传递。
+
+```zc
+fn process(r: Resource) { ... } // 'r' 被移动进函数
+fn peek(r: Resource*) { ... } // 'r' 被借用 (引用)
+```
+
+**显式克隆**:
+如果你 *确实* 想要一个资源的两个副本,请显式执行:
+
+```zc
+let b = a.clone(); // 调用 Clone trait 中的 'clone' 方法
+```
+
+**选择性复制 (值类型)**:
+对于没有析构函数的小型类型:
+
+```zc
+struct Point { x: int; y: int; }
+impl Copy for Point {} // 选择参与隐式复制
+
+fn main() {
+ let p1 = Point { x: 1, y: 2 };
+ let p2 = p1; // 已复制。p1 保持有效。
+}
+```
+
+#### RAII / Drop Trait
+实现 `Drop` 以自动运行清理逻辑。
+```zc
+impl Drop for MyStruct {
+ fn drop(self) {
+ self.free();
+ }
+}
+```
+
+### 9. 面向对象编程
+
+#### 方法
+使用 `impl` 为类型定义方法。
+```zc
+impl Point {
+ // 静态方法 (构造函数惯例)
+ fn new(x: int, y: int) -> Self {
+ return Point{x: x, y: y};
+ }
+
+ // 实例方法
+ fn dist(self) -> float {
+ return sqrt(self.x * self.x + self.y * self.y);
+ }
+}
+```
+
+#### Trait
+定义共享行为。
+```zc
+struct Circle { radius: f32; }
+
+trait Drawable {
+ fn draw(self);
+}
+
+impl Drawable for Circle {
+ fn draw(self) { ... }
+}
+
+let circle = Circle{};
+let drawable: Drawable = &circle;
+```
+
+#### 标准 Trait
+Zen C 包含与语言语法集成的标准 Trait。
+
+**Iterable**
+
+实现 `Iterable<T>` 以便为你的自定义类型启用 `for-in` 循环。
+
+```zc
+import "std/iter.zc"
+
+// 定义一个迭代器
+struct MyIter {
+ curr: int;
+ stop: int;
+}
+
+impl MyIter {
+ fn next(self) -> Option<int> {
+ if self.curr < self.stop {
+ self.curr += 1;
+ return Option<int>::Some(self.curr - 1);
+ }
+ return Option<int>::None();
+ }
+}
+
+// 实现 Iterable
+impl MyRange {
+ fn iterator(self) -> MyIter {
+ return MyIter{curr: self.start, stop: self.end};
+ }
+}
+
+// 在循环中使用
+for i in my_range {
+ println "{i}";
+}
+```
+
+**Drop**
+
+实现 `Drop` 来定义一个在对象超出范围时运行的析构函数 (RAII)。
+
+```zc
+import "std/mem.zc"
+
+struct Resource {
+ ptr: void*;
+}
+
+impl Drop for Resource {
+ fn drop(self) {
+ if self.ptr != NULL {
+ free(self.ptr);
+ }
+ }
+}
+```
+
+> **注意:** 如果一个变量被移动,则原始变量不会调用 `drop`。它遵循 [资源语义](#资源语义-默认移动)。
+
+**Copy**
+
+标记 Trait,用于选择支持 `Copy` 行为(隐式复制)而不是移动语义。通过 `@derive(Copy)` 使用。
+
+> **规则:** 实现了 `Copy` 的类型不得定义析构函数 (`Drop`)。
+
+```zc
+@derive(Copy)
+struct Point { x: int; y: int; }
+
+fn main() {
+ let p1 = Point{x: 1, y: 2};
+ let p2 = p1; // 已复制!p1 保持有效。
+}
+```
+
+**Clone**
+
+实现 `Clone` 以允许显式复制拥有资源的类型。
+
+```zc
+import "std/mem.zc"
+
+struct MyBox { val: int; }
+
+impl Clone for MyBox {
+ fn clone(self) -> MyBox {
+ return MyBox{val: self.val};
+ }
+}
+
+fn main() {
+ let b1 = MyBox{val: 42};
+ let b2 = b1.clone(); // 显式复制
+}
+```
+
+#### 组合
+使用 `use` 嵌入其他结构体。你可以将它们混合进来(展平字段)或者为它们命名(嵌套字段)。
+
+```zc
+struct Entity { id: int; }
+
+struct Player {
+ // 混入 (未命名): 展平字段
+ use Entity; // 直接将 'id' 添加到 Player
+ name: string;
+}
+
+struct Match {
+ // 组合 (命名): 嵌套字段
+ use p1: Player; // 通过 match.p1 访问
+ use p2: Player; // 通过 match.p2 访问
+}
+```
+
+### 10. 泛型
+
+结构体和函数的类型安全模板。
+
+```zc
+// 泛型结构体
+struct Box<T> {
+ item: T;
+}
+
+// 泛型函数
+fn identity<T>(val: T) -> T {
+ return val;
+}
+
+// 多参数泛型
+struct Pair<K, V> {
+ key: K;
+ value: V;
+}
+```
+
+### 11. 并发 (Async/Await)
+
+基于 pthreads 构建。
+
+```zc
+async fn fetch_data() -> string {
+ // 在后台运行
+ return "Data";
+}
+
+fn main() {
+ let future = fetch_data();
+ let result = await future;
+}
+```
+
+### 12. 元编程
+
+#### Comptime
+在编译时运行代码以生成源码或打印消息。
+```zc
+comptime {
+ // 在编译时生成代码 (写入 stdout)
+ println "let build_date = \"2024-01-01\";";
+}
+
+println "构建日期: {build_date}";
+```
+
+#### Embed
+将文件嵌入为指定类型。
+```zc
+// 默认 (Slice_char)
+let data = embed "assets/logo.png";
+
+// 类型化嵌入
+let text = embed "shader.glsl" as string; // 嵌入为 C-string
+let rom = embed "bios.bin" as u8[1024]; // 嵌入为固定数组
+let wav = embed "sound.wav" as u8[]; // 嵌入为 Slice_u8
+```
+
+#### 插件
+导入编译器插件以扩展语法。
+```zc
+import plugin "regex"
+let re = regex! { ^[a-z]+$ };
+```
+
+#### 泛型 C 宏
+将预处理器宏传递给 C。
+
+> **提示**:对于简单的常量,请使用 `def`。当你需要 C 预处理器宏或条件编译标志时,请使用 `#define`。
+
+```zc
+#define MAX_BUFFER 1024
+```
+
+### 13. 属性
+
+修饰函数和结构体以修改编译器行为。
+
+| 属性 | 作用域 | 描述 |
+|:---|:---|:---|
+| `@must_use` | 函数 | 如果忽略返回值则发出警告。 |
+| `@deprecated("msg")` | 函数/结构体 | 使用时发出带有消息的警告。 |
+| `@inline` | 函数 | 提示编译器进行内联。 |
+| `@noinline` | 函数 | 防止内联。 |
+| `@packed` | 结构体 | 移除字段间的填充。 |
+| `@align(N)` | 结构体 | 强制按 N 字节对齐。 |
+| `@constructor` | 函数 | 在 main 之前运行。 |
+| `@destructor` | 函数 | 在 main 退出后运行。 |
+| `@unused` | 函数/变量 | 抑制未使用变量警告。 |
+| `@weak` | 函数 | 弱符号链接。 |
+| `@section("name")` | 函数 | 将代码放置在特定段中。 |
+| `@noreturn` | 函数 | 函数不会返回 (例如 exit)。 |
+| `@pure` | 函数 | 函数无副作用 (优化提示)。 |
+| `@cold` | 函数 | 函数不太可能被执行 (分支预测提示)。 |
+| `@hot` | 函数 | 函数频繁执行 (优化提示)。 |
+| `@export` | 函数/结构体 | 导出符号 (默认可见性)。 |
+| `@global` | 函数 | CUDA: 内核入口点 (`__global__`)。 |
+| `@device` | 函数 | CUDA: 设备函数 (`__device__`)。 |
+| `@host` | 函数 | CUDA: 主机函数 (`__host__`)。 |
+| `@comptime` | 函数 | 用于编译时执行的辅助函数。 |
+| `@derive(...)` | 结构体 | 自动实现 Trait。支持 `Debug`, `Eq` (智能派生), `Copy`, `Clone`。 |
+| `@ctype("type")` | 函数参数 | 覆盖参数生成的 C 类型。 |
+| `@<custom>` | 任意 | 将泛型属性传递给 C (例如 `@flatten`, `@alias("name")`)。 |
+
+#### 自定义属性
+
+Zen C 支持强大的 **自定义属性** 系统,允许你在代码中直接使用任何 GCC/Clang 的 `__attribute__`。任何不被 Zen C 编译器显式识别的属性都会被视为泛型属性并传递给生成的 C 代码。
+
+这提供了对高级编译器特性、优化和链接器指令的访问,而无需在语言核心中提供显式支持。
+
+#### 语法映射
+Zen C 属性直接映射到 C 属性:
+- `@name` → `__attribute__((name))`
+- `@name(args)` → `__attribute__((name(args)))`
+- `@name("string")` → `__attribute__((name("string")))`
+
+#### 智能派生
+
+Zen C 提供了尊重移动语义的 "智能派生":
+
+- **`@derive(Eq)`**:生成一个通过引用获取参数的相等性方法 (`fn eq(self, other: T*)`)。
+ - 当比较两个非 Copy 结构体 (`a == b`) 时,编译器会自动通过引用传递 `b` (`&b`) 以避免移动它。
+ - 字段上的递归相等性检查也会优先使用指针访问,以防止所有权转移。
+
+### 14. 内联汇编
+
+Zen C 为内联汇编提供了一流支持,直接转译为 GCC 风格的扩展 `asm`。
+
+#### 基本用法
+在 `asm` 块内编写原始汇编。字符串会自动拼接。
+```zc
+asm {
+ "nop"
+ "mfence"
+}
+```
+
+#### Volatile
+防止编译器优化掉具有副作用的汇编代码。
+```zc
+asm volatile {
+ "rdtsc"
+}
+```
+
+#### 命名约束
+Zen C 通过命名绑定简化了复杂的 GCC 约束语法。
+
+```zc
+// 语法: : out(变量) : in(变量) : clobber(寄存器)
+// 使用 {变量} 占位符语法以提高可读性
+
+fn add(a: int, b: int) -> int {
+ let result: int;
+ asm {
+ "add {result}, {a}, {b}"
+ : out(result)
+ : in(a), in(b)
+ : clobber("cc")
+ }
+ return result;
+}
+```
+
+| 类型 | 语法 | GCC 等效项 |
+|:---|:---|:---|
+| **输出** | `: out(variable)` | `"=r"(variable)` |
+| **输入** | `: in(variable)` | `"r"(variable)` |
+| **破坏** | `: clobber("rax")` | `"rax"` |
+| **内存** | `: clobber("memory")` | `"memory"` |
+
+> **注意:** 使用 Intel 语法时(通过 `-masm=intel`),必须确保你的构建配置正确(例如,`//> cflags: -masm=intel`)。TCC 不支持 Intel 语法的汇编。
+
+### 15. 构建指令
+
+Zen C 支持在源文件顶部使用特殊注释来配置构建过程,无需复杂的构建系统或 Makefile。
+
+| 指令 | 参数 | 描述 |
+|:---|:---|:---|
+| `//> link:` | `-lfoo` 或 `path/to/lib.a` | 链接库或对象文件。 |
+| `//> lib:` | `path/to/libs` | 添加库搜索路径 (`-L`)。 |
+| `//> include:` | `path/to/headers` | 添加包含头文件搜索路径 (`-I`)。 |
+| `//> framework:` | `Cocoa` | 链接 macOS Framework。 |
+| `//> cflags:` | `-Wall -O3` | 向 C 编译器传递任意标志。 |
+| `//> define:` | `MACRO` 或 `KEY=VAL` | 定义预处理器宏 (`-D`)。 |
+| `//> pkg-config:` | `gtk+-3.0` | 运行 `pkg-config` 并追加 `--cflags` 和 `--libs`。 |
+| `//> shell:` | `command` | 在构建期间执行 shell 命令。 |
+| `//> get:` | `http://url/file` | 如果特定文件不存在,则下载该文件。 |
+
+#### 特性
+
+**1. 操作系统守护 (OS Guarding)**
+在指令前加上操作系统名称,以使其仅在特定平台上应用。
+受支持的前缀:`linux:`, `windows:`, `macos:` (或 `darwin:`)。
+
+```zc
+//> linux: link: -lm
+//> windows: link: -lws2_32
+//> macos: framework: Cocoa
+```
+
+**2. 环境变量展开**
+使用 `${VAR}` 语法在指令中展开环境变量。
+
+```zc
+//> include: ${HOME}/mylib/include
+//> lib: ${ZC_ROOT}/std
+```
+
+#### 示例
+
+```zc
+//> include: ./include
+//> lib: ./libs
+//> link: -lraylib -lm
+//> cflags: -Ofast
+//> pkg-config: gtk+-3.0
+
+import "raylib.h"
+
+fn main() { ... }
+```
+
+### 16. 关键字
+
+以下关键字在 Zen C 中是保留的。
+
+#### 声明
+`alias`, `def`, `enum`, `fn`, `impl`, `import`, `let`, `module`, `opaque`, `struct`, `trait`, `union`, `use`
+
+#### 控制流
+`async`, `await`, `break`, `catch`, `continue`, `defer`, `else`, `for`, `goto`, `guard`, `if`, `loop`, `match`, `return`, `try`, `unless`, `while`
+
+#### 特殊
+`asm`, `assert`, `autofree`, `comptime`, `const`, `embed`, `launch`, `ref`, `sizeof`, `static`, `test`, `volatile`
+
+#### 常量
+`true`, `false`, `null`
+
+#### C 保留字
+以下标识符是保留的,因为它们是 C11 中的关键字:
+`auto`, `case`, `char`, `default`, `do`, `double`, `extern`, `float`, `inline`, `int`, `long`, `register`, `restrict`, `short`, `signed`, `switch`, `typedef`, `unsigned`, `void`, `_Atomic`, `_Bool`, `_Complex`, `_Generic`, `_Imaginary`, `_Noreturn`, `_Static_assert`, `_Thread_local`
+
+#### 运算符
+`and`, `or`
+
+---
+
+## 标准库
+
+Zen C 包含一个涵盖基本功能的标准库 (`std`)。
+
+[浏览标准库文档](docs/std/README.md)
+
+### 核心模块
+
+| 模块 | 描述 | 文档 |
+| :--- | :--- | :--- |
+| **`std/vec.zc`** | 可增长动态数组 `Vec<T>`。 | [文档](docs/std/vec.md) |
+| **`std/string.zc`** | 堆分配的 `String` 类型,支持 UTF-8。 | [文档](docs/std/string.md) |
+| **`std/queue.zc`** | 先进先出队列 (环形缓冲区)。 | [文档](docs/std/queue.md) |
+| **`std/map.zc`** | 泛型哈希表 `Map<V>`。 | [文档](docs/std/map.md) |
+| **`std/fs.zc`** | 文件系统操作。 | [文档](docs/std/fs.md) |
+| **`std/io.zc`** | 标准输入/输出 (`print`/`println`)。 | [文档](docs/std/io.md) |
+| **`std/option.zc`** | 可选值 (`Some`/`None`)。 | [文档](docs/std/option.md) |
+| **`std/result.zc`** | 错误处理 (`Ok`/`Err`)。 | [文档](docs/std/result.md) |
+| **`std/path.zc`** | 跨平台路径操作。 | [文档](docs/std/path.md) |
+| **`std/env.zc`** | 进程环境变量。 | [文档](docs/std/env.md) |
+| **`std/net.zc`** | TCP 网络 (套接字)。 | [文档](docs/std/net.md) |
+| **`std/thread.zc`** | 线程与同步。 | [文档](docs/std/thread.md) |
+| **`std/time.zc`** | 时间测量与睡眠。 | [文档](docs/std/time.md) |
+| **`std/json.zc`** | JSON 解析与序列化。 | [文档](docs/std/json.md) |
+| **`std/stack.zc`** | 后进先出栈 `Stack<T>`。 | [文档](docs/std/stack.md) |
+| **`std/set.zc`** | 泛型哈希集合 `Set<T>`。 | [文档](docs/std/set.md) |
+| **`std/process.zc`** | 进程执行与管理。 | [文档](docs/std/process.md) |
+
+---
+
+## 工具链
+
+Zen C 提供内置的语言服务器 (LSP) 和 REPL 以增强开发体验。
+
+### 语言服务器 (LSP)
+
+Zen C 语言服务器 (LSP) 支持标准的 LSP 特性,用于编辑器集成:
+
+* **转到定义**
+* **查找引用**
+* **悬停信息**
+* **补全** (函数/结构体名,方法/字段的点补全)
+* **文档符号** (大纲)
+* **签名帮助**
+* **诊断** (语法/语义错误)
+
+启动语言服务器(通常在编辑器的 LSP 设置中配置):
+
+```bash
+zc lsp
+```
+
+它通过标准 I/O (JSON-RPC 2.0) 进行通信。
+
+### REPL
+
+Read-Eval-Print Loop 允许你交互式地尝试 Zen C 代码。
+
+```bash
+zc repl
+```
+
+#### 特性
+
+* **交互式编码**:输入表达式或语句以立即求值。
+* **持久历史**:命令保存在 `~/.zprep_history` 中。
+* **启动脚本**:自动加载 `~/.zprep_init.zc` 中的命令。
+
+#### 命令
+
+| 命令 | 描述 |
+|:---|:---|
+| `:help` | 显示可用命令。 |
+| `:reset` | 清除当前会话历史 (变量/函数)。 |
+| `:vars` | 显示活跃变量。 |
+| `:funcs` | 显示用户定义的函数。 |
+| `:structs` | 显示用户定义的结构体。 |
+| `:imports` | 显示活跃导入。 |
+| `:history` | 显示会话输入历史。 |
+| `:type <expr>` | 显示表达式的类型。 |
+| `:c <stmt>` | 显示语句生成的 C 代码。 |
+| `:time <expr>` | 基准测试表达式 (运行 1000 次迭代)。 |
+| `:edit [n]` | 在 `$EDITOR` 中编辑命令 `n` (默认:最后一条)。 |
+| `:save <file>` | 将当前会话保存到 `.zc` 文件。 |
+| `:load <file>` | 将 `.zc` 文件加载并执行到会话中。 |
+| `:watch <expr>` | 监视表达式 (每次输入后重新求值)。 |
+| `:unwatch <n>` | 移除监视。 |
+| `:undo` | 从会话中移除最后一条命令。 |
+| `:delete <n>` | 移除索引为 `n` 的命令。 |
+| `:clear` | 清屏。 |
+| `:quit` | 退出 REPL。 |
+| `! <cmd>` | 运行 shell 命令 (如 `!ls`)。 |
+
+---
+
+
+## 编译器支持与兼容性
+
+Zen C 旨在与大多数 C11 编译器配合使用。某些特性依赖于 GNU C 扩展,但这些扩展通常在其他编译器中也能工作。使用 `--cc` 标志切换后端。
+
+```bash
+zc run app.zc --cc clang
+zc run app.zc --cc zig
+```
+
+### 测试套件状态
+
+| 编译器 | 通过率 | 受支持特性 | 已知局限性 |
+|:---|:---:|:---|:---|
+| **GCC** | **100%** | 所有特性 | 无。 |
+| **Clang** | **100%** | 所有特性 | 无。 |
+| **Zig** | **100%** | 所有特性 | 无。使用 `zig cc` 作为替代 C 编译器。 |
+| **TCC** | **~70%** | 基本语法, 泛型, Trait | 不支持 `__auto_type`, 不支持 Intel ASM, 不支持嵌套函数。 |
+
+> **建议:** 生产环境构建请使用 **GCC**, **Clang**, 或 **Zig**。TCC 非常适合快速原型开发,因为它编译速度极快,但缺少 Zen C 全面支持所需的一些高级 C 扩展。
+
+### 使用 Zig 构建
+
+Zig 的 `zig cc` 命令提供了 GCC/Clang 的替代方案,具有出色的跨平台编译支持。使用 Zig:
+
+```bash
+# 使用 Zig 编译并运行 Zen C 程序
+zc run app.zc --cc zig
+
+# 使用 Zig 构建 Zen C 编译器本身
+make zig
+```
+
+### C++ 互操作
+
+Zen C 可以通过 `--cpp` 标志生成 C++ 兼容的代码,从而实现与 C++ 库的无缝集成。
+
+```bash
+# 直接使用 g++ 编译
+zc app.zc --cpp
+
+# 或者转译用于手动构建
+zc transpile app.zc --cpp
+g++ out.c my_cpp_lib.o -o app
+```
+
+#### 在 Zen C 中使用 C++
+
+包含 C++ 头文件并在 `raw` 块中使用 C++ 代码:
+
+```zc
+include <vector>
+include <iostream>
+
+raw {
+ std::vector<int> make_vec(int a, int b) {
+ return {a, b};
+ }
+}
+
+fn main() {
+ let v = make_vec(1, 2);
+ raw { std::cout << "Size: " << v.size() << std::endl; }
+}
+```
+
+> **注意:** `--cpp` 标志会将后端切换为 `g++` 并发出 C++ 兼容的代码(使用 `auto` 代替 `__auto_type`,使用函数重载代替 `_Generic`,以及对 `void*` 进行显式转换)。
+
+#### CUDA 互操作
+
+Zen C 通过转译为 **CUDA C++** 来支持 GPU 编程。这使你在维持 Zen C 人体工程学语法的同时,能够利用内核中的强大 C++ 特性(模板、constexpr)。
+
+```bash
+# 直接使用 nvcc 编译
+zc run app.zc --cuda
+
+# 或者转译用于手动构建
+zc transpile app.zc --cuda -o app.cu
+nvcc app.cu -o app
+```
+
+#### CUDA 特定属性
+
+| 属性 | CUDA 等效项 | 描述 |
+|:---|:---|:---|
+| `@global` | `__global__` | 内核函数 (运行在 GPU,从主机调用) |
+| `@device` | `__device__` | 设备函数 (运行在 GPU,从 GPU 调用) |
+| `@host` | `__host__` | 主机函数 (明确仅 CPU 运行) |
+
+#### 内核启动语法
+
+Zen C 提供了一个简洁的 `launch` 语句用于调用 CUDA 内核:
+
+```zc
+launch kernel_name(args) with {
+ grid: num_blocks,
+ block: threads_per_block,
+ shared_mem: 1024, // 可选
+ stream: my_stream // 可选
+};
+```
+
+这转译为:`kernel_name<<<grid, block, shared, stream>>>(args);`
+
+#### 编写 CUDA 内核
+
+使用带有 `@global` 的 Zen C 函数语法和 `launch` 语句:
+
+```zc
+import "std/cuda.zc"
+
+@global
+fn add_kernel(a: float*, b: float*, c: float*, n: int) {
+ let i = thread_id();
+ if i < n {
+ c[i] = a[i] + b[i];
+ }
+}
+
+fn main() {
+ def N = 1024;
+ let d_a = cuda_alloc<float>(N);
+ let d_b = cuda_alloc<float>(N);
+ let d_c = cuda_alloc<float>(N);
+ defer cuda_free(d_a);
+ defer cuda_free(d_b);
+ defer cuda_free(d_c);
+
+ // ... 初始化数据 ...
+
+ launch add_kernel(d_a, d_b, d_c, N) with {
+ grid: (N + 255) / 256,
+ block: 256
+ };
+
+ cuda_sync();
+}
+```
+
+#### 标准库 (`std/cuda.zc`)
+Zen C 为常见的 CUDA 操作提供了一个标准库,以减少 `raw` 块的使用:
+
+```zc
+import "std/cuda.zc"
+
+// 内存管理
+let d_ptr = cuda_alloc<float>(1024);
+cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
+defer cuda_free(d_ptr);
+
+// 同步
+cuda_sync();
+
+// 线程索引 (在内核内部使用)
+let i = thread_id(); // 全局索引
+let bid = block_id();
+let tid = local_id();
+```
+
+
+> **注意:** `--cuda` 标志设置 `nvcc` 为编译器并隐含 `--cpp` 模式。需要安装 NVIDIA CUDA Toolkit。
+
+### C23 支持
+
+当使用兼容的后端编译器(GCC 14+, Clang 14+)时,Zen C 支持现代 C23特性。
+
+- **`auto`**: 如果 `__STDC_VERSION__ >= 202300L`,Zen C 会自动将类型推导映射到标准 C23 `auto`。
+- **`_BitInt(N)`**: 使用 `iN` 和 `uN` 类型(例如 `i256`, `u12`, `i24`)访问 C23 任意位宽整数。
+
+### Objective-C 互操作
+
+Zen C 可以通过 `--objc` 标志编译为 Objective-C (`.m`),允许你使用 Objective-C 框架(如 Cocoa/Foundation)和语法。
+
+```bash
+# 使用 clang (或 gcc/gnustep) 编译
+zc app.zc --objc --cc clang
+```
+
+#### 在 Zen C 中使用 Objective-C
+
+使用 `include` 包含头文件,并在 `raw` 块中使用 Objective-C 语法 (`@interface`, `[...]`, `@""`)。
+
+```zc
+//> macos: framework: Foundation
+//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS
+//> linux: link: -lgnustep-base -lobjc
+
+include <Foundation/Foundation.h>
+
+fn main() {
+ raw {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSLog(@"来自 Objective-C 的问候!");
+ [pool drain];
+ }
+ println "Zen C 也能正常工作!";
+}
+```
+
+> **注意:** Zen C 字符串插值通过调用 `debugDescription` 或 `description` 同样适用于 Objective-C 对象 (`id`)。
+
+---
+
+## 贡献
+
+我们欢迎各类贡献!无论是修复 Bug、完善文档,还是提出新功能建议。
+
+### 如何贡献
+1. **Fork 仓库**:标准的 GitHub 工作流程。
+2. **创建功能分支**:`git checkout -b feature/NewThing`。
+3. **代码规范**:
+ * 遵循现有的 C 风格。
+ * 确保所有测试通过:`make test`。
+ * 在 `tests/` 中为你的功能添加新测试。
+4. **提交拉取请求**:清晰地描述你的更改。
+
+### 运行测试
+测试套件是你最好的朋友。
+
+```bash
+# 运行所有测试 (GCC)
+make test
+
+# 运行特定的测试
+./zc run tests/test_match.zc
+
+# 使用不同的编译器运行
+./tests/run_tests.sh --cc clang
+./tests/run_tests.sh --cc zig
+./tests/run_tests.sh --cc tcc
+```
+
+### 扩展编译器
+* **解析器 (Parser)**:`src/parser/` - 递归下降解析器。
+* **代码生成 (Codegen)**:`src/codegen/` - 转译逻辑 (Zen C -> GNU C/C11)。
+* **标准库 (Standard Library)**:`std/` - 使用 Zen C 本身编写。
+
+---
+
+## 致谢与归属
+
+本项目使用了第三方库。完整许可证文本可在 `LICENSES/` 目录中找到。
+
+* **[cJSON](https://github.com/DaveGamble/cJSON)** (MIT 许可证):用于语言服务器中的 JSON 解析和生成。
+* **[zc-ape](https://github.com/OEvgeny/zc-ape)** (MIT 许可证):由 [Eugene Olonov](https://github.com/OEvgeny) 开发的原版 Zen-C 实际上便携的可执行文件 (APE) 端口。
+* **[Cosmopolitan Libc](https://github.com/jart/cosmopolitan)** (ISC 许可证):使 APE 成为可能的基础库。
diff --git a/README_ZH_TW.md b/README_ZH_TW.md
new file mode 100644
index 0000000..6fa0dbd
--- /dev/null
+++ b/README_ZH_TW.md
@@ -0,0 +1,1435 @@
+
+<div align="center">
+
+[English](README.md) • [简体中文](README_ZH_CN.md) • [繁體中文](README_ZH_TW.md) • [Español](README_ES.md)
+
+</div>
+
+<div align="center">
+
+# Zen C
+
+**現代開發體驗。零開銷。純淨 C。**
+
+[![構建狀態](https://img.shields.io/badge/build-passing-brightgreen)]()
+[![許可證](https://img.shields.io/badge/license-MIT-blue)]()
+[![版本](https://img.shields.io/badge/version-0.1.0-orange)]()
+[![平台](https://img.shields.io/badge/platform-linux-lightgrey)]()
+
+*像高級語言一樣編寫,像 C 一樣運行。*
+
+</div>
+
+---
+
+## 概述
+
+**Zen C** 是一種現代系統編程語言,可編譯為人類可讀的 `GNU C`/`C11`。它提供了一套豐富的特性,包括類型推斷、模式匹配、泛型、Trait、async/await 以及具有 RAII 能力的手動內存管理,同時保持 100% 的 C ABI 兼容性。
+
+## 社區
+
+加入官方 Zen C Discord 服務器,參與討論、展示 Demo、提問或報告 Bug!
+
+- Discord: [點擊加入](https://discord.com/invite/q6wEsCmkJP)
+
+---
+
+## 目錄
+
+- [概述](#概述)
+- [社區](#社區)
+- [快速入門](#快速入門)
+ - [安裝](#安裝)
+ - [用法](#用法)
+ - [環境變量](#環境變量)
+- [語言參考](#語言參考)
+ - [1. 變量與常量](#1-變量與常量)
+ - [2. 原始類型](#2-原始類型)
+ - [3. 複合類型](#3-複合類型)
+ - [數組](#數組)
+ - [元組](#元組)
+ - [結構體](#結構體)
+ - [不透明結構體](#不透明結構體)
+ - [枚舉](#枚舉)
+ - [聯合體](#聯合體)
+ - [類型別名](#類型別名)
+ - [不透明類型別名](#不透明類型別名)
+ - [4. 函數與 Lambda](#4-函數與-lambda)
+ - [函數](#函數)
+ - [常量參數](#常量參數)
+ - [默認參數](#默認參數)
+ - [Lambda (閉包)](#lambda-閉包)
+ - [原始函數指針](#原始函數指針)
+ - [變參函數](#變參函數)
+ - [5. 控制流](#5-控制流)
+ - [條件語句](#條件語句)
+ - [模式匹配](#模式匹配)
+ - [循環](#循環)
+ - [高級控制](#高級控制)
+ - [6. 運算符](#6-運算符)
+ - [可重載運算符](#可重載運算符)
+ - [語法糖](#語法糖)
+ - [7. 打印與字符串插值](#7-打印與字符串插值)
+ - [關鍵字](#關鍵字)
+ - [簡寫形式](#簡寫形式)
+ - [字符串插值 (F-strings)](#字符串插值-f-strings)
+ - [輸入提示 (`?`)](#輸入提示-)
+ - [8. 內存管理](#8-內存管理)
+ - [Defer](#defer)
+ - [Autofree](#autofree)
+ - [資源語義 (默認移動)](#資源語義-默認移動)
+ - [RAII / Drop Trait](#raii--drop-trait)
+ - [9. 面向對象編程](#9-面向對象編程)
+ - [方法](#方法)
+ - [Trait](#trait)
+ - [標準 Trait](#標準-trait)
+ - [組合](#組合)
+ - [10. 泛型](#10-泛型)
+ - [11. 並發 (Async/Await)](#11-並發-asyncawait)
+ - [12. 元編程](#12-元編程)
+ - [Comptime](#comptime)
+ - [Embed](#embed)
+ - [插件](#插件)
+ - [泛型 C 宏](#泛型-c-宏)
+ - [13. 屬性](#13-屬性)
+ - [自定義屬性](#自定義屬性)
+ - [智能派生](#智能派生)
+ - [14. 內聯匯編](#14-內聯匯編)
+ - [基本用法](#基本用法)
+ - [Volatile](#volatile)
+ - [命名約束](#命名約束)
+ - [15. 構建指令](#15-構建指令)
+ - [16. 關鍵字](#16-關鍵字)
+- [標準庫](#標準庫)
+- [工具鏈](#工具鏈)
+ - [語言服務器 (LSP)](#語言服務器-lsp)
+ - [REPL](#repl)
+- [編譯器支持與兼容性](#編譯器支持與兼容性)
+ - [測試套件狀態](#測試套件狀態)
+ - [使用 Zig 構建](#使用-zig-構建)
+ - [C++ 互操作](#c-互操作)
+ - [CUDA 互操作](#cuda-互操作)
+ - [Objective-C 互操作](#objective-c-互操作)
+- [貢獻](#貢獻)
+- [致謝與歸屬](#致謝與歸屬)
+
+---
+
+## 快速入門
+
+### 安裝
+
+```bash
+git clone https://github.com/z-libs/Zen-C.git
+cd Zen-C
+make
+sudo make install
+```
+
+### 便攜式構建 (APE)
+
+Zen C 可以通過 [Cosmopolitan Libc](https://github.com/jart/cosmopolitan) 編譯為 **Actually Portable Executable (APE)**。這將生成一個單個的可執行文件 (`.com`),能夠原生運行在 Linux, macOS, Windows, FreeBSD, OpenBSD, 和 NetBSD 上的 x86_64 和 aarch64 架構上。
+
+**前提條件:**
+- `cosmocc` 工具鏈(必須在 PATH 中)
+
+**構建與安裝:**
+```bash
+make ape
+sudo env "PATH=$PATH" make install-ape
+```
+
+**產物:**
+- `out/bin/zc.com`: 便攜式 Zen-C 編譯器。已將標準庫嵌入到可執行文件中。
+- `out/bin/zc-boot.com`: 一個自包含的引導安裝程序,用於設置新的 Zen-C 項目。
+
+**用法:**
+```bash
+# 在任何支持的操作系統上運行
+./out/bin/zc.com build hello.zc -o hello
+```
+
+### 用法
+
+```bash
+# 編譯並運行
+zc run hello.zc
+
+# 構建可執行文件
+zc build hello.zc -o hello
+
+# 交互式 Shell
+zc repl
+```
+
+### 環境變量
+
+你可以設置 `ZC_ROOT` 來指定標準庫的位置(標準導入如 `import "std/vector.zc"`)。這允許你從任何目錄運行 `zc`。
+
+```bash
+export ZC_ROOT=/path/to/Zen-C
+```
+
+---
+
+## 語言參考
+
+### 1. 變量與常量
+
+Zen C 區分編譯時常量和運行時變量。
+
+#### 清單常量 (`def`)
+僅在編譯時存在的值(折疊到代碼中)。用於數組大小、固定配置和魔術數字。
+
+```zc
+def MAX_SIZE = 1024;
+let buffer: char[MAX_SIZE]; // 有效的數組大小
+```
+
+#### 變量 (`let`)
+內存中的存儲位置。可以是可變的或只讀的 (`const`)。
+
+```zc
+let x = 10; // 可變
+x = 20; // 允許
+
+let y: const int = 10; // 只讀 (類型修飾)
+// y = 20; // 錯誤:無法賦值給 const 變量
+```
+
+> **型別推導**:Zen C 自動推導初始化變數的型別。在支援的編譯器上編譯為 C23 的 `auto`,否則使用 GCC 的 `__auto_type` 擴充功能。
+
+### 2. 原始類型
+
+| 類型 | C 等效類型 | 描述 |
+|:---|:---|:---|
+| `int`, `uint` | `int`, `unsigned int` | 平台標準整數 |
+| `I8` .. `I128` 或 `i8` .. `i128` | `int8_t` .. `__int128_t` | 有符號固定寬度整數 |
+| `U8` .. `U128` 或 `u8` .. `u128` | `uint8_t` .. `__uint128_t` | 無符號固定寬度整數 |
+| `isize`, `usize` | `ptrdiff_t`, `size_t` | 指針大小的整數 |
+| `byte` | `uint8_t` | U8 的別名 |
+| `F32`, `F64` 或 `f32`, `f64` | `float`, `double` | 浮點數 |
+| `bool` | `bool` | `true` 或 `false` |
+| `char` | `char` | 單個字符 |
+| `string` | `char*` | C-string (以 null 結尾) |
+| `U0`, `u0`, `void` | `void` | 空類型 |
+| `iN` (例 `i256`) | `_BitInt(N)` | 任意位元寬度有號整數 (C23) |
+| `uN` (例 `u42`) | `unsigned _BitInt(N)` | 任意位元寬度無號整數 (C23) |
+
+### 3. 複合類型
+
+#### 數組
+具有值語義的固定大小數組。
+```zc
+def SIZE = 5;
+let ints: int[SIZE] = [1, 2, 3, 4, 5];
+let zeros: [int; SIZE]; // 零初始化的
+```
+
+#### 元組
+將多個值組合在一起,通過索引訪問元素。
+```zc
+let pair = (1, "Hello");
+let x = pair.0; // 1
+let s = pair.1; // "Hello"
+```
+
+**多個返回值**
+
+函數可以返回元組以提供多個結果:
+```zc
+fn add_and_subtract(a: int, b: int) -> (int, int) {
+ return (a + b, a - b);
+}
+
+let result = add_and_subtract(3, 2);
+let sum = result.0; // 5
+let diff = result.1; // 1
+```
+
+**解構**
+
+元組可以直接解構為多個變量:
+```zc
+let (sum, diff) = add_and_subtract(3, 2);
+// sum = 5, diff = 1
+```
+
+#### 結構體
+帶有可選位域的數據結構。
+```zc
+struct Point {
+ x: int;
+ y: int;
+}
+
+// 結構體初始化
+let p = Point { x: 10, y: 20 };
+
+// 位域
+struct Flags {
+ valid: U8 : 1;
+ mode: U8 : 3;
+}
+```
+
+> **注意**:結構體默認使用 [移動語義](#資源語義-默認移動)。即使是指針,也可以通過 `.` 訪問字段(自動解引用)。
+
+#### 不透明結構體
+你可以將結構體定義為 `opaque`,以將對其字段的訪問限制在定義該結構體的模塊內部,同時仍允許在棧上分配該結構體(大小已知)。
+
+```zc
+// 在 user.zc 中
+opaque struct User {
+ id: int;
+ name: string;
+}
+
+fn new_user(name: string) -> User {
+ return User{id: 1, name: name}; // 允許:在模塊內部
+}
+
+// 在 main.zc 中
+import "user.zc";
+
+fn main() {
+ let u = new_user("Alice");
+ // let id = u.id; // 錯誤:無法訪問私有字段 'id'
+}
+```
+
+#### 枚舉
+能夠持有數據的標籤聯合 (Sum types)。
+```zc
+enum Shape {
+ Circle(float), // 持有半徑
+ Rect(float, float), // 持有寬、高
+ Point // 不帶數據
+}
+```
+
+#### 聯合體
+標準 C 聯合體(不安全訪問)。
+```zc
+union Data {
+ i: int;
+ f: float;
+}
+```
+
+#### 類型別名
+為現有類型創建新名稱。
+```zc
+alias ID = int;
+alias PointMap = Map<string, Point>;
+```
+
+#### 不透明類型別名
+你可以將類型別名定義為 `opaque`,從而在定義模塊之外創建一個與基礎類型不同的新類型。這提供了強大的封裝和類型安全性,而沒有包裝結構體的運行時開銷。
+
+```zc
+// 在 library.zc 中
+opaque alias Handle = int;
+
+fn make_handle(v: int) -> Handle {
+ return v; // 允許在模塊內部進行隱式轉換
+}
+
+// 在 main.zc 中
+import "library.zc";
+
+fn main() {
+ let h: Handle = make_handle(42);
+ // let i: int = h; // 錯誤:類型驗證失敗
+ // let h2: Handle = 10; // 錯誤:類型驗證失敗
+}
+```
+
+### 4. 函數與 Lambda
+
+#### 函數
+```zc
+fn add(a: int, b: int) -> int {
+ return a + b;
+}
+
+// 調用時支持命名參數
+add(a: 10, b: 20);
+```
+
+> **注意**:命名參數必須嚴格遵循定義的參數順序。`add(b: 20, a: 10)` 是無效的。
+
+#### 常量參數
+函數參數可以標記為 `const` 以強制執行只讀語義。這是一個類型修飾符,而不是清單常量。
+
+```zc
+fn print_val(v: const int) {
+ // v = 10; // 錯誤:無法賦值給 const 變量
+ println "{v}";
+}
+```
+
+#### 默認參數
+函數可以為尾部參數定義默認值。這些值可以是字面量、表達式或有效的 Zen C 代碼(如結構體構造函數)。
+```zc
+// 簡單默認值
+fn increment(val: int, amount: int = 1) -> int {
+ return val + amount;
+}
+
+// 表達式默認值(在調用處計算)
+fn offset(val: int, pad: int = 10 * 2) -> int {
+ return val + pad;
+}
+
+// 結構體默認值
+struct Config { debug: bool; }
+fn init(cfg: Config = Config { debug: true }) {
+ if cfg.debug { println "調試模式"; }
+}
+
+fn main() {
+ increment(10); // 11
+ offset(5); // 25
+ init(); // 打印 "調試模式"
+}
+```
+
+#### Lambda (閉包)
+可以捕獲環境的匿名函數。
+```zc
+let factor = 2;
+let double = x -> x * factor; // 箭頭語法
+let full = fn(x: int) -> int { return x * factor; }; // 塊語法
+```
+
+#### 原始函數指針
+Zen C 使用 `fn*` 語法支持原始 C 函數指針。這允許與期望函數指針且沒有閉包開銷的 C 庫進行無縫互操作。
+
+```zc
+// 接受原始函數指針的函數
+fn set_callback(cb: fn*(int)) {
+ cb(42);
+}
+
+// 返回原始函數指針的函數
+fn get_callback() -> fn*(int) {
+ return my_handler;
+}
+
+// 支持指向函數指針的指針 (fn**)
+let pptr: fn**(int) = &ptr;
+```
+
+#### 變參函數
+函數可以使用 `...` 和 `va_list` 類型接受可變數量的參數。
+```zc
+fn log(lvl: int, fmt: char*, ...) {
+ let ap: va_list;
+ va_start(ap, fmt);
+ vprintf(fmt, ap); // 使用 C stdio
+ va_end(ap);
+}
+```
+
+### 5. 控制流
+
+#### 条件语句
+```zc
+if x > 10 {
+ print("Large");
+} else if x > 5 {
+ print("Medium");
+} else {
+ print("Small");
+}
+
+// 三元運算符
+let y = x > 10 ? 1 : 0;
+```
+
+#### 模式匹配
+`switch` 的強大替代方案。
+```zc
+match val {
+ 1 => { print "One" },
+ 2 || 3 => { print "Two or Three" }, // 使用 || 進行 或 操作
+ 4 or 5 => { print "Four or Five" }, // 使用 'or' 進行 或 操作
+ 6, 7, 8 => { print "Six to Eight" }, // 使用逗號進行 或 操作
+ 10 .. 15 => { print "10 to 14" }, // 左閉右開區間 (舊語法)
+ 10 ..< 15 => { print "10 to 14" }, // 左閉右開區間 (顯式)
+ 20 ..= 25 => { print "20 to 25" }, // 全閉區間
+ _ => { print "Other" },
+}
+
+// 解構枚舉
+match shape {
+ Shape::Circle(r) => println "半徑: {r}",
+ Shape::Rect(w, h) => println "面積: {w*h}",
+ Shape::Point => println "點"
+}
+```
+
+#### 引用綁定
+為了在不獲取所有權(移動)的情況下檢查一個值,在模式中使用 `ref` 關鍵字。這對於實現了移動語義的類型(如 `Option`, `Result`, 非 Copy 結構體)至關重要。
+
+```zc
+let opt = Some(NonCopyVal{...});
+match opt {
+ Some(ref x) => {
+ // 'x' 是指向 'opt' 內部值的指針
+ // 'opt' 在此處不會被移動/消耗
+ println "{x.field}";
+ },
+ None => {}
+}
+```
+
+#### 循環
+```zc
+// 區間迭代
+for i in 0..10 { ... } // 左閉右開 (0 到 9)
+for i in 0..<10 { ... } // 左閉右開 (顯式)
+for i in 0..=10 { ... } // 全閉 (0 到 10)
+for i in 0..10 step 2 { ... }
+
+// 迭代器 (Vec 或自定義 Iterable)
+for item in vec { ... }
+
+// 直接迭代固定大小數組
+let arr: int[5] = [1, 2, 3, 4, 5];
+for val in arr {
+ // val 是 int
+ println "{val}";
+}
+
+// While 循環
+while x < 10 { ... }
+
+// 帶標籤的無限循環
+outer: loop {
+ if done { break outer; }
+}
+
+// 重複 N 次
+for _ in 0..5 { ... }
+```
+
+#### 高級控制
+```zc
+// Guard: 如果條件為假,則執行 else 塊並返回
+guard ptr != NULL else { return; }
+
+// Unless: 除非為真(即如果為假)
+unless is_valid { return; }
+```
+
+### 6. 運算符
+
+Zen C 通過實現特定的方法名來支持用戶定義結構體的運算符重載。
+
+#### 可重載運算符
+
+| 類別 | 運算符 | 方法名 |
+|:---|:---|:---|
+| **算術** | `+`, `-`, `*`, `/`, `%` | `add`, `sub`, `mul`, `div`, `rem` |
+| **比較** | `==`, `!=` | `eq`, `neq` |
+| | `<`, `>`, `<=`, `>=` | `lt`, `gt`, `le`, `ge` |
+| **位運算** | `&`, `|`, `^` | `bitand`, `bitor`, `bitxor` |
+| | `<<`, `>>` | `shl`, `shr` |
+| **一元** | `-` | `neg` |
+| | `!` | `not` |
+| | `~` | `bitnot` |
+| **索引** | `a[i]` | `get(a, i)` |
+| | `a[i] = v` | `set(a, i, v)` |
+
+> **關於字符串相等性的說明**:
+> - `string == string` 進行 **值比較**(等同於 `strcmp`)。
+> - `char* == char*` 進行 **指針比較**(檢查內存地址)。
+> - 混合比較(例如 `string == char*`)默認為 **指針比較**。
+
+**示例:**
+```zc
+impl Point {
+ fn add(self, other: Point) -> Point {
+ return Point{x: self.x + other.x, y: self.y + other.y};
+ }
+}
+
+let p3 = p1 + p2; // 調用 p1.add(p2)
+```
+
+#### 語法糖
+
+這些運算符是內置語言特性,不能直接重載。
+
+| 運算符 | 名稱 | 描述 |
+|:---|:---|:---|
+| `|>` | 管道 | `x |> f(y)` 脫糖為 `f(x, y)` |
+| `??` | 空合併 | 如果 `val` 為 NULL,`val ?? default` 返回 `default` (用於指針) |
+| `??=` | 空賦值 | 如果 `val` 為 NULL 則賦值 |
+| `?.` | 安全導航 | 僅當 `ptr` 不為 NULL 時訪問字段 |
+| `?` | Try 運算符 | 如果存在錯誤則返回 (用於 Result/Option 類型) |
+
+**自動解引用**:
+指針字段訪問 (`ptr.field`) 和方法調用 (`ptr.method()`) 會自動解引用指針,等同於 `(*ptr).field`。
+
+### 7. 打印與字符串插值
+
+Zen C 提供了多種控制台打印選項,包括關鍵字和簡潔的簡寫形式。
+
+#### 關鍵字
+
+- `print "text"`: 打印到 `stdout`,不帶尾隨換行符。
+- `println "text"`: 打印到 `stdout`,帶尾隨換行符。
+- `eprint "text"`: 打印到 `stderr`,不帶尾隨換行符。
+- `eprintln "text"`: 打印到 `stderr`,帶尾隨換行符。
+
+#### 簡寫形式
+
+Zen C 允許直接將字符串字面量用作語句來進行快速打印:
+
+- `"Hello World"`: 等同於 `println "Hello World"`。(隱式添加換行符)
+- `"Hello World"..`: 等同於 `print "Hello World"`。(不帶尾隨換行符)
+- `!"Error"`: 等同於 `eprintln "Error"`。(輸出到 stderr)
+- `!"Error"..`: 等同於 `eprint "Error"`。(輸出到 stderr,不帶換行符)
+
+#### 字符串插值 (F-strings)
+
+你可以使用 `{}` 語法將表達式直接嵌入到字符串字面量中。這適用於所有打印方法和字符串簡寫。
+
+```zc
+let x = 42;
+let name = "Zen";
+println "值: {x}, 名稱: {name}";
+"值: {x}, 名稱: {name}"; // 簡寫形式的 println
+```
+
+#### 輸入提示 (`?`)
+
+Zen C 支持使用 `?` 前綴進行用戶輸入提示的簡寫。
+
+- `? "提示文本"`: 打印提示信息(不換行)並等待輸入(讀取一行)。
+- `? "輸入年齡: " (age)`: 打印提示並掃描輸入到變量 `age` 中。
+ - 格式說明符會根據變量類型自動推斷。
+
+```zc
+let age: int;
+? "你多大了? " (age);
+println "你 {age} 歲了。";
+```
+
+### 8. 內存管理
+
+Zen C 允許帶有符合人體工程學輔助的手動內存管理。
+
+#### Defer
+在當前作用域退出時執行代碼。Defer 語句按照後進先出 (LIFO) 的順序執行。
+```zc
+let f = fopen("file.txt", "r");
+defer fclose(f);
+```
+
+> 為了防止未定義行為,`defer` 塊內不允許使用控制流語句(`return`, `break`, `continue`, `goto`)。
+
+#### Autofree
+在作用域退出時自動釋放變量。
+```zc
+autofree let types = malloc(1024);
+```
+
+#### 資源語義 (默認移動)
+Zen C 將帶有析構函數(如 `File`, `Vec`, 或 malloc 的指針)的類型視為 **資源**。為了防止雙重釋放錯誤,資源不能被隱式複製。
+
+- **默認移動**:分配資源變量會轉移所有權。原始變量變得無效(已移動)。
+- **複製類型**:沒有析構函數的類型可以申請參與 `Copy` 行為,使賦值變成複製。
+
+**診斷與哲學**:
+如果你看到錯誤 "Use of moved value",編譯器是在告訴你:*"此類型擁有一個資源(如內存或句柄),盲目複製它是不安全的。"*
+
+> **對比:** 與 C/C++ 不同,Zen C 不會隱式複製擁有資源的值。
+
+**函數參數**:
+將值傳遞給函數遵循與賦值相同的規則:資源會被移動,除非通過引用傳遞。
+
+```zc
+fn process(r: Resource) { ... } // 'r' 被移動進函數
+fn peek(r: Resource*) { ... } // 'r' 被借用 (引用)
+```
+
+**顯式克隆**:
+如果你 *確實* 想要一個資源的兩個副本,請顯式執行:
+
+```zc
+let b = a.clone(); // 調用 Clone trait 中的 'clone' 方法
+```
+
+**選擇性複製 (值類型)**:
+對於沒有析構函數的小型類型:
+
+```zc
+struct Point { x: int; y: int; }
+impl Copy for Point {} // 選擇參與隱式複製
+
+fn main() {
+ let p1 = Point { x: 1, y: 2 };
+ let p2 = p1; // 已複製。p1 保持有效。
+}
+```
+
+#### RAII / Drop Trait
+實現 `Drop` 以自動運行清理邏輯。
+```zc
+impl Drop for MyStruct {
+ fn drop(self) {
+ self.free();
+ }
+}
+```
+
+### 9. 面向對象編程
+
+#### 方法
+使用 `impl` 為類型定義方法。
+```zc
+impl Point {
+ // 靜態方法 (構造函數慣例)
+ fn new(x: int, y: int) -> Self {
+ return Point{x: x, y: y};
+ }
+
+ // 實例方法
+ fn dist(self) -> float {
+ return sqrt(self.x * self.x + self.y * self.y);
+ }
+}
+```
+
+#### Trait
+定義共享行為。
+```zc
+struct Circle { radius: f32; }
+
+trait Drawable {
+ fn draw(self);
+}
+
+impl Drawable for Circle {
+ fn draw(self) { ... }
+}
+
+let circle = Circle{};
+let drawable: Drawable = &circle;
+```
+
+#### 標準 Trait
+Zen C 包含與語言語法集成的標準 Trait。
+
+**Iterable**
+
+實現 `Iterable<T>` 以便為你的自定義類型啟用 `for-in` 循環。
+
+```zc
+import "std/iter.zc"
+
+// 定義一個迭代器
+struct MyIter {
+ curr: int;
+ stop: int;
+}
+
+impl MyIter {
+ fn next(self) -> Option<int> {
+ if self.curr < self.stop {
+ self.curr += 1;
+ return Option<int>::Some(self.curr - 1);
+ }
+ return Option<int>::None();
+ }
+}
+
+// 實現 Iterable
+impl MyRange {
+ fn iterator(self) -> MyIter {
+ return MyIter{curr: self.start, stop: self.end};
+ }
+}
+
+// 在循環中使用
+for i in my_range {
+ println "{i}";
+}
+```
+
+**Drop**
+
+實現 `Drop` 來定義一個在對象超出範圍時運行的析構函數 (RAII)。
+
+```zc
+import "std/mem.zc"
+
+struct Resource {
+ ptr: void*;
+}
+
+impl Drop for Resource {
+ fn drop(self) {
+ if self.ptr != NULL {
+ free(self.ptr);
+ }
+ }
+}
+```
+
+> **注意:** 如果一個變量被移動,則原始變量不會調用 `drop`。它遵循 [資源語義](#資源語義-默認移動)。
+
+**Copy**
+
+標記 Trait,用於選擇支持 `Copy` 行為(隱式複製)而不是移動語義。通過 `@derive(Copy)` 使用。
+
+> **規則:** 實現了 `Copy` 的類型不得定義析構函數 (`Drop`)。
+
+```zc
+@derive(Copy)
+struct Point { x: int; y: int; }
+
+fn main() {
+ let p1 = Point{x: 1, y: 2};
+ let p2 = p1; // 已複製!p1 保持有效。
+}
+```
+
+**Clone**
+
+實現 `Clone` 以允許顯式複製擁有資源的類型。
+
+```zc
+import "std/mem.zc"
+
+struct MyBox { val: int; }
+
+impl Clone for MyBox {
+ fn clone(self) -> MyBox {
+ return MyBox{val: self.val};
+ }
+}
+
+fn main() {
+ let b1 = MyBox{val: 42};
+ let b2 = b1.clone(); // 顯式複製
+}
+```
+
+#### 組合
+使用 `use` 嵌入其他結構體。你可以將它們混合進來(展平字段)或者為它們命名(嵌套字段)。
+
+```zc
+struct Entity { id: int; }
+
+struct Player {
+ // 混入 (未命名): 展平字段
+ use Entity; // 直接將 'id' 添加到 Player
+ name: string;
+}
+
+struct Match {
+ // 組合 (命名): 嵌套字段
+ use p1: Player; // 通過 match.p1 訪問
+ use p2: Player; // 通過 match.p2 訪問
+}
+```
+
+### 10. 泛型
+
+結構體和函數的類型安全模板。
+
+```zc
+// 泛型結構體
+struct Box<T> {
+ item: T;
+}
+
+// 泛型函數
+fn identity<T>(val: T) -> T {
+ return val;
+}
+
+// 多參數泛型
+struct Pair<K, V> {
+ key: K;
+ value: V;
+}
+```
+
+### 11. 並發 (Async/Await)
+
+基於 pthreads 構建。
+
+```zc
+async fn fetch_data() -> string {
+ // 在後台運行
+ return "Data";
+}
+
+fn main() {
+ let future = fetch_data();
+ let result = await future;
+}
+```
+
+### 12. 元編程
+
+#### Comptime
+在編譯時運行代碼以生成源碼或打印消息。
+```zc
+comptime {
+ // 在編譯時生成代碼 (寫入 stdout)
+ println "let build_date = \"2024-01-01\";";
+}
+
+println "構建日期: {build_date}";
+```
+
+#### Embed
+將文件嵌入為指定類型。
+```zc
+// 默認 (Slice_char)
+let data = embed "assets/logo.png";
+
+// 類型化嵌入
+let text = embed "shader.glsl" as string; // 嵌入為 C-string
+let rom = embed "bios.bin" as u8[1024]; // 嵌入為固定數組
+let wav = embed "sound.wav" as u8[]; // 嵌入為 Slice_u8
+```
+
+#### 插件
+導入編譯器插件以擴展語法。
+```zc
+import plugin "regex"
+let re = regex! { ^[a-z]+$ };
+```
+
+#### 泛型 C 宏
+將預處理器宏傳遞給 C。
+
+> **提示**:對於簡單的常量,請使用 `def`。當你需要 C 預處理器宏或條件編譯標誌時,請使用 `#define`。
+
+```zc
+#define MAX_BUFFER 1024
+```
+
+### 13. 屬性
+
+修飾函數和結構體以修改編譯器行為。
+
+| 屬性 | 作用域 | 描述 |
+|:---|:---|:---|
+| `@must_use` | 函數 | 如果忽略返回值則發出警告。 |
+| `@deprecated("msg")` | 函數/結構體 | 使用時發出帶有消息的警告。 |
+| `@inline` | 函數 | 提示編譯器進行內聯。 |
+| `@noinline` | 函數 | 防止內聯。 |
+| `@packed` | 結構體 | 移除字段間的填充。 |
+| `@align(N)` | 結構體 | 強制按 N 字节對齊。 |
+| `@constructor` | 函數 | 在 main 之前運行。 |
+| `@destructor` | 函數 | 在 main 退出後運行。 |
+| `@unused` | 函數/變量 | 抑制未使用變量警告。 |
+| `@weak` | 函數 | 弱符號鏈接。 |
+| `@section("name")` | 函數 | 將代碼放置在特定段中。 |
+| `@noreturn` | 函數 | 函數不會返回 (例如 exit)。 |
+| `@pure` | 函數 | 函數無副作用 (優化提示)。 |
+| `@cold` | 函數 | 函數不太可能被執行 (分支預測提示)。 |
+| `@hot` | 函數 | 函數頻繁執行 (優化提示)。 |
+| `@export` | 函數/結構體 | 導出符號 (默認可見性)。 |
+| `@global` | 函數 | CUDA: 內核入口點 (`__global__`)。 |
+| `@device` | 函數 | CUDA: 設備函數 (`__device__`)。 |
+| `@host` | 函數 | CUDA: 主機函數 (`__host__`)。 |
+| `@comptime` | 函數 | 用於編譯時執行的輔助函數。 |
+| `@derive(...)` | 結構體 | 自動實現 Trait。支持 `Debug`, `Eq` (智能派生), `Copy`, `Clone`。 |
+| `@ctype("type")` | 函數參數 | 覆蓋參數生成的 C 類型。 |
+| `@<custom>` | 任意 | 將泛型屬性傳遞給 C (例如 `@flatten`, `@alias("name")`)。 |
+
+#### 自定義屬性
+
+Zen C 支持強大的 **自定義屬性** 系統,允許你在代碼中直接使用任何 GCC/Clang 的 `__attribute__`。任何不被 Zen C 編譯器顯式識別的屬性都會被視為泛型屬性並傳遞給生成的 C 代碼。
+
+這提供了對高級編譯器特性、優化和鏈接器指令的訪問,而無需在語言核心中提供顯式支持。
+
+#### 語法映射
+Zen C 屬性直接映射到 C 屬性:
+- `@name` → `__attribute__((name))`
+- `@name(args)` → `__attribute__((name(args)))`
+- `@name("string")` → `__attribute__((name("string")))`
+
+#### 智能派生
+
+Zen C 提供了尊重移動語義的 "智能派生":
+
+- **`@derive(Eq)`**:生成一個通過引用獲取參數的相等性方法 (`fn eq(self, other: T*)`)。
+ - 當比較兩個非 Copy 結構體 (`a == b`) 時,編譯器會自動通過引用傳遞 `b` (`&b`) 以避免移動它。
+ - 字段上的遞歸相等性檢查也會優先使用指針訪問,以防止所有權轉移。
+
+### 14. 內聯匯編
+
+Zen C 為內聯匯編提供了一流支持,直接轉譯為 GCC 風格的擴展 `asm`。
+
+#### 基本用法
+在 `asm` 塊內編寫原始匯編。字符串會自動拼接。
+```zc
+asm {
+ "nop"
+ "mfence"
+}
+```
+
+#### Volatile
+防止編譯器優化掉具有副作用的匯編代碼。
+```zc
+asm volatile {
+ "rdtsc"
+}
+```
+
+#### 命名約束
+Zen C 通過命名綁定簡化了複雜的 GCC 約束語法。
+
+```zc
+// 語法: : out(變量) : in(變量) : clobber(寄存器)
+// 使用 {變量} 佔位符語法以提高可讀性
+
+fn add(a: int, b: int) -> int {
+ let result: int;
+ asm {
+ "add {result}, {a}, {b}"
+ : out(result)
+ : in(a), in(b)
+ : clobber("cc")
+ }
+ return result;
+}
+```
+
+| 類型 | 語法 | GCC 等效項 |
+|:---|:---|:---|
+| **輸出** | `: out(variable)` | `"=r"(variable)` |
+| **輸入** | `: in(variable)` | `"r"(variable)` |
+| **破壞** | `: clobber("rax")` | `"rax"` |
+| **內存** | `: clobber("memory")` | `"memory"` |
+
+> **注意:** 使用 Intel 語法時(通過 `-masm=intel`),必須確保你的構建配置正確(例如,`//> cflags: -masm=intel`)。TCC 不支持 Intel 語法的匯編。
+
+### 15. 構建指令
+
+Zen C 支持在源文件頂部使用特殊註釋來配置構建過程,無需複雜的構建系統或 Makefile。
+
+| 指令 | 參數 | 描述 |
+|:---|:---|:---|
+| `//> link:` | `-lfoo` 或 `path/to/lib.a` | 鏈接庫或對象文件。 |
+| `//> lib:` | `path/to/libs` | 添加庫搜索路徑 (`-L`)。 |
+| `//> include:` | `path/to/headers` | 添加包含頭文件搜索路徑 (`-I`)。 |
+| `//> framework:` | `Cocoa` | 鏈接 macOS Framework。 |
+| `//> cflags:` | `-Wall -O3` | 向 C 編譯器傳遞任意標誌。 |
+| `//> define:` | `MACRO` 或 `KEY=VAL` | 定義預處理器宏 (`-D`)。 |
+| `//> pkg-config:` | `gtk+-3.0` | 運行 `pkg-config` 並追加 `--cflags` 和 `--libs`。 |
+| `//> shell:` | `command` | 在構建期間執行 shell 命令。 |
+| `//> get:` | `http://url/file` | 如果特定文件不存在,則下載該文件。 |
+
+#### 特性
+
+**1. 操作系統守護 (OS Guarding)**
+在指令前加上操作系統名稱,以使其僅在特定平台上應用。
+受支持的前綴:`linux:`, `windows:`, `macos:` (或 `darwin:`)。
+
+```zc
+//> linux: link: -lm
+//> windows: link: -lws2_32
+//> macos: framework: Cocoa
+```
+
+**2. 環境變量展開**
+使用 `${VAR}` 語法在指令中展開環境變量。
+
+```zc
+//> include: ${HOME}/mylib/include
+//> lib: ${ZC_ROOT}/std
+```
+
+#### 示例
+
+```zc
+//> include: ./include
+//> lib: ./libs
+//> link: -lraylib -lm
+//> cflags: -Ofast
+//> pkg-config: gtk+-3.0
+
+import "raylib.h"
+
+fn main() { ... }
+```
+
+### 16. 關鍵字
+
+以下關鍵字在 Zen C 中是保留的。
+
+#### 聲明
+`alias`, `def`, `enum`, `fn`, `impl`, `import`, `let`, `module`, `opaque`, `struct`, `trait`, `union`, `use`
+
+#### 控制流
+`async`, `await`, `break`, `catch`, `continue`, `defer`, `else`, `for`, `goto`, `guard`, `if`, `loop`, `match`, `return`, `try`, `unless`, `while`
+
+#### 特殊
+`asm`, `assert`, `autofree`, `comptime`, `const`, `embed`, `launch`, `ref`, `sizeof`, `static`, `test`, `volatile`
+
+#### 常量
+`true`, `false`, `null`
+
+#### C 保留字
+以下標識符是保留的,因為它們是 C11 中的關鍵字:
+`auto`, `case`, `char`, `default`, `do`, `double`, `extern`, `float`, `inline`, `int`, `long`, `register`, `restrict`, `short`, `signed`, `switch`, `typedef`, `unsigned`, `void`, `_Atomic`, `_Bool`, `_Complex`, `_Generic`, `_Imaginary`, `_Noreturn`, `_Static_assert`, `_Thread_local`
+
+#### 運算符
+`and`, `or`
+
+---
+
+## 標準庫
+
+Zen C 包含一個涵蓋基本功能的標準庫 (`std`)。
+
+[瀏覽標準庫文檔](docs/std/README.md)
+
+### 核心模塊
+
+| 模塊 | 描述 | 文檔 |
+| :--- | :--- | :--- |
+| **`std/vec.zc`** | 可增長動態數組 `Vec<T>`。 | [文檔](docs/std/vec.md) |
+| **`std/string.zc`** | 堆分配的 `String` 類型,支持 UTF-8。 | [文檔](docs/std/string.md) |
+| **`std/queue.zc`** | 先進先出隊列 (環形緩衝區)。 | [文檔](docs/std/queue.md) |
+| **`std/map.zc`** | 泛型哈希表 `Map<V>`。 | [文檔](docs/std/map.md) |
+| **`std/fs.zc`** | 文件系統操作。 | [文檔](docs/std/fs.md) |
+| **`std/io.zc`** | 標準輸入/輸出 (`print`/`println`)。 | [文檔](docs/std/io.md) |
+| **`std/option.zc`** | 可選值 (`Some`/`None`)。 | [文檔](docs/std/option.md) |
+| **`std/result.zc`** | 錯誤處理 (`Ok`/`Err`)。 | [文檔](docs/std/result.md) |
+| **`std/path.zc`** | 跨平台路徑操作。 | [文檔](docs/std/path.md) |
+| **`std/env.zc`** | 進程環境變量。 | [文檔](docs/std/env.md) |
+| **`std/net.zc`** | TCP 網絡 (套接字)。 | [文檔](docs/std/net.md) |
+| **`std/thread.zc`** | 線程與同步。 | [文檔](docs/std/thread.md) |
+| **`std/time.zc`** | 時間測量與睡眠。 | [文檔](docs/std/time.md) |
+| **`std/json.zc`** | JSON 解析與序列化。 | [文檔](docs/std/json.md) |
+| **`std/stack.zc`** | 後進先出棧 `Stack<T>`。 | [文檔](docs/std/stack.md) |
+| **`std/set.zc`** | 泛型哈希集合 `Set<T>`。 | [文檔](docs/std/set.md) |
+| **`std/process.zc`** | 進程執行與管理。 | [文檔](docs/std/process.md) |
+
+---
+
+## 工具鏈
+
+Zen C 提供內置的語言服務器 (LSP) 和 REPL 以增強開發體驗。
+
+### 語言服務器 (LSP)
+
+Zen C 語言服務器 (LSP) 支持標準的 LSP 特性,用於編輯器集成:
+
+* **轉到定義**
+* **查找引用**
+* **懸停信息**
+* **補全** (函數/結構體名,方法/字段的點補全)
+* **文檔符號** (大綱)
+* **簽名幫助**
+* **診斷** (語法/語義錯誤)
+
+啟動語言服務器(通常在編輯器的 LSP 設置中配置):
+
+```bash
+zc lsp
+```
+
+它通過標準 I/O (JSON-RPC 2.0) 進行通信。
+
+### REPL
+
+Read-Eval-Print Loop 允許你交互式地嘗試 Zen C 代碼。
+
+```bash
+zc repl
+```
+
+#### 特性
+
+* **交互式編碼**:輸入表達式或語句以立即求值。
+* **持久歷史**:命令保存在 `~/.zprep_history` 中。
+* **啟動腳本**:自動加載 `~/.zprep_init.zc` 中的命令。
+
+#### 命令
+
+| 命令 | 描述 |
+|:---|:---|
+| `:help` | 顯示可用命令。 |
+| `:reset` | 清除當前會話歷史 (變量/函數)。 |
+| `:vars` | 顯示活躍變量。 |
+| `:funcs` | 顯示用戶定義的函數。 |
+| `:structs` | 顯示用戶定義的結構體。 |
+| `:imports` | 顯示活躍導入。 |
+| `:history` | 顯示會話輸入歷史。 |
+| `:type <expr>` | 顯示表達式的類型。 |
+| `:c <stmt>` | 顯示語句生成的 C 代碼。 |
+| `:time <expr>` | 基准測試表達式 (運行 1000 次迭代)。 |
+| `:edit [n]` | 在 `$EDITOR` 中編輯命令 `n` (默認:最後一條)。 |
+| `:save <file>` | 將當前會話保存到 `.zc` 文件。 |
+| `:load <file>` | 將 `.zc` 文件加載並執行到會話中。 |
+| `:watch <expr>` | 監視表達式 (每次輸入後重新求值)。 |
+| `:unwatch <n>` | 移除監視。 |
+| `:undo` | 從會話中移除最後一條命令。 |
+| `:delete <n>` | 移除索引為 `n` 的命令。 |
+| `:clear` | 清屏。 |
+| `:quit` | 退出 REPL。 |
+| `! <cmd>` | 運行 shell 命令 (如 `!ls`)。 |
+
+---
+
+
+## 編譯器支持與兼容性
+
+Zen C 旨在與大多數 C11 編譯器配合使用。某些特性依賴於 GNU C 擴展,但這些擴展通常在其他編譯器中也能工作。使用 `--cc` 標誌切換後端。
+
+```bash
+zc run app.zc --cc clang
+zc run app.zc --cc zig
+```
+
+### 測試套件狀態
+
+| 編譯器 | 通過率 | 受支持特性 | 已知局限性 |
+|:---|:---:|:---|:---|
+| **GCC** | **100%** | 所有特性 | 無。 |
+| **Clang** | **100%** | 所有特性 | 無。 |
+| **Zig** | **100%** | 所有特性 | 無。使用 `zig cc` 作為替代 C 編譯器。 |
+| **TCC** | **~70%** | 基本語法, 泛型, Trait | 不支持 `__auto_type`, 不支持 Intel ASM, 不支持嵌套函數。 |
+
+> **建議:** 生產環境構建請使用 **GCC**, **Clang**, 或 **Zig**。TCC 非常適合快速原型開發,因為它編譯速度極快,但缺少 Zen C 全面支持所需的一些高級 C 擴展。
+
+### 使用 Zig 構建
+
+Zig 的 `zig cc` 命令提供了 GCC/Clang 的替代方案,具有出色的跨平台編譯支持。使用 Zig:
+
+```bash
+# 使用 Zig 編譯並運行 Zen C 程序
+zc run app.zc --cc zig
+
+# 使用 Zig 構建 Zen C 編譯器本身
+make zig
+```
+
+### C++ 互操作
+
+Zen C 可以通過 `--cpp` 標誌生成 C++ 兼容的代碼,從而實現與 C++ 庫的無縫集成。
+
+```bash
+# 直接使用 g++ 編譯
+zc app.zc --cpp
+
+# 或者轉譯用於手動構建
+zc transpile app.zc --cpp
+g++ out.c my_cpp_lib.o -o app
+```
+
+#### 在 Zen C 中使用 C++
+
+包含 C++ 頭文件並在 `raw` 塊中使用 C++ 代碼:
+
+```zc
+include <vector>
+include <iostream>
+
+raw {
+ std::vector<int> make_vec(int a, int b) {
+ return {a, b};
+ }
+}
+
+fn main() {
+ let v = make_vec(1, 2);
+ raw { std::cout << "Size: " << v.size() << std::endl; }
+}
+```
+
+> **注意:** `--cpp` 標誌會將後端切換為 `g++` 並發出 C++ 兼容的代碼(使用 `auto` 代替 `__auto_type`,使用函數重載代替 `_Generic`,以及對 `void*` 進行顯式轉換)。
+
+#### CUDA 互操作
+
+Zen C 通過轉譯為 **CUDA C++** 來支持 GPU 編程。這使你在維持 Zen C 人體工程學語法的同時,能夠利用內核中的強大 C++ 特性(模板、constexpr)。
+
+```bash
+# 直接使用 nvcc 編譯
+zc run app.zc --cuda
+
+# 或者轉譯用於手動構建
+zc transpile app.zc --cuda -o app.cu
+nvcc app.cu -o app
+```
+
+#### CUDA 特定屬性
+
+| 屬性 | CUDA 等效項 | 描述 |
+|:---|:---|:---|
+| `@global` | `__global__` | 內核函數 (運行在 GPU,從主機調用) |
+| `@device` | `__device__` | 設備函數 (運行在 GPU,從 GPU 調用) |
+| `@host` | `__host__` | 主機函數 (明確僅 CPU 運行) |
+
+#### 內核啟動語法
+
+Zen C 提供了一個簡潔的 `launch` 語句用於調用 CUDA 內核:
+
+```zc
+launch kernel_name(args) with {
+ grid: num_blocks,
+ block: threads_per_block,
+ shared_mem: 1024, // 可選
+ stream: my_stream // 可選
+};
+```
+
+這轉譯為:`kernel_name<<<grid, block, shared, stream>>>(args);`
+
+#### 編寫 CUDA 內核
+
+使用帶有 `@global` 的 Zen C 函數語法和 `launch` 語句:
+
+```zc
+import "std/cuda.zc"
+
+@global
+fn add_kernel(a: float*, b: float*, c: float*, n: int) {
+ let i = thread_id();
+ if i < n {
+ c[i] = a[i] + b[i];
+ }
+}
+
+fn main() {
+ def N = 1024;
+ let d_a = cuda_alloc<float>(N);
+ let d_b = cuda_alloc<float>(N);
+ let d_c = cuda_alloc<float>(N);
+ defer cuda_free(d_a);
+ defer cuda_free(d_b);
+ defer cuda_free(d_c);
+
+ // ... 初始化數據 ...
+
+ launch add_kernel(d_a, d_b, d_c, N) with {
+ grid: (N + 255) / 256,
+ block: 256
+ };
+
+ cuda_sync();
+}
+```
+
+#### 標準庫 (`std/cuda.zc`)
+Zen C 為常見的 CUDA 操作提供了一個標準庫,以減少 `raw` 塊的使用:
+
+```zc
+import "std/cuda.zc"
+
+// 內存管理
+let d_ptr = cuda_alloc<float>(1024);
+cuda_copy_to_device(d_ptr, h_ptr, 1024 * sizeof(float));
+defer cuda_free(d_ptr);
+
+// 同步
+cuda_sync();
+
+// 線程索引 (在內核內部使用)
+let i = thread_id(); // 全局索引
+let bid = block_id();
+let tid = local_id();
+```
+
+
+> **注意:** `--cuda` 標誌設置 `nvcc` 為編譯器並隱含 `--cpp` 模式。需要安裝 NVIDIA CUDA Toolkit。
+
+### C23 支援
+
+當使用相容的後端編譯器(GCC 14+, Clang 14+)時,Zen C 支援現代 C23 特性。
+
+- **`auto`**: 如果 `__STDC_VERSION__ >= 202300L`,Zen C 會自動將型別推導映射到標準 C23 `auto`。
+- **`_BitInt(N)`**: 使用 `iN` 和 `uN` 型別(例如 `i256`, `u12`, `i24`)存取 C23 任意位元寬度整數。
+
+### Objective-C 互操作
+
+Zen C 可以通過 `--objc` 標誌編譯為 Objective-C (`.m`),允許你使用 Objective-C 框架(如 Cocoa/Foundation)和語法。
+
+```bash
+# 使用 clang (或 gcc/gnustep) 編譯
+zc app.zc --objc --cc clang
+```
+
+#### 在 Zen C 中使用 Objective-C
+
+使用 `include` 包含頭文件,並在 `raw` 塊中使用 Objective-C 語法 (`@interface`, `[...]`, `@""`)。
+
+```zc
+//> macos: framework: Foundation
+//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS
+//> linux: link: -lgnustep-base -lobjc
+
+include <Foundation/Foundation.h>
+
+fn main() {
+ raw {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSLog(@"來自 Objective-C 的問候!");
+ [pool drain];
+ }
+ println "Zen C 也能正常工作!";
+}
+```
+
+> **注意:** Zen C 字符串插值通過調用 `debugDescription` 或 `description` 同樣適用於 Objective-C 對象 (`id`)。
+
+---
+
+## 貢獻
+
+我們歡迎各類貢獻!無論是修復 Bug、完善文檔,還是提出新功能建議。
+
+### 如何貢獻
+1. **Fork 倉庫**:標準的 GitHub 工作流程。
+2. **創建功能分支**:`git checkout -b feature/NewThing`。
+3. **代碼規範**:
+ * 遵循現有的 C 風格。
+ * 確保所有測試通過:`make test`。
+ * 在 `tests/` 中為你的功能添加新測試。
+4. **提交拉取請求**:清晰地描述你的更改。
+
+### 運行測試
+測試套件是你最好的朋友。
+
+```bash
+# 運行所有測試 (GCC)
+make test
+
+# 運行特定的測試
+./zc run tests/test_match.zc
+
+# 使用不同的編譯器運行
+./tests/run_tests.sh --cc clang
+./tests/run_tests.sh --cc zig
+./tests/run_tests.sh --cc tcc
+```
+
+### 擴展編譯器
+* **解析器 (Parser)**:`src/parser/` - 遞歸下降解析器。
+* **代碼生成 (Codegen)**:`src/codegen/` - 轉譯邏輯 (Zen C -> GNU C/C11)。
+* **標準庫 (Standard Library)**:`std/` - 使用 Zen C 本身編寫。
+
+---
+
+## 致謝與歸属
+
+本項目使用了第三方庫。完整許可證文本可在 `LICENSES/` 目錄中找到。
+
+* **[cJSON](https://github.com/DaveGamble/cJSON)** (MIT 許可證):用於語言服務器中的 JSON 解析和生成。
+* **[zc-ape](https://github.com/OEvgeny/zc-ape)** (MIT 許可證):由 [Eugene Olonov](https://github.com/OEvgeny) 開發的原版 Zen-C 實際上便攜的可執行文件 (APE) 端口。
+* **[Cosmopolitan Libc](https://github.com/jart/cosmopolitan)** (ISC 許可證):使 APE 成為可能納基礎庫。
diff --git a/docs/lex.md b/docs/lex.md
new file mode 100644
index 0000000..1cd70fd
--- /dev/null
+++ b/docs/lex.md
@@ -0,0 +1,130 @@
+# Lexical Structure
+
+## Source Text
+
+Zen-C source code is encoded in UTF-8.
+
+## Grammar Notation
+
+The lexical grammar is defined using a notation similar to EBNF.
+- `Rule ::= Production`: Defines a rule.
+- `[ ... ]`: Character class.
+- `*`: Zero or more repetitions.
+- `+`: One or more repetitions.
+- `?`: Zero or one occurrence.
+- `|`: Alternation.
+- `"..."` or `'...'`: Literal string/character.
+- `~`: Negation (e.g., `~[\n]` means any character except newline).
+
+## Whitespace and Comments
+
+Whitespace separates tokens but is otherwise ignored. Comments are treated as whitespace.
+
+```text
+Whitespace ::= [ \t\n\r]+
+Comment ::= LineComment | BlockComment
+
+LineComment ::= "//" ~[\n]*
+BlockComment ::= "/*" (BlockComment | ~("*/"))* "*/"
+```
+
+## Identifiers
+
+Identifiers name entities such as variables, functions, and types.
+
+```text
+Identifier ::= IdentifierStart IdentifierPart*
+IdentifierStart ::= [a-zA-Z_]
+IdentifierPart ::= [a-zA-Z0-9_]
+```
+
+## Literals
+
+### Integer Literals
+
+Integers can be decimal, hexadecimal, or binary.
+
+```text
+IntegerLiteral ::= ( DecimalInt | HexInt | BinaryInt ) IntegerSuffix?
+
+DecimalInt ::= [0-9]+
+HexInt ::= "0x" [0-9a-fA-F]+
+BinaryInt ::= "0b" [01]+
+
+IntegerSuffix ::= "u" | "L" | "u64" | ...
+```
+*Note: The lexer technically consumes any alphanumeric sequence following a number as a suffix.*
+
+### Floating Point Literals
+
+```text
+FloatLiteral ::= [0-9]+ "." [0-9]* FloatSuffix?
+ | [0-9]+ FloatSuffix
+
+FloatSuffix ::= "f"
+```
+
+### String Literals
+
+```text
+StringLiteral ::= '"' StringChar* '"'
+StringChar ::= ~["\\] | EscapeSequence
+EscapeSequence ::= "\\" ( ["\\/bfnrt] | "u" HexDigit{4} )
+```
+
+### F-Strings
+
+```text
+FStringLiteral ::= 'f"' StringChar* '"'
+```
+
+
+### Character Literals
+
+```text
+CharLiteral ::= "'" ( ~['\\] | EscapeSequence ) "'"
+```
+
+## Keywords
+
+```text
+Keyword ::= Declaration | Control | Special | BoolLiteral | NullLiteral | LogicOp
+
+Declaration ::= "let" | "def" | "fn" | "struct" | "enum" | "union" | "alias"
+ | "trait" | "impl" | "use" | "module" | "import" | "opaque"
+
+Control ::= "if" | "else" | "match" | "for" | "while" | "loop"
+ | "return" | "break" | "continue" | "guard" | "unless"
+ | "defer" | "async" | "await" | "try" | "catch" | "goto"
+
+Special ::= "asm" | "assert" | "test" | "sizeof" | "embed" | "comptime"
+ | "autofree" | "volatile" | "launch" | "ref" | "static" | "const"
+
+BoolLiteral ::= "true" | "false"
+NullLiteral ::= "null"
+
+CReserved ::= "auto" | "case" | "char" | "default" | "do" | "double"
+ | "extern" | "float" | "inline" | "int" | "long" | "register"
+ | "restrict" | "short" | "signed" | "switch" | "typedef"
+ | "unsigned" | "void" | "_Atomic" | "_Bool" | "_Complex"
+ | "_Generic" | "_Imaginary" | "_lmaginary" | "_Noreturn"
+ | "_Static_assert" | "_Thread_local"
+
+LogicOp ::= "and" | "or"
+```
+
+## Operators and Punctuation
+
+```text
+Operator ::= "+" | "-" | "*" | "/" | "%"
+ | "&&" | "||" | "!" | "++" | "--"
+ | "&" | "|" | "^" | "~" | "<<" | ">>"
+ | "==" | "!=" | "<" | ">" | "<=" | ">="
+ | "=" | "+=" | "-=" | "*=" | "/=" | "%="
+ | "&=" | "|=" | "^=" | "<<=" | ">>="
+ | ".." | "..=" | "..<" | "..."
+ | "." | "?." | "??" | "??=" | "->" | "=>"
+ | "::" | "|>" | "?"
+ | "(" | ")" | "{" | "}" | "[" | "]"
+ | "," | ":" | ";" | "@"
+```
diff --git a/docs/std/README.md b/docs/std/README.md
index 6125a4e..3cbf8f8 100644
--- a/docs/std/README.md
+++ b/docs/std/README.md
@@ -3,10 +3,17 @@
- [Env (Environment)](./env.md) - Process environment variables.
- [File System (FS)](./fs.md) - File I/O and directory operations.
- [IO](./io.md) - Standard Input/Output.
+- [JSON](./json.md) - JSON parsing and serialization.
- [Map](./map.md) - Hash map implementation.
+- [Networking (Net)](./net.md) - TCP networking.
- [Option](./option.md) - Optional values (Some/None).
- [Path](./path.md) - File path manipulation.
+- [Process](./process.md) - Process execution and management.
- [Result](./result.md) - Error handling (Ok/Err).
- [Queue](./queue.md) - FIFO queue (Ring Buffer).
+- [Set](./set.md) - Hash set implementation.
+- [Stack](./stack.md) - LIFO stack.
- [String](./string.md) - Growable, heap-allocated string type.
+- [Thread (Concurrency)](./thread.md) - Multithreading and synchronization.
+- [Time](./time.md) - Time measurement and sleep.
- [Vector (Vec)](./vec.md) - A growable dynamic array.
diff --git a/docs/std/json.md b/docs/std/json.md
new file mode 100644
index 0000000..ce35d64
--- /dev/null
+++ b/docs/std/json.md
@@ -0,0 +1,83 @@
+# JSON (`std/json.zc`)
+
+The `std/json` module provides a DOM-style JSON parser and builder.
+
+## Usage
+
+```zc
+import "std/json.zc"
+```
+
+## Types
+
+### Struct `JsonValue`
+
+Represents a node in a JSON document.
+
+#### Creation Methods
+
+- **`fn null() -> JsonValue`**, **`fn null_ptr() -> JsonValue*`**
+- **`fn bool(b: bool) -> JsonValue`**, **`fn bool_ptr(b: bool) -> JsonValue*`**
+- **`fn number(n: double) -> JsonValue`**, **`fn number_ptr(n: double) -> JsonValue*`**
+- **`fn string(s: char*) -> JsonValue`**, **`fn string_ptr(s: char*) -> JsonValue*`**
+- **`fn array() -> JsonValue`**, **`fn array_ptr() -> JsonValue*`**
+- **`fn object() -> JsonValue`**, **`fn object_ptr() -> JsonValue*`**
+
+#### Parsing
+
+- **`fn parse(json: char*) -> Result<JsonValue*>`**
+ Parses a JSON string into a heap-allocated `JsonValue` tree.
+
+#### Accessors
+
+- **`fn is_null(self) -> bool`**, **`is_bool`**, **`is_number`**, **`is_string`**, **`is_array`**, **`is_object`**
+ Check the type of the value.
+
+- **`fn as_string(self) -> Option<char*>`**
+ Returns `Some(string)` if the value is a string, `None` otherwise.
+- **`fn as_int(self) -> Option<int>`**
+- **`fn as_float(self) -> Option<double>`**
+- **`fn as_bool(self) -> Option<bool>`**
+
+#### Object/Array Operations
+
+- **`fn push(self, val: JsonValue)`**
+ Appends a value to an array.
+- **`fn set(self, key: char*, val: JsonValue)`**
+ Sets a key-value pair in an object.
+
+- **`fn get(self, key: char*) -> Option<JsonValue*>`**
+ Retrieves a value from an object by key.
+- **`fn at(self, index: usize) -> Option<JsonValue*>`**
+ Retrieves a value from an array by index.
+
+#### Serialization
+
+- **`fn to_string(self) -> String`**
+ Serializes the JSON value to a string representation.
+
+- **`fn stringify(self, buf: String*)`**
+ Internal recursive serialization method that appends to a string buffer.
+
+**Example:**
+```zc
+let obj = JsonValue::object();
+obj.set("name", JsonValue::string("Alice"));
+obj.set("age", JsonValue::number(30.0));
+
+let json_str = obj.to_string();
+println "{json_str.c_str()}"; // {"name":"Alice","age":30}
+json_str.free();
+obj.free();
+```
+
+**Features:**
+- Proper escaping of special characters: `\"`, `\\`, `\n`, `\t`, `\r`, `\b`, `\f`
+- Numbers formatted with `%.15g` for precision
+- Recursive serialization for nested objects and arrays
+- Round-trip compatible with `parse()`
+
+#### Memory Management
+
+- **`fn free(self)`**
+ Recursively frees the JSON value and all its children.
diff --git a/docs/std/net.md b/docs/std/net.md
new file mode 100644
index 0000000..392c901
--- /dev/null
+++ b/docs/std/net.md
@@ -0,0 +1,44 @@
+# Networking (`std/net.zc`)
+
+The `std/net` module provides basic TCP networking capabilities.
+
+## Usage
+
+```zc
+import "std/net.zc"
+```
+
+## Types
+
+### Type `TcpListener`
+
+Represents a TCP socket listening for incoming connections.
+
+#### Methods
+
+- **`fn bind(host: char*, port: int) -> Result<TcpListener>`**
+ Creates a new listener bound to the specified host and port.
+
+- **`fn accept(self) -> Result<TcpStream>`**
+ Blocks waiting for a new connection. Returns a `TcpStream` for the connected client.
+
+- **`fn close(self)`**
+ Closes the listening socket.
+
+### Type `TcpStream`
+
+Represents a TCP connection stream.
+
+#### Methods
+
+- **`fn connect(host: char*, port: int) -> Result<TcpStream>`**
+ Connects to a remote host.
+
+- **`fn read(self, buf: char*, len: usize) -> Result<usize>`**
+ Reads up to `len` bytes into `buf`. Returns the number of bytes read.
+
+- **`fn write(self, buf: char*, len: usize) -> Result<usize>`**
+ Writes `len` bytes from `buf` to the stream. Returns the number of bytes written.
+
+- **`fn close(self)`**
+ Closes the connection.
diff --git a/docs/std/process.md b/docs/std/process.md
new file mode 100644
index 0000000..31485ee
--- /dev/null
+++ b/docs/std/process.md
@@ -0,0 +1,57 @@
+# Standard Library: Process (`std/process.zc`)
+
+The process module allows you to spawn and interact with child processes.
+
+## Usage
+
+```zc
+import "std/process.zc"
+
+fn main() {
+ let output = Command::new("echo")
+ .arg("hello")
+ .output();
+
+ if (output.exit_code == 0) {
+ output.stdout.print();
+ // Or access raw C string: output.stdout.c_str()
+ }
+}
+```
+
+## Structs
+
+### Command
+
+A builder for spawning a process.
+
+```zc
+struct Command {
+ program: String;
+ args: Vec<String>;
+}
+```
+
+#### Methods
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **new** | `Command::new(program: char*) -> Command` | Creates a new Command for the given program. |
+| **arg** | `arg(self, arg: char*) -> Command*` | Adds an argument to the command. Returns the command pointer for chaining. |
+| **output** | `output(self) -> Output` | Executes the command as a child process, waiting for it to finish and collecting all of its stdout. |
+| **status** | `status(self) -> int` | Executes the command as a child process and returns the exit status code. Does not capture output (output goes to stdout/stderr). |
+
+### Output
+
+The output of a finished process.
+
+```zc
+struct Output {
+ stdout: String;
+ exit_code: int;
+}
+```
+
+#### Methods
+
+`Output` implements `Drop` to automatically free the captured `stdout` string.
diff --git a/docs/std/set.md b/docs/std/set.md
new file mode 100644
index 0000000..0d62a66
--- /dev/null
+++ b/docs/std/set.md
@@ -0,0 +1,38 @@
+# Set (`std/set.zc`)
+
+The `std/set` module provides a Generic Hash Set `Set<T>`.
+
+## Usage
+
+```zc
+import "std/set.zc"
+```
+
+## Types
+
+### Struct `Set<T>`
+
+A set of unique elements.
+
+#### Methods
+
+- **`fn new() -> Set<T>`**
+ Creates a new empty set.
+
+- **`fn add(self, val: T) -> bool`**
+ Adds a value to the set. Returns `true` if the value was added, `false` if it was already present.
+
+- **`fn contains(self, val: T) -> bool`**
+ Returns `true` if the set contains the value.
+
+- **`fn remove(self, val: T) -> bool`**
+ Removes a value from the set. Returns `true` if present and removed.
+
+- **`fn length(self) -> usize`**
+ Returns the number of elements in the set.
+
+- **`fn is_empty(self) -> bool`**
+ Returns `true` if the set is empty.
+
+- **`fn clear(self)`**
+ Removes all elements from the set.
diff --git a/docs/std/slice.md b/docs/std/slice.md
new file mode 100644
index 0000000..f029995
--- /dev/null
+++ b/docs/std/slice.md
@@ -0,0 +1,93 @@
+# Standard Library: Slice (`std/slice.zc`)
+
+`Slice<T>` is a lightweight, non-owning view into a contiguous sequence of elements. It's particularly useful for working with fixed-size arrays and enabling iteration.
+
+## Usage
+
+```zc
+import "std/slice.zc"
+
+fn main() {
+ let arr: int[5] = [1, 2, 3, 4, 5];
+
+ // Direct iteration (auto-imports std/slice.zc)
+ for val in arr {
+ println "{val}";
+ }
+
+ // Manual slice creation
+ let slice = Slice<int>::from_array((int*)(&arr), 5);
+ for val in slice {
+ println "{val}";
+ }
+}
+```
+
+## Structure
+
+```zc
+struct Slice<T> {
+ data: T*;
+ len: usize;
+}
+```
+
+## Methods
+
+### Construction
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **from_array** | `Slice<T>::from_array(arr: T*, len: usize) -> Slice<T>` | Creates a slice view over an array. |
+| **new** | `Slice<T>::new(data: T*, len: usize) -> Slice<T>` | Alias for `from_array` (backwards compat). |
+
+### Iteration
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **iterator** | `iterator(self) -> SliceIter<T>` | Returns an iterator for `for-in` loops. |
+
+`SliceIter<T>` implements the iterator protocol with a `next() -> Option<T>` method.
+
+### Access & Query
+
+| Method | Signature | Description |
+| :--- | :--- | :--- |
+| **length** | `length(self) -> usize` | Returns the number of elements. |
+| **is_empty** | `is_empty(self) -> bool` | Returns true if length is 0. |
+| **get** | `get(self, idx: usize) -> Option<T>` | Returns the element at index, or None if out of bounds. |
+| **at** | `at(self, idx: usize) -> Option<T>` | Alias for `get`. |
+
+## Examples
+
+### Iterating over fixed-size arrays
+
+```zc
+// std/slice.zc is auto-imported when using for-in on arrays
+let numbers: int[3] = [10, 20, 30];
+
+for n in numbers {
+ println "Number: {n}";
+}
+```
+
+### Safe indexed access
+
+```zc
+import "std/slice.zc"
+
+let arr: int[3] = [1, 2, 3];
+let slice = Slice<int>::from_array((int*)(&arr), 3);
+
+let opt = slice.get(1);
+if (!opt.is_none()) {
+ println "Value: {opt.unwrap()}"; // Prints: Value: 2
+}
+```
+
+## Notes
+
+- `Slice<T>` does not own its data — it's just a view
+- No memory management needed (no `free()` method)
+- **Auto-import**: `std/slice.zc` is automatically imported when using `for val in arr` on a fixed-size array
+- The array pointer cast `(T*)(&arr)` is required for fixed-size arrays
diff --git a/docs/std/stack.md b/docs/std/stack.md
new file mode 100644
index 0000000..6e5da84
--- /dev/null
+++ b/docs/std/stack.md
@@ -0,0 +1,38 @@
+# Stack (`std/stack.zc`)
+
+The `std/stack` module provides a LIFO (Last-In, First-Out) stack data structure.
+
+## Usage
+
+```zc
+import "std/stack.zc"
+```
+
+## Types
+
+### Struct `Stack<T>`
+
+A generic stack.
+
+#### Methods
+
+- **`fn new() -> Stack<T>`**
+ Creates a new empty stack.
+
+- **`fn push(self, value: T)`**
+ Pushes a value onto the top of the stack.
+
+- **`fn pop(self) -> Option<T>`**
+ Removes and returns the top element of the stack. Returns `None` if empty.
+
+- **`fn length(self) -> usize`**
+ Returns the number of elements in the stack.
+
+- **`fn is_empty(self) -> bool`**
+ Returns `true` if the stack contains no elements.
+
+- **`fn clear(self)`**
+ Removes all elements from the stack.
+
+- **`fn clone(self) -> Stack<T>`**
+ Creates a deep copy of the stack.
diff --git a/docs/std/string.md b/docs/std/string.md
index 1f89e0f..a2f63f5 100644
--- a/docs/std/string.md
+++ b/docs/std/string.md
@@ -49,8 +49,12 @@ struct String {
| Method | Signature | Description |
| :--- | :--- | :--- |
| **append** | `append(self, other: String*)` | Appends another string to this one. |
+| **append_c** | `append_c(self, s: char*)` | Appends a C string literal. Uses value receiver. |
+| **append_c_ptr** | `append_c_ptr(ptr: String*, s: char*)` | Appends a C string literal using pointer receiver for guaranteed mutation. |
| **add** | `add(self, other: String*) -> String` | Concatenates this string and another into a new String. |
+**Note:** When passing `String*` to functions that need to mutate, use `append_c_ptr` instead of `append_c` for reliable mutation.
+
### Access & Query
| Method | Signature | Description |
diff --git a/docs/std/thread.md b/docs/std/thread.md
new file mode 100644
index 0000000..6ac7e29
--- /dev/null
+++ b/docs/std/thread.md
@@ -0,0 +1,47 @@
+# Concurrency (`std/thread.zc`)
+
+The `std/thread` module provides primitives for multithreading and synchronization.
+
+## Usage
+
+```zc
+import "std/thread.zc"
+```
+
+## Functions
+
+- **`fn sleep_ms(ms: int)`**
+ Sleeps the current thread for the specified number of milliseconds.
+
+## Types
+
+### Type `Thread`
+
+Represents a handle to a spawned thread.
+
+#### Methods
+
+- **`fn spawn(func: fn()) -> Result<Thread>`**
+ Spawns a new thread executing the provided function.
+ > Note: Currently supports void functions with no arguments.
+
+- **`fn join(self) -> Result<bool>`**
+ Blocks the current thread until the spawned thread finishes.
+
+### Type `Mutex`
+
+A mutual exclusion primitive for protecting shared data.
+
+#### Methods
+
+- **`fn new() -> Mutex`**
+ Creates a new mutex.
+
+- **`fn lock(self)`**
+ Acquires the lock. Blocks if the lock is already held.
+
+- **`fn unlock(self)`**
+ Releases the lock.
+
+- **`fn free(self)`**
+ Destroys the mutex and frees associated resources.
diff --git a/docs/std/time.md b/docs/std/time.md
new file mode 100644
index 0000000..97dd208
--- /dev/null
+++ b/docs/std/time.md
@@ -0,0 +1,38 @@
+# Time (`std/time.zc`)
+
+The `std/time` module provides functionality for measuring time and sleeping.
+
+## Usage
+
+```zc
+import "std/time.zc"
+```
+
+## Structs
+
+### Struct `Duration`
+
+Represents a span of time in milliseconds.
+
+#### Methods
+
+- **`fn from_ms(ms: U64) -> Duration`**
+ Creates a duration from milliseconds.
+
+- **`fn from_secs(s: U64) -> Duration`**
+ Creates a duration from seconds.
+
+### Struct `Time`
+
+Utilities for time manipulation.
+
+#### Methods
+
+- **`fn now() -> U64`**
+ Returns the current system time in milliseconds since the epoch.
+
+- **`fn sleep(d: Duration)`**
+ Sleeps for the specified duration.
+
+- **`fn sleep_ms(ms: U64)`**
+ Sleeps for the specified number of milliseconds.
diff --git a/examples/data_structures/stack.zc b/examples/data_structures/stack.zc
index 4a8593a..ea6a20a 100644
--- a/examples/data_structures/stack.zc
+++ b/examples/data_structures/stack.zc
@@ -1,11 +1,11 @@
import "std.zc"
-struct Stack<T> {
+struct MyStack<T> {
data: Vec<T>;
}
-impl Stack<T> {
+impl MyStack<T> {
fn new() -> Self {
return Self { data: Vec<T>::new() };
}
@@ -43,7 +43,7 @@ impl Stack<T> {
fn main() {
"[Integer Stack]";
- let int_stack = Stack<int>::new();
+ let int_stack = MyStack<int>::new();
defer int_stack.free();
"Pushing: 10, 20, 30";
@@ -64,7 +64,7 @@ fn main() {
"";
"[String Stack]";
- let str_stack = Stack<String>::new();
+ let str_stack = MyStack<String>::new();
defer str_stack.free();
str_stack.push(String::new("First"));
diff --git a/examples/graphics/mandelbrot.zc b/examples/graphics/mandelbrot.zc
index 04f61b9..3a0662e 100644
--- a/examples/graphics/mandelbrot.zc
+++ b/examples/graphics/mandelbrot.zc
@@ -5,35 +5,37 @@ struct Complex {
im: float,
}
-fn complex_make(re: float, im: float) -> Complex {
- return Complex { re: re, im: im };
-}
+impl Complex {
+ fn new(re: float, im: float) -> Complex {
+ return Complex { re: re, im: im };
+ }
-fn complex_add(a: Complex, b: Complex) -> Complex {
- return Complex { re: a.re + b.re, im: a.im + b.im };
-}
+ fn add(self, b: Complex) -> Complex {
+ return Complex { re: self.re + b.re, im: self.im + b.im };
+ }
-fn complex_mul(a: Complex, b: Complex) -> Complex {
- return Complex {
- re: a.re * b.re - a.im * b.im,
- im: a.re * b.im + a.im * b.re
- };
-}
+ fn mul(self, b: Complex) -> Complex {
+ return Complex {
+ re: self.re * b.re - self.im * b.im,
+ im: self.re * b.im + self.im * b.re
+ };
+ }
-fn complex_abs2(z: Complex) -> float {
- return z.re * z.re + z.im * z.im;
-}
+ fn abs2(self) -> float {
+ return self.re * self.re + self.im * self.im;
+ }
-fn complex_print(z: Complex) {
- println "{z.re}{z.im}i";
+ fn print(self) {
+ println "{self.re}{self.im}i";
+ }
}
fn pick_char(iter: int, max_iter: int, edge_chars: char[], edge_count: int) -> char {
if (iter >= max_iter) { return ' '; }
if (iter <= 0) { return edge_chars[0]; }
- let t: float = ((float)iter) / ((float)max_iter);
- let idx: int = (int)(t * ((float)(edge_count - 1)));
+ let t = (float)iter / (float)max_iter;
+ let idx = (int)(t * (float)(edge_count - 1));
if (idx < 0) { idx = 0; }
if (idx >= edge_count) { idx = edge_count - 1; }
@@ -42,32 +44,30 @@ fn pick_char(iter: int, max_iter: int, edge_chars: char[], edge_count: int) -> c
}
fn main() {
- let width: int = 120;
- let height: int = 40;
- let max_iter: int = 200;
+ let width = 120;
+ let height = 40;
+ let max_iter = 200;
- let edge_chars: char[12] = [ '#', '@', '%', '8', '&', '*', '+', '=', '-', ':', '.', ',' ];
- let edge_count: int = 12;
+ let edge_chars: char[] = [ '#', '@', '%', '8', '&', '*', '+', '=', '-', ':', '.', ',' ];
+ let edge_count = 12;
- let min_re: float = -2.2;
- let max_re: float = 1.0;
- let min_im: float = -1.2;
- let max_im: float = 1.2;
+ let min_re = -2.2;
+ let max_re = 1.0;
+ let min_im = -1.2;
+ let max_im = 1.2;
for y in 0..height {
- let im: float =
- max_im - (max_im - min_im) * ( ((float)y) / ((float)(height - 1)) );
+ let im = max_im - (max_im - min_im) * ((float)y / (float)(height - 1));
for x in 0..width {
- let re: float =
- min_re + (max_re - min_re) * ( ((float)x) / ((float)(width - 1)) );
+ let re = min_re + (max_re - min_re) * ((float)x / (float)(width - 1));
- let c: Complex = complex_make(re, im);
- let z: Complex = complex_make(0.0, 0.0);
+ let c = Complex::new(re, im);
+ let z = Complex::new(0.0, 0.0);
- let iter: int = 0;
- while (iter < max_iter and complex_abs2(z) <= 4.0) {
- z = complex_add(complex_mul(z, z), c);
+ let iter = 0;
+ while (iter < max_iter and z.abs2() <= 4.0) {
+ z = z.mul(z).add(c);
iter += 1;
}
diff --git a/examples/networking/echo_server.zc b/examples/networking/echo_server.zc
index 072c3a2..2934923 100644
--- a/examples/networking/echo_server.zc
+++ b/examples/networking/echo_server.zc
@@ -1,11 +1,13 @@
import "std/net.zc"
+def SIZE = 1024;
+
fn main() {
"Starting Echo Server on 127.0.0.1:8080...";
let listener_res = TcpListener::bind("127.0.0.1", 8080);
- if listener_res.is_err() {
+ guard listener_res.is_ok() else {
!"Failed to bind: {listener_res.err}";
return 1;
}
@@ -19,9 +21,9 @@ fn main() {
let stream = client_res.unwrap();
defer stream.close();
- let buf: char[1024];
-
- let read_res = stream.read(buf, 1024);
+ let buf = (char*)malloc(SIZE);
+ defer free(buf);
+ let read_res = stream.read(buf, SIZE);
if read_res.is_ok() {
let bytes = read_res.unwrap();
diff --git a/examples/objc_interop.zc b/examples/objc_interop.zc
new file mode 100644
index 0000000..c33fd0d
--- /dev/null
+++ b/examples/objc_interop.zc
@@ -0,0 +1,42 @@
+
+//> macos: framework: Foundation
+//> linux: cflags: -fconstant-string-class=NSConstantString -D_NATIVE_OBJC_EXCEPTIONS -I/usr/include/x86_64-linux-gnu/GNUstep -std=gnu99
+//> linux: link: -lgnustep-base -lobjc
+
+include <Foundation/Foundation.h>
+
+raw {
+ id make_nsstring(const char* s) {
+ return [NSString stringWithUTF8String:s];
+ }
+
+ void print_description(id obj) {
+ NSLog(@"[ObjC Log] Description: %@", obj);
+ }
+}
+
+fn main() {
+
+ raw {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ }
+
+ "=> Zen C + Objective-C interop demo.";
+ "=> (Make sure to run with: zc run --objc examples/objc_interop.zc)";
+
+ // Call ObjC helper to create an NSString (returned as id)
+ let s = make_nsstring("Hello from Objective-C!");
+
+ // Pass it back to ObjC
+ print_description(s);
+
+ "Zen C interpolated string: {s}";
+
+ raw {
+ // You can also raw ObjC syntax anywhere.
+ NSArray *arr = [NSArray arrayWithObjects: @"Zen", @"Bit", @"C", nil];
+ NSLog(@"[ObjC Raw] Array: %@", arr);
+
+ [pool drain];
+ }
+}
diff --git a/examples/process/exec.zc b/examples/process/exec.zc
new file mode 100644
index 0000000..712a356
--- /dev/null
+++ b/examples/process/exec.zc
@@ -0,0 +1,20 @@
+
+import "std/process.zc";
+import "std/string.zc";
+
+fn main() {
+ "Executing 'ls -la' using std/process...";
+
+ let output = Command::new("ls")
+ .arg("-l")
+ .arg("-a")
+ .output();
+
+ if output.exit_code == 0 {
+ "--- Output ---";
+ output.stdout.print();
+ "--------------";
+ } else {
+ !"Command failed with exit code: {output.exit_code}";
+ }
+}
diff --git a/examples/tools/mini_grep.zc b/examples/tools/mini_grep.zc
index 39fec07..54338bf 100644
--- a/examples/tools/mini_grep.zc
+++ b/examples/tools/mini_grep.zc
@@ -30,7 +30,7 @@ fn str_find_case(haystack: string, needle: string, ignore_case: bool) -> Option<
let n = needle;
let n_len = strlen(needle);
- while (*h != 0)
+ while (*h != '\0')
{
let is_match: bool = true;
for i in 0..n_len
@@ -52,7 +52,7 @@ fn str_find_case(haystack: string, needle: string, ignore_case: bool) -> Option<
return Option<string>::None();
}
-fn print_highlight(line: string, match_ptr: string, match_len: usize, config: GrepConfig) {
+fn print_highlight(line: string, match_ptr: string, match_len: usize, config: GrepConfig*) {
if (!config.color)
{
"{line}";
@@ -84,7 +84,7 @@ fn print_highlight(line: string, match_ptr: string, match_len: usize, config: Gr
"{current}";
}
-fn grep_file(path: string, config: GrepConfig) -> Result<int> {
+fn grep_file(path: string, config: GrepConfig*) -> Result<int> {
let content_str: String = File::read_all(path)?;
defer content_str.destroy();
let content = content_str.c_str();
@@ -95,7 +95,7 @@ fn grep_file(path: string, config: GrepConfig) -> Result<int> {
let q_len = strlen(config.query);
- while (*ptr != 0)
+ while (*ptr != '\0')
{
if (*ptr == '\n')
{
@@ -163,7 +163,7 @@ fn grep_file(path: string, config: GrepConfig) -> Result<int> {
return Result<int>::Ok(0);
}
-fn visit_dir(path: string, config: GrepConfig) {
+fn visit_dir(path: string, config: GrepConfig*) {
let entries_res = File::read_dir(path);
guard entries_res.is_ok() else return;
@@ -287,7 +287,7 @@ fn main(argc: int, argv: string*)
{
if (config.recursive)
{
- visit_dir(config.path, config);
+ visit_dir(config.path, &config);
}
else
{
@@ -296,7 +296,7 @@ fn main(argc: int, argv: string*)
}
else
{
- let res = grep_file(config.path, config);
+ let res = grep_file(config.path, &config);
if (res.is_err()) {
!"Error: {res.err}";
return 1;
diff --git a/src/ast/ast.c b/src/ast/ast.c
index 0799845..439a9f5 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -100,6 +100,7 @@ int is_integer_type(Type *t)
t->kind == TYPE_I64 || t->kind == TYPE_U64 || t->kind == TYPE_USIZE ||
t->kind == TYPE_ISIZE || t->kind == TYPE_BYTE || t->kind == TYPE_RUNE ||
t->kind == TYPE_UINT || t->kind == TYPE_I128 || t->kind == TYPE_U128 ||
+ t->kind == TYPE_BITINT || t->kind == TYPE_UBITINT ||
(t->kind == TYPE_STRUCT && t->name &&
(0 == strcmp(t->name, "int8_t") || 0 == strcmp(t->name, "uint8_t") ||
0 == strcmp(t->name, "int16_t") || 0 == strcmp(t->name, "uint16_t") ||
@@ -168,6 +169,18 @@ int type_eq(Type *a, Type *b)
{
return 0 == strcmp(a->name, b->name);
}
+ if (a->kind == TYPE_ALIAS)
+ {
+ if (a->alias.is_opaque_alias)
+ {
+ if (b->kind != TYPE_ALIAS || !b->alias.is_opaque_alias)
+ {
+ return 0;
+ }
+ return 0 == strcmp(a->name, b->name);
+ }
+ return type_eq(a->inner, b);
+ }
if (a->kind == TYPE_POINTER || a->kind == TYPE_ARRAY)
{
return type_eq(a->inner, b->inner);
@@ -250,6 +263,18 @@ static char *type_to_string_impl(Type *t)
return xstrdup("int");
case TYPE_FLOAT:
return xstrdup("float");
+ case TYPE_BITINT:
+ {
+ char *res = xmalloc(32);
+ sprintf(res, "i%d", t->array_size);
+ return res;
+ }
+ case TYPE_UBITINT:
+ {
+ char *res = xmalloc(32);
+ sprintf(res, "u%d", t->array_size);
+ return res;
+ }
case TYPE_POINTER:
{
@@ -340,6 +365,8 @@ static char *type_to_string_impl(Type *t)
}
return xstrdup(t->name);
}
+ case TYPE_ALIAS:
+ return xstrdup(t->name);
default:
return xstrdup("unknown");
@@ -438,6 +465,18 @@ static char *type_to_c_string_impl(Type *t)
return xstrdup("int");
case TYPE_FLOAT:
return xstrdup("float");
+ case TYPE_BITINT:
+ {
+ char *res = xmalloc(32);
+ sprintf(res, "_BitInt(%d)", t->array_size);
+ return res;
+ }
+ case TYPE_UBITINT:
+ {
+ char *res = xmalloc(40);
+ sprintf(res, "unsigned _BitInt(%d)", t->array_size);
+ return res;
+ }
case TYPE_POINTER:
{
@@ -524,6 +563,9 @@ static char *type_to_c_string_impl(Type *t)
case TYPE_GENERIC:
return xstrdup(t->name);
+ case TYPE_ALIAS:
+ return type_to_c_string(t->inner);
+
case TYPE_ENUM:
return xstrdup(t->name);
diff --git a/src/ast/ast.h b/src/ast/ast.h
index b272cae..4498d7c 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -58,6 +58,9 @@ typedef enum
TYPE_ARRAY, ///< Fixed size array [N].
TYPE_FUNCTION, ///< Function pointer or reference.
TYPE_GENERIC, ///< Generic type parameter (T).
+ TYPE_ALIAS, ///< Opaque type alias.
+ TYPE_BITINT, ///< C23 _BitInt(N).
+ TYPE_UBITINT, ///< C23 unsigned _BitInt(N).
TYPE_UNKNOWN ///< Unknown/unresolved type.
} TypeKind;
@@ -74,7 +77,7 @@ typedef struct Type
int is_const; ///< 1 if const-qualified.
int is_explicit_struct; ///< 1 if defined with "struct" keyword explicitly.
int is_raw; // Raw function pointer (fn*)
- int array_size; ///< Size for fixed-size arrays.
+ int array_size; ///< Size for fixed-size arrays. For TYPE_BITINT, this is the bit width.
union
{
int is_varargs; ///< 1 if function type is variadic.
@@ -84,6 +87,11 @@ typedef struct Type
int has_drop; ///< 1 if type implements Drop trait (RAII).
int has_iterable; ///< 1 if type implements Iterable trait.
} traits;
+ struct
+ {
+ int is_opaque_alias;
+ char *alias_defined_in_file;
+ } alias;
};
} Type;
@@ -221,6 +229,8 @@ struct ASTNode
int cuda_device; // @device -> __device__
int cuda_host; // @host -> __host__
+ char **c_type_overrides; // @ctype("...") per parameter
+
Attribute *attributes; // Custom attributes
} func;
@@ -263,6 +273,8 @@ struct ASTNode
{
char *alias;
char *original_type;
+ int is_opaque;
+ char *defined_in_file;
} type_alias;
struct
@@ -436,6 +448,8 @@ struct ASTNode
Attribute *attributes; // Custom attributes
char **used_structs; // Names of structs used/mixed-in
int used_struct_count;
+ int is_opaque;
+ char *defined_in_file; // File where the struct is defined (for privacy check)
} strct;
struct
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index 7c58943..37415c2 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -1,4 +1,3 @@
-
#include "codegen.h"
#include "zprep.h"
#include "../constants.h"
@@ -59,12 +58,58 @@ static void codegen_var_expr(ParserContext *ctx, ASTNode *node, FILE *out)
if (node->var_ref.suggestion && !ctx->silent_warnings)
{
char msg[256];
- sprintf(msg, "Undefined variable '%s'", node->var_ref.name);
char help[256];
- sprintf(help, "Did you mean '%s'?", node->var_ref.suggestion);
+ snprintf(msg, sizeof(msg), "Undefined variable '%s'", node->var_ref.name);
+ snprintf(help, sizeof(help), "Did you mean '%s'?", node->var_ref.suggestion);
zwarn_at(node->token, "%s\n = help: %s", msg, help);
}
}
+
+ // Check for static method call pattern: Type::method or Slice<T>::method
+ char *double_colon = strstr(node->var_ref.name, "::");
+ if (double_colon)
+ {
+ // Extract type name and method name
+ int type_len = double_colon - node->var_ref.name;
+ char *type_name = xmalloc(type_len + 1);
+ strncpy(type_name, node->var_ref.name, type_len);
+ type_name[type_len] = 0;
+
+ char *method_name = double_colon + 2; // Skip ::
+
+ // Handle generic types: Slice<int> -> Slice_int
+ char mangled_type[256];
+ if (strchr(type_name, '<'))
+ {
+ // Generic type - need to mangle it
+ char *lt = strchr(type_name, '<');
+ char *gt = strchr(type_name, '>');
+
+ if (lt && gt)
+ {
+ // Extract base type and type argument
+ *lt = 0;
+ char *type_arg = lt + 1;
+ *gt = 0;
+
+ sprintf(mangled_type, "%s_%s", type_name, type_arg);
+ }
+ else
+ {
+ strcpy(mangled_type, type_name);
+ }
+ }
+ else
+ {
+ strcpy(mangled_type, type_name);
+ }
+
+ // Output as Type__method
+ fprintf(out, "%s__%s", mangled_type, method_name);
+ free(type_name);
+ return;
+ }
+
fprintf(out, "%s", node->var_ref.name);
}
@@ -146,7 +191,6 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
else if ((strcmp(node->binary.op, "==") == 0 || strcmp(node->binary.op, "!=") == 0))
{
char *t1 = infer_type(ctx, node->binary.left);
-
int is_ptr = 0;
if (t1)
{
@@ -161,19 +205,16 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
int resolved = 0;
ASTNode *alias = global_user_structs;
- if (alias)
+ while (alias)
{
- while (alias)
+ if (alias->type == NODE_TYPE_ALIAS &&
+ strcmp(check, alias->type_alias.alias) == 0)
{
- if (alias->type == NODE_TYPE_ALIAS &&
- strcmp(check, alias->type_alias.alias) == 0)
- {
- check = alias->type_alias.original_type;
- resolved = 1;
- break;
- }
- alias = alias->next;
+ check = alias->type_alias.original_type;
+ resolved = 1;
+ break;
}
+ alias = alias->next;
}
if (!resolved)
{
@@ -183,10 +224,9 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
int is_basic = IS_BASIC_TYPE(t1);
-
ASTNode *def = t1 ? find_struct_def(ctx, t1) : NULL;
- if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic &&
- !is_ptr)
+
+ if (t1 && def && (def->type == NODE_STRUCT || def->type == NODE_ENUM) && !is_basic && !is_ptr)
{
char *base = t1;
if (strncmp(base, "struct ", 7) == 0)
@@ -239,7 +279,6 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
else if (t1 && (strcmp(t1, "string") == 0 || strcmp(t1, "char*") == 0 ||
strcmp(t1, "const char*") == 0))
{
- // Check if comparing to NULL - don't use strcmp for NULL comparisons
int is_null_compare = 0;
if (node->binary.right->type == NODE_EXPR_VAR &&
strcmp(node->binary.right->var_ref.name, "NULL") == 0)
@@ -251,10 +290,21 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
{
is_null_compare = 1;
}
+ else if (node->binary.right->type == NODE_EXPR_LITERAL &&
+ node->binary.right->literal.type_kind == LITERAL_INT &&
+ node->binary.right->literal.int_val == 0)
+ {
+ is_null_compare = 1;
+ }
+ else if (node->binary.left->type == NODE_EXPR_LITERAL &&
+ node->binary.left->literal.type_kind == LITERAL_INT &&
+ node->binary.left->literal.int_val == 0)
+ {
+ is_null_compare = 1;
+ }
if (is_null_compare)
{
- // Direct pointer comparison for NULL
fprintf(out, "(");
codegen_expression(ctx, node->binary.left, out);
fprintf(out, " %s ", node->binary.op);
@@ -285,6 +335,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
codegen_expression(ctx, node->binary.right, out);
fprintf(out, ")");
}
+ if (t1) free(t1);
}
else
{
@@ -348,7 +399,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
if (def && def->type == NODE_ENUM)
{
char mangled[256];
- sprintf(mangled, "%s_%s", target->var_ref.name, method);
+ snprintf(mangled, sizeof(mangled), "%s_%s", target->var_ref.name, method);
FuncSig *sig = find_func(ctx, mangled);
if (sig)
{
@@ -357,15 +408,13 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
int arg_idx = 0;
while (arg)
{
- if (arg_idx > 0 && arg)
+ if (arg_idx > 0)
{
fprintf(out, ", ");
}
- Type *param_t =
- (arg_idx < sig->total_args) ? sig->arg_types[arg_idx] : NULL;
+ Type *param_t = (arg_idx < sig->total_args) ? sig->arg_types[arg_idx] : NULL;
- // Tuple Packing Logic
if (param_t && param_t->kind == TYPE_STRUCT &&
strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 &&
node->call.arg_count > 1)
@@ -383,7 +432,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
arg = arg->next;
}
fprintf(out, "}");
- break; // All args consumed
+ break;
}
codegen_expression(ctx, arg, out);
@@ -403,7 +452,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
char *ptr = strchr(clean, '*');
if (ptr)
{
- *ptr = 0;
+ *ptr = '\0';
}
char *base = clean;
@@ -412,11 +461,43 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
base += 7;
}
+ char *mangled_base = base;
+ char base_buf[256];
+
+ // Mangle generic types: Slice<int> -> Slice_int, Vec<Point> -> Vec_Point
+ char *lt = strchr(base, '<');
+ if (lt)
+ {
+ char *gt = strchr(lt, '>');
+ if (gt)
+ {
+ int prefix_len = lt - base;
+ int arg_len = gt - lt - 1;
+ snprintf(base_buf, 255, "%.*s_%.*s", prefix_len, base, arg_len, lt + 1);
+ mangled_base = base_buf;
+ }
+ }
+
if (!strchr(type, '*') && target->type == NODE_EXPR_CALL)
{
- fprintf(out, "({ %s _t = ", type);
+ char *type_mangled = type;
+ char type_buf[256];
+ char *t_lt = strchr(type, '<');
+ if (t_lt)
+ {
+ char *t_gt = strchr(t_lt, '>');
+ if (t_gt)
+ {
+ int p_len = t_lt - type;
+ int a_len = t_gt - t_lt - 1;
+ snprintf(type_buf, 255, "%.*s_%.*s", p_len, type, a_len, t_lt + 1);
+ type_mangled = type_buf;
+ }
+ }
+
+ fprintf(out, "({ %s _t = ", type_mangled);
codegen_expression(ctx, target, out);
- fprintf(out, "; %s__%s(&_t", base, method);
+ fprintf(out, "; %s__%s(&_t", mangled_base, method);
ASTNode *arg = node->call.args;
while (arg)
{
@@ -429,36 +510,34 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
else
{
// Mixin Lookup Logic
- char *call_base = base;
+ char *call_base = mangled_base;
+
int need_cast = 0;
char mixin_func_name[128];
- sprintf(mixin_func_name, "%s__%s", base, method);
+ snprintf(mixin_func_name, sizeof(mixin_func_name), "%s__%s", call_base, method);
char *resolved_method_suffix = NULL;
if (!find_func(ctx, mixin_func_name))
{
- // Try resolving as a trait method: Struct__Trait_Method
StructRef *ref = ctx->parsed_impls_list;
while (ref)
{
- if (ref->node && ref->node->type == NODE_IMPL_TRAIT)
+ if (ref->node && ref->node->type == NODE_IMPL_TRAIT &&
+ strcmp(ref->node->impl_trait.target_type, base) == 0)
{
- if (strcmp(ref->node->impl_trait.target_type, base) == 0)
+ char trait_mangled[256];
+ snprintf(trait_mangled, sizeof(trait_mangled), "%s__%s_%s", base,
+ ref->node->impl_trait.trait_name, method);
+ if (find_func(ctx, trait_mangled))
{
- char trait_mangled[256];
- sprintf(trait_mangled, "%s__%s_%s", base,
- ref->node->impl_trait.trait_name, method);
- if (find_func(ctx, trait_mangled))
- {
- char *suffix =
- xmalloc(strlen(ref->node->impl_trait.trait_name) +
- strlen(method) + 2);
- sprintf(suffix, "%s_%s", ref->node->impl_trait.trait_name,
- method);
- resolved_method_suffix = suffix;
- break;
- }
+ size_t suffix_len = strlen(ref->node->impl_trait.trait_name) +
+ strlen(method) + 2;
+ char *suffix = xmalloc(suffix_len);
+ snprintf(suffix, suffix_len, "%s_%s",
+ ref->node->impl_trait.trait_name, method);
+ resolved_method_suffix = suffix;
+ break;
}
}
ref = ref->next;
@@ -473,15 +552,14 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
if (it->impl_node && it->impl_node->type == NODE_IMPL_TRAIT)
{
tname = it->impl_node->impl_trait.trait_name;
- }
- if (tname)
- {
char trait_mangled[512];
- sprintf(trait_mangled, "%s__%s_%s", base, tname, method);
+ snprintf(trait_mangled, sizeof(trait_mangled),
+ "%s__%s_%s", base, tname, method);
if (find_func(ctx, trait_mangled))
{
- char *suffix = xmalloc(strlen(tname) + strlen(method) + 2);
- sprintf(suffix, "%s_%s", tname, method);
+ size_t suffix_len = strlen(tname) + strlen(method) + 2;
+ char *suffix = xmalloc(suffix_len);
+ snprintf(suffix, suffix_len, "%s_%s", tname, method);
resolved_method_suffix = suffix;
break;
}
@@ -496,15 +574,14 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- // Method not found on primary struct, check mixins
ASTNode *def = find_struct_def(ctx, base);
if (def && def->type == NODE_STRUCT && def->strct.used_structs)
{
for (int k = 0; k < def->strct.used_struct_count; k++)
{
char mixin_check[128];
- sprintf(mixin_check, "%s__%s", def->strct.used_structs[k],
- method);
+ snprintf(mixin_check, sizeof(mixin_check), "%s__%s",
+ def->strct.used_structs[k], method);
if (find_func(ctx, mixin_check))
{
call_base = def->strct.used_structs[k];
@@ -534,11 +611,19 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
arg = arg->next;
}
fprintf(out, ")");
+
+ if (resolved_method_suffix)
+ {
+ free(resolved_method_suffix);
+ }
}
free(clean);
+ free(type);
return;
}
+ if (type) free(type);
}
+
if (node->call.callee->type == NODE_EXPR_VAR)
{
ASTNode *def = find_struct_def(ctx, node->call.callee->var_ref.name);
@@ -594,26 +679,6 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
if (node->call.arg_names && node->call.callee->type == NODE_EXPR_VAR)
{
- char *fn_name = node->call.callee->var_ref.name;
- FuncSig *sig = find_func(ctx, fn_name);
-
- if (sig && sig->arg_types)
- {
- for (int p = 0; p < sig->total_args; p++)
- {
- ASTNode *arg = node->call.args;
-
- for (int i = 0; i < node->call.arg_count && arg; i++, arg = arg->next)
- {
- if (node->call.arg_names[i] && p < node->call.arg_count)
- {
-
- // For now, emit in order provided...
- }
- }
- }
- }
-
ASTNode *arg = node->call.args;
int first = 1;
while (arg)
@@ -660,11 +725,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
strncmp(param_t->name, "Tuple_", 6) == 0 && sig->total_args == 1 &&
node->call.arg_count > 1)
{
- // Implicit Tuple Packing:
- // Function expects 1 Tuple argument, but call has multiple args -> Pack
- // them
fprintf(out, "(%s){", param_t->name);
-
ASTNode *curr = arg;
int first_field = 1;
while (curr)
@@ -679,8 +740,6 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
fprintf(out, "}");
handled = 1;
-
- // Advance main loop iterator to end
arg = NULL;
}
}
@@ -689,7 +748,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
{
if (arg == NULL)
{
- break; // Tuple packed all args
+ break;
}
}
else
@@ -714,16 +773,12 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
case NODE_EXPR_MEMBER:
if (strcmp(node->member.field, "len") == 0)
{
- if (node->member.target->type_info)
+ if (node->member.target->type_info &&
+ node->member.target->type_info->kind == TYPE_ARRAY &&
+ node->member.target->type_info->array_size > 0)
{
- if (node->member.target->type_info->kind == TYPE_ARRAY)
- {
- if (node->member.target->type_info->array_size > 0)
- {
- fprintf(out, "%d", node->member.target->type_info->array_size);
- break;
- }
- }
+ fprintf(out, "%d", node->member.target->type_info->array_size);
+ break;
}
}
@@ -746,17 +801,14 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
else
{
codegen_expression(ctx, node->member.target, out);
- // Verify actual type instead of trusting is_pointer_access flag
char *lt = infer_type(ctx, node->member.target);
int actually_ptr = 0;
if (lt && (lt[strlen(lt) - 1] == '*' || strstr(lt, "*")))
{
actually_ptr = 1;
}
- if (lt)
- {
- free(lt);
- }
+ if (lt) free(lt);
+
char *field = node->member.field;
if (field && field[0] >= '0' && field[0] <= '9')
{
@@ -779,7 +831,8 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
is_slice_struct = 1;
}
}
- if (node->index.array->resolved_type)
+
+ if (!is_slice_struct && node->index.array->resolved_type)
{
if (strncmp(node->index.array->resolved_type, "Slice_", 6) == 0)
{
@@ -794,10 +847,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
{
is_slice_struct = 1;
}
- if (inferred)
- {
- free(inferred);
- }
+ if (inferred) free(inferred);
}
if (is_slice_struct)
@@ -896,7 +946,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, "/* UNSAFE: Full Slice on unknown size */ 0; ");
+ fprintf(out, "0; ");
}
}
@@ -912,6 +962,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, "(Slice_%s){ .data = _arr + _start, .len = _len, .cap = _len }; })",
tname);
}
+ if (tname && strcmp(tname, "unknown") != 0) free(tname);
break;
}
case NODE_BLOCK:
@@ -1002,9 +1053,7 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
break;
case NODE_PLUGIN:
{
- // Plugin registry - declare external plugins
ZPlugin *found = zptr_find_plugin(node->plugin_stmt.plugin_name);
-
if (found)
{
ZApi api = {.filename = g_current_filename ? g_current_filename : "input.zc",
@@ -1084,9 +1133,9 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
break;
}
case NODE_EXPR_CAST:
- fprintf(out, "(%s)(", node->cast.target_type);
+ fprintf(out, "((%s)(", node->cast.target_type);
codegen_expression(ctx, node->cast.expr, out);
- fprintf(out, ")");
+ fprintf(out, "))");
break;
case NODE_EXPR_SIZEOF:
if (node->size_of.target_type)
@@ -1117,20 +1166,19 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
{
Type *t = node->reflection.target_type;
if (node->reflection.kind == 0)
- { // @type_name
+ {
char *s = codegen_type_to_string(t);
fprintf(out, "\"%s\"", s);
free(s);
}
else
- { // @fields
+ {
if (t->kind != TYPE_STRUCT || !t->name)
{
fprintf(out, "((void*)0)");
break;
}
char *sname = t->name;
- // Find definition
ASTNode *def = find_struct_def(ctx, sname);
if (!def)
{
diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h
index b3e971d..89614f7 100644
--- a/src/codegen/codegen.h
+++ b/src/codegen/codegen.h
@@ -48,7 +48,7 @@ char *replace_string_type(const char *args);
const char *parse_original_method_name(const char *mangled);
void emit_auto_type(ParserContext *ctx, ASTNode *init_expr, Token t, FILE *out);
char *codegen_type_to_string(Type *t);
-void emit_func_signature(FILE *out, ASTNode *func, const char *name_override);
+void emit_func_signature(ParserContext *ctx, FILE *out, ASTNode *func, const char *name_override);
char *strip_template_suffix(const char *name);
int emit_move_invalidation(ParserContext *ctx, ASTNode *node, FILE *out);
void codegen_expression_with_move(ParserContext *ctx, ASTNode *node, FILE *out);
@@ -66,7 +66,7 @@ void emit_trait_defs(ASTNode *node, FILE *out);
void emit_enum_protos(ASTNode *node, FILE *out);
void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out);
void emit_lambda_defs(ParserContext *ctx, FILE *out);
-void emit_protos(ASTNode *node, FILE *out);
+void emit_protos(ParserContext *ctx, ASTNode *node, FILE *out);
void emit_impl_vtables(ParserContext *ctx, FILE *out);
/**
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index 5fb9f54..31bd2ee 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -3,6 +3,7 @@
#include "../parser/parser.h"
#include "../zprep.h"
#include "codegen.h"
+#include "compat.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -12,7 +13,7 @@ static void emit_freestanding_preamble(FILE *out)
fputs("#include <stddef.h>\n#include <stdint.h>\n#include "
"<stdbool.h>\n#include <stdarg.h>\n",
out);
- fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
+ fputs(ZC_TCC_COMPAT_STR, out);
fputs("typedef size_t usize;\ntypedef char* string;\n", out);
fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
"int16_t\n#define U16 uint16_t\n",
@@ -49,6 +50,7 @@ void emit_preamble(ParserContext *ctx, FILE *out)
else
{
// Standard hosted preamble.
+ fputs("#define _GNU_SOURCE\n", out);
fputs("#include <stdio.h>\n#include <stdlib.h>\n#include "
"<stddef.h>\n#include <string.h>\n",
out);
@@ -84,20 +86,18 @@ void emit_preamble(ParserContext *ctx, FILE *out)
else
{
// C mode
+ fputs("#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202300L\n", out);
+ fputs("#define ZC_AUTO auto\n", out);
+ fputs("#else\n", out);
fputs("#define ZC_AUTO __auto_type\n", out);
+ fputs("#endif\n", out);
fputs("#define ZC_CAST(T, x) ((T)(x))\n", out);
- fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
+ fputs(ZC_TCC_COMPAT_STR, out);
fputs("static inline const char* _z_bool_str(_Bool b) { return b ? \"true\" : "
"\"false\"; }\n",
out);
- fputs("#define _z_str(x) _Generic((x), _Bool: \"%s\", char: \"%c\", "
- "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", "
- "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", "
- "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", "
- "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", "
- "char*: \"%s\", void*: \"%p\")\n",
- out);
- fputs("#define _z_arg(x) _Generic((x), _Bool: _z_bool_str(x), default: (x))\n", out);
+ fputs(ZC_C_GENERIC_STR, out);
+ fputs(ZC_C_ARG_GENERIC_STR, out);
}
fputs("typedef size_t usize;\ntypedef char* string;\n", out);
@@ -107,12 +107,11 @@ void emit_preamble(ParserContext *ctx, FILE *out)
fputs("typedef struct { pthread_t thread; void *result; } Async;\n", out);
}
fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
- fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
- "int16_t\n#define U16 uint16_t\n",
+ fputs("typedef void U0;\ntypedef int8_t I8;\ntypedef uint8_t U8;\ntypedef "
+ "int16_t I16;\ntypedef uint16_t U16;\n",
out);
- fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
- "int64_t\n#define U64 "
- "uint64_t\n",
+ fputs("typedef int32_t I32;\ntypedef uint32_t U32;\ntypedef int64_t I64;\ntypedef "
+ "uint64_t U64;\n",
out);
fputs("#define F32 float\n#define F64 double\n", out);
@@ -700,7 +699,7 @@ void emit_globals(ParserContext *ctx, ASTNode *node, FILE *out)
}
// Emit function prototypes
-void emit_protos(ASTNode *node, FILE *out)
+void emit_protos(ParserContext *ctx, ASTNode *node, FILE *out)
{
ASTNode *f = node;
while (f)
@@ -723,7 +722,7 @@ void emit_protos(ASTNode *node, FILE *out)
}
else
{
- emit_func_signature(out, f, NULL);
+ emit_func_signature(ctx, out, f, NULL);
fprintf(out, ";\n");
}
}
@@ -801,7 +800,7 @@ void emit_protos(ASTNode *node, FILE *out)
}
else
{
- emit_func_signature(out, m, proto);
+ emit_func_signature(ctx, out, m, proto);
fprintf(out, ";\n");
}
diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c
index a140070..82fc3ce 100644
--- a/src/codegen/codegen_main.c
+++ b/src/codegen/codegen_main.c
@@ -448,6 +448,39 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
emit_type_aliases(kids, out); // Emit local aliases (redundant but safe)
emit_trait_defs(kids, out);
+ // Also emit traits from parsed_globals_list (from auto-imported files like std/mem.zc)
+ // but only if they weren't already emitted from kids
+ StructRef *trait_ref = ctx->parsed_globals_list;
+ while (trait_ref)
+ {
+ if (trait_ref->node && trait_ref->node->type == NODE_TRAIT)
+ {
+ // Check if this trait was already in kids (explicitly imported)
+ int already_in_kids = 0;
+ ASTNode *k = kids;
+ while (k)
+ {
+ if (k->type == NODE_TRAIT && k->trait.name && trait_ref->node->trait.name &&
+ strcmp(k->trait.name, trait_ref->node->trait.name) == 0)
+ {
+ already_in_kids = 1;
+ break;
+ }
+ k = k->next;
+ }
+
+ if (!already_in_kids)
+ {
+ // Create a temporary single-node list for emit_trait_defs
+ ASTNode *saved_next = trait_ref->node->next;
+ trait_ref->node->next = NULL;
+ emit_trait_defs(trait_ref->node, out);
+ trait_ref->node->next = saved_next;
+ }
+ }
+ trait_ref = trait_ref->next;
+ }
+
// Track emitted raw statements to prevent duplicates
EmittedContent *emitted_raw = NULL;
@@ -616,7 +649,7 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
}
}
- emit_protos(merged_funcs, out);
+ emit_protos(ctx, merged_funcs, out);
emit_impl_vtables(ctx, out);
diff --git a/src/codegen/codegen_stmt.c b/src/codegen/codegen_stmt.c
index bd0c816..7828ecf 100644
--- a/src/codegen/codegen_stmt.c
+++ b/src/codegen/codegen_stmt.c
@@ -750,7 +750,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
{
fprintf(out, "inline ");
}
- emit_func_signature(out, node, NULL);
+ emit_func_signature(ctx, out, node, NULL);
fprintf(out, "\n");
fprintf(out, "{\n");
char *prev_ret = g_current_func_ret_type;
@@ -884,8 +884,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[0], id,
- check);
+ fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[0], id, check);
}
}
else
@@ -903,8 +902,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, " __auto_type %s = _tmp_%d.%s;\n", node->destruct.names[i],
- id, field);
+ fprintf(out, " ZC_AUTO %s = _tmp_%d.%s;\n", node->destruct.names[i], id,
+ field);
}
}
else
@@ -916,8 +915,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, " __auto_type %s = _tmp_%d.v%d;\n", node->destruct.names[i],
- id, i);
+ fprintf(out, " ZC_AUTO %s = _tmp_%d.v%d;\n", node->destruct.names[i], id,
+ i);
}
}
}
@@ -1528,7 +1527,7 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
}
else
{
- fprintf(out, "__auto_type");
+ fprintf(out, "ZC_AUTO");
}
fprintf(out, " _z_ret_mv = ");
codegen_expression(ctx, node->ret.value, out);
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index 8de3cf6..08707cc 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -41,7 +41,7 @@ char *strip_template_suffix(const char *name)
}
// Helper to emit C declaration (handle arrays, function pointers correctly)
-void emit_c_decl(FILE *out, const char *type_str, const char *name)
+void emit_c_decl(ParserContext *ctx, FILE *out, const char *type_str, const char *name)
{
char *bracket = strchr(type_str, '[');
char *generic = strchr(type_str, '<');
@@ -64,9 +64,34 @@ void emit_c_decl(FILE *out, const char *type_str, const char *name)
}
else if (generic && (!bracket || generic < bracket))
{
- // Strip generic part for C output
- int base_len = generic - type_str;
- fprintf(out, "%.*s %s", base_len, type_str, name);
+ char mangled_candidate[256];
+ char *gt = strchr(generic, '>');
+ int success = 0;
+
+ if (gt)
+ {
+ int base_len = generic - type_str;
+ int arg_len = gt - generic - 1;
+
+ // Limit check
+ if (base_len + arg_len + 2 < 256)
+ {
+ snprintf(mangled_candidate, 256, "%.*s_%.*s", base_len, type_str, arg_len,
+ generic + 1);
+
+ if (find_struct_def_codegen(ctx, mangled_candidate))
+ {
+ fprintf(out, "%s %s", mangled_candidate, name);
+ success = 1;
+ }
+ }
+ }
+
+ if (!success)
+ {
+ int base_len = generic - type_str;
+ fprintf(out, "%.*s %s", base_len, type_str, name);
+ }
if (bracket)
{
@@ -87,8 +112,7 @@ void emit_c_decl(FILE *out, const char *type_str, const char *name)
// Helper to emit variable declarations with array types.
void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
{
- (void)ctx;
- emit_c_decl(out, type_str, var_name);
+ emit_c_decl(ctx, out, type_str, var_name);
}
// Find struct definition
@@ -411,6 +435,10 @@ char *infer_type(ParserContext *ctx, ASTNode *node)
char *inner = infer_type(ctx, node->unary.operand);
if (inner)
{
+ if (strcmp(inner, "string") == 0)
+ {
+ return xstrdup("char");
+ }
char *ptr = strchr(inner, '*');
if (ptr)
{
@@ -640,7 +668,7 @@ char *codegen_type_to_string(Type *t)
}
// Emit function signature using Type info for correct C codegen
-void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
+void emit_func_signature(ParserContext *ctx, FILE *out, ASTNode *func, const char *name_override)
{
if (!func || func->type != NODE_FUNCTION)
{
@@ -710,7 +738,12 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
char *type_str = NULL;
- if (func->func.arg_types && func->func.arg_types[i])
+ // Check for @ctype override first
+ if (func->func.c_type_overrides && func->func.c_type_overrides[i])
+ {
+ type_str = xstrdup(func->func.c_type_overrides[i]);
+ }
+ else if (func->func.arg_types && func->func.arg_types[i])
{
type_str = codegen_type_to_string(func->func.arg_types[i]);
}
@@ -720,13 +753,14 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
const char *name = "";
+
if (func->func.param_names && func->func.param_names[i])
{
name = func->func.param_names[i];
}
// check if array type
- emit_c_decl(out, type_str, name);
+ emit_c_decl(ctx, out, type_str, name);
free(type_str);
}
if (func->func.is_varargs)
diff --git a/src/codegen/compat.h b/src/codegen/compat.h
index f2d221a..f8d9a4e 100644
--- a/src/codegen/compat.h
+++ b/src/codegen/compat.h
@@ -14,7 +14,11 @@
#define ZC_EXTERN_C_END }
#else
/* C mode */
-#define ZC_AUTO __auto_type ///< Auto type inference.
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202300L
+#define ZC_AUTO auto ///< C23 standard auto.
+#else
+#define ZC_AUTO __auto_type ///< GCC/Clang extension.
+#endif
#define ZC_CAST(T, x) ((T)(x)) ///< Explicit cast.
#define ZC_REINTERPRET(T, x) ((T)(x)) ///< Reinterpret cast.
#define ZC_EXTERN_C ///< Extern "C" (no-op in C).
@@ -22,6 +26,58 @@
#define ZC_EXTERN_C_END
#endif
+#ifdef __TINYC__
+/* TCC compatibility */
+#ifndef __auto_type
+#define __auto_type __typeof__
+#endif
+
+#ifndef __builtin_expect
+#define __builtin_expect(x, v) (x)
+#endif
+
+#ifndef __builtin_unreachable
+#define __builtin_unreachable()
+#endif
+#endif
+
+/* Centralized string definition for codegen emission */
+#define ZC_TCC_COMPAT_STR \
+ "#ifdef __TINYC__\n" \
+ "#ifndef __auto_type\n" \
+ "#define __auto_type __typeof__\n" \
+ "#endif\n" \
+ "\n" \
+ "#ifndef __builtin_expect\n" \
+ "#define __builtin_expect(x, v) (x)\n" \
+ "#endif\n" \
+ "\n" \
+ "#ifndef __builtin_unreachable\n" \
+ "#define __builtin_unreachable()\n" \
+ "#endif\n" \
+ "#endif\n"
+
+/* Generic selection string for C mode */
+#define ZC_C_GENERIC_STR \
+ "#ifdef __OBJC__\n" \
+ "#define _z_objc_map ,id: \"%s\", Class: \"%s\", SEL: \"%s\"\n" \
+ "#define _z_objc_arg_map(x) ,id: [(id)(x) description].UTF8String, Class: " \
+ "class_getName((Class)(x)), SEL: sel_getName((SEL)(x))\n" \
+ "#else\n" \
+ "#define _z_objc_map\n" \
+ "#define _z_objc_arg_map(x)\n" \
+ "#endif\n" \
+ "\n" \
+ "#define _z_str(x) _Generic((x), _Bool: \"%s\", char: \"%c\", " \
+ "signed char: \"%c\", unsigned char: \"%u\", short: \"%d\", " \
+ "unsigned short: \"%u\", int: \"%d\", unsigned int: \"%u\", " \
+ "long: \"%ld\", unsigned long: \"%lu\", long long: \"%lld\", " \
+ "unsigned long long: \"%llu\", float: \"%f\", double: \"%f\", " \
+ "char*: \"%s\", void*: \"%p\" _z_objc_map)\n"
+
+#define ZC_C_ARG_GENERIC_STR \
+ "#define _z_arg(x) _Generic((x), _Bool: _z_bool_str(x) _z_objc_arg_map(x), default: (x))\n"
+
#ifdef __cplusplus
#include <type_traits>
@@ -95,6 +151,32 @@ inline const char *_zc_fmt(void *)
}
#define _z_str(x) _zc_fmt(x)
+
+#ifdef __OBJC__
+#include <objc/objc.h>
+#include <objc/runtime.h>
+#include <objc/message.h> // for direct calls if needed, but [x description] is fine
+
+inline const char *_zc_fmt(id x)
+{
+ return [[x description] UTF8String];
+}
+inline const char *_zc_fmt(Class x)
+{
+ return class_getName(x);
+}
+inline const char *_zc_fmt(SEL x)
+{
+ return sel_getName(x);
+}
+// BOOL is signed char usually, already handled?
+// "typedef signed char BOOL;" on standard apple headers.
+// If it maps to signed char, `_zc_fmt(signed char)` handles it ("%c").
+// We might want "YES"/"NO" for BOOL.
+// But we can't distinguish typedefs in C++ function overloads easily if underlying type is same.
+// We'll leave BOOL as %c or %d for now to avoid ambiguity errors.
+#endif
+
#endif
#endif
diff --git a/src/lexer/token.c b/src/lexer/token.c
index decabbe..095815d 100644
--- a/src/lexer/token.c
+++ b/src/lexer/token.c
@@ -149,6 +149,14 @@ Token lexer_next(Lexer *l)
{
return (Token){TOK_DEF, s, 3, start_line, start_col};
}
+ if (len == 5 && strncmp(s, "trait", 5) == 0)
+ {
+ return (Token){TOK_TRAIT, s, 5, start_line, start_col};
+ }
+ if (len == 4 && strncmp(s, "impl", 4) == 0)
+ {
+ return (Token){TOK_IMPL, s, 4, start_line, start_col};
+ }
if (len == 8 && strncmp(s, "autofree", 8) == 0)
{
return (Token){TOK_AUTOFREE, s, 8, start_line, start_col};
@@ -193,6 +201,10 @@ Token lexer_next(Lexer *l)
{
return (Token){TOK_OR, s, 2, start_line, start_col};
}
+ if (len == 6 && strncmp(s, "opaque", 6) == 0)
+ {
+ return (Token){TOK_OPAQUE, s, 6, start_line, start_col};
+ }
// F-Strings
if (len == 1 && s[0] == 'f' && s[1] == '"')
diff --git a/src/lsp/lsp_analysis.c b/src/lsp/lsp_analysis.c
index 088bede..0367d93 100644
--- a/src/lsp/lsp_analysis.c
+++ b/src/lsp/lsp_analysis.c
@@ -454,11 +454,80 @@ void lsp_completion(const char *uri, int line, int col, int id)
cJSON_AddStringToObject(item, "label", s->name);
cJSON_AddNumberToObject(item, "kind", 22); // Struct
char detail[256];
- sprintf(detail, "struct %s", s->name);
+ sprintf(detail, "%sstruct %s",
+ (s->node && s->node->type == NODE_STRUCT && s->node->strct.is_opaque)
+ ? "opaque "
+ : "",
+ s->name);
cJSON_AddStringToObject(item, "detail", detail);
cJSON_AddItemToArray(items, item);
s = s->next;
}
+
+ // Globals and Constants
+ StructRef *g = g_project->ctx->parsed_globals_list;
+ while (g)
+ {
+ if (g->node)
+ {
+ cJSON *item = cJSON_CreateObject();
+ char *name =
+ (g->node->type == NODE_CONST) ? g->node->var_decl.name : g->node->var_decl.name;
+ cJSON_AddStringToObject(item, "label", name);
+ cJSON_AddNumberToObject(item, "kind", 21); // Constant/Variable
+ char detail[256];
+ sprintf(detail, "%s %s", (g->node->type == NODE_CONST) ? "const" : "var", name);
+ cJSON_AddStringToObject(item, "detail", detail);
+ cJSON_AddItemToArray(items, item);
+ }
+ g = g->next;
+ }
+
+ // Enums
+ StructRef *e = g_project->ctx->parsed_enums_list;
+ while (e)
+ {
+ if (e->node)
+ {
+ cJSON *item = cJSON_CreateObject();
+ cJSON_AddStringToObject(item, "label", e->node->enm.name);
+ cJSON_AddNumberToObject(item, "kind", 13); // Enum
+ char detail[256];
+ sprintf(detail, "enum %s", e->node->enm.name);
+ cJSON_AddStringToObject(item, "detail", detail);
+ cJSON_AddItemToArray(items, item);
+ }
+ e = e->next;
+ }
+
+ // Type Aliases
+ TypeAlias *ta = g_project->ctx->type_aliases;
+ while (ta)
+ {
+ cJSON *item = cJSON_CreateObject();
+ cJSON_AddStringToObject(item, "label", ta->alias);
+ cJSON_AddNumberToObject(item, "kind", 8); // Interface/Reference
+ char detail[256];
+ sprintf(detail, "alias %s = %s", ta->alias, ta->original_type);
+ cJSON_AddStringToObject(item, "detail", detail);
+ cJSON_AddItemToArray(items, item);
+ ta = ta->next;
+ }
+
+ // Keywords
+ const char *keywords[] = {
+ "fn", "struct", "enum", "alias", "return", "if", "else", "for", "while",
+ "break", "continue", "true", "false", "int", "char", "bool", "string", "void",
+ "import", "module", "test", "assert", "defer", "sizeof", "opaque", "unsafe", "asm",
+ "trait", "impl", "u8", "u16", "u32", "u64", "i8", "i16", "i32",
+ "i64", "f32", "f64", "usize", "isize", "const", "var", NULL};
+ for (int i = 0; keywords[i]; i++)
+ {
+ cJSON *item = cJSON_CreateObject();
+ cJSON_AddStringToObject(item, "label", keywords[i]);
+ cJSON_AddNumberToObject(item, "kind", 14); // Keyword
+ cJSON_AddItemToArray(items, item);
+ }
}
cJSON_AddItemToObject(root, "result", items);
diff --git a/src/lsp/lsp_index.c b/src/lsp/lsp_index.c
index 285dec3..975e153 100644
--- a/src/lsp/lsp_index.c
+++ b/src/lsp/lsp_index.c
@@ -151,7 +151,32 @@ void lsp_walk_node(LSPIndex *idx, ASTNode *node)
else if (node->type == NODE_STRUCT)
{
char hover[256];
- sprintf(hover, "struct %s", node->strct.name);
+ if (node->strct.is_opaque)
+ {
+ sprintf(hover, "opaque struct %s", node->strct.name);
+ }
+ else
+ {
+ sprintf(hover, "struct %s", node->strct.name);
+ }
+ lsp_index_add_def(idx, node->token, hover, node);
+ }
+ else if (node->type == NODE_ENUM)
+ {
+ char hover[256];
+ sprintf(hover, "enum %s", node->enm.name);
+ lsp_index_add_def(idx, node->token, hover, node);
+ }
+ else if (node->type == NODE_TYPE_ALIAS)
+ {
+ char hover[256];
+ sprintf(hover, "alias %s = %s", node->type_alias.alias, node->type_alias.original_type);
+ lsp_index_add_def(idx, node->token, hover, node);
+ }
+ else if (node->type == NODE_TRAIT)
+ {
+ char hover[256];
+ sprintf(hover, "trait %s", node->trait.name);
lsp_index_add_def(idx, node->token, hover, node);
}
@@ -196,6 +221,31 @@ void lsp_walk_node(LSPIndex *idx, ASTNode *node)
lsp_walk_node(idx, node->call.callee);
lsp_walk_node(idx, node->call.args);
break;
+ case NODE_MATCH:
+ lsp_walk_node(idx, node->match_stmt.expr);
+ lsp_walk_node(idx, node->match_stmt.cases);
+ break;
+ case NODE_MATCH_CASE:
+ lsp_walk_node(idx, node->match_case.guard);
+ lsp_walk_node(idx, node->match_case.body);
+ break;
+ case NODE_FOR:
+ lsp_walk_node(idx, node->for_stmt.init);
+ lsp_walk_node(idx, node->for_stmt.condition);
+ lsp_walk_node(idx, node->for_stmt.step);
+ lsp_walk_node(idx, node->for_stmt.body);
+ break;
+ case NODE_FOR_RANGE:
+ lsp_walk_node(idx, node->for_range.start);
+ lsp_walk_node(idx, node->for_range.end);
+ lsp_walk_node(idx, node->for_range.body);
+ break;
+ case NODE_LOOP:
+ lsp_walk_node(idx, node->loop_stmt.body);
+ break;
+ case NODE_DEFER:
+ lsp_walk_node(idx, node->defer_stmt.stmt);
+ break;
default:
break;
}
diff --git a/src/main.c b/src/main.c
index e2b3cde..f5d8c1b 100644
--- a/src/main.c
+++ b/src/main.c
@@ -172,6 +172,10 @@ int main(int argc, char **argv)
g_config.use_cuda = 1;
g_config.use_cpp = 1; // CUDA implies C++ mode.
}
+ else if (strcmp(arg, "--objc") == 0)
+ {
+ g_config.use_objc = 1;
+ }
else if (strcmp(arg, "--check") == 0)
{
g_config.mode_check = 1;
@@ -304,6 +308,10 @@ int main(int argc, char **argv)
{
temp_source_file = "out.cpp";
}
+ else if (g_config.use_objc)
+ {
+ temp_source_file = "out.m";
+ }
// Codegen to C/C++/CUDA
FILE *out = fopen(temp_source_file, "w");
@@ -362,8 +370,9 @@ int main(int argc, char **argv)
// If using cosmocc, it handles these usually, but keeping them is okay for Linux targets
snprintf(cmd, sizeof(cmd), "%s %s %s %s %s -o %s %s %s %s -I./src %s", g_config.cc,
- g_config.gcc_flags, g_cflags, g_config.is_freestanding ? "-ffreestanding" : "", "",
- outfile, temp_source_file, math_flag, thread_flag, g_link_flags);
+ g_config.gcc_flags, g_cflags, g_config.is_freestanding ? "-ffreestanding" : "",
+ g_config.quiet ? "-w" : "", outfile, temp_source_file, math_flag, thread_flag,
+ g_link_flags);
if (g_config.verbose)
{
diff --git a/src/parser/parser.h b/src/parser/parser.h
index cf57971..23c2920 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -261,6 +261,8 @@ typedef struct TypeAlias
char *alias; ///< New type name.
char *original_type; ///< Original type.
struct TypeAlias *next;
+ int is_opaque;
+ char *defined_in_file;
} TypeAlias;
/**
@@ -514,12 +516,9 @@ char *sanitize_mangled_name(const char *name);
/**
* @brief Registers a type alias.
*/
-void register_type_alias(ParserContext *ctx, const char *alias, const char *original);
-
-/**
- * @brief Finds a type alias.
- */
-const char *find_type_alias(ParserContext *ctx, const char *alias);
+TypeAlias *find_type_alias_node(ParserContext *ctx, const char *name);
+void register_type_alias(ParserContext *ctx, const char *alias, const char *original, int is_opaque,
+ const char *defined_in_file);
/**
* @brief Registers an implementation.
@@ -562,7 +561,8 @@ ASTNode *parse_arrow_lambda_multi(ParserContext *ctx, Lexer *l, char **param_nam
* @brief Parses and converts arguments.
*/
char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out, int *count_out,
- Type ***types_out, char ***names_out, int *is_varargs_out);
+ Type ***types_out, char ***names_out, int *is_varargs_out,
+ char ***ctype_overrides_out);
/**
* @brief Checks if a file has been imported.
@@ -681,10 +681,6 @@ void register_selective_import(ParserContext *ctx, const char *symbol, const cha
SelectiveImport *find_selective_import(ParserContext *ctx, const char *name);
// Type Aliases
-/**
- * @brief Registers a type alias.
- */
-void register_type_alias(ParserContext *ctx, const char *alias, const char *original);
/**
* @brief Finds a type alias.
@@ -741,6 +737,11 @@ FuncSig *find_func(ParserContext *ctx, const char *name);
Type *parse_type_formal(ParserContext *ctx, Lexer *l);
/**
+ * @brief Checks compatibility of opaque aliases (allows access within defining file).
+ */
+int check_opaque_alias_compat(ParserContext *ctx, Type *a, Type *b);
+
+/**
* @brief Parses a type.
*/
char *parse_type(ParserContext *ctx, Lexer *l);
@@ -889,7 +890,7 @@ ASTNode *parse_def(ParserContext *ctx, Lexer *l);
/**
* @brief Parses a type alias.
*/
-ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l);
+ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l, int is_opaque);
/**
* @brief Parses a function definition.
@@ -899,7 +900,7 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async);
/**
* @brief Parses a struct definition.
*/
-ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union);
+ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union, int is_opaque);
/**
* @brief Parses an enum definition.
@@ -963,4 +964,4 @@ char *patch_self_args(const char *args, const char *struct_name);
*/
ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l);
-#endif // PARSER_H
+#endif // PARSER_H \ No newline at end of file
diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c
index e9a418e..43137b1 100644
--- a/src/parser/parser_core.c
+++ b/src/parser/parser_core.c
@@ -338,7 +338,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
}
else if (0 == strncmp(t.start, "struct", 6) && 6 == t.len)
{
- s = parse_struct(ctx, l, 0);
+ s = parse_struct(ctx, l, 0, 0);
if (s && s->type == NODE_STRUCT)
{
s->strct.is_packed = attr_packed;
@@ -436,7 +436,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
}
else if (0 == strncmp(t.start, "type", 4) && 4 == t.len)
{
- s = parse_type_alias(ctx, l);
+ s = parse_type_alias(ctx, l, 0);
}
else if (0 == strncmp(t.start, "raw", 3) && 3 == t.len)
{
@@ -482,9 +482,31 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
lexer_next(l);
}
}
+ else if (t.type == TOK_OPAQUE)
+ {
+ lexer_next(l); // eat opaque
+ Token next = lexer_peek(l);
+ if (0 == strncmp(next.start, "struct", 6) && 6 == next.len)
+ {
+ s = parse_struct(ctx, l, 0, 1);
+ if (s && s->type == NODE_STRUCT)
+ {
+ s->strct.is_packed = attr_packed;
+ s->strct.align = attr_align;
+ }
+ }
+ else if (next.type == TOK_ALIAS)
+ {
+ s = parse_type_alias(ctx, l, 1);
+ }
+ else
+ {
+ zpanic_at(next, "Expected 'struct' or 'alias' after 'opaque'");
+ }
+ }
else if (t.type == TOK_ALIAS)
{
- s = parse_type_alias(ctx, l);
+ s = parse_type_alias(ctx, l, 0);
}
else if (t.type == TOK_ASYNC)
{
@@ -506,7 +528,7 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l)
else if (t.type == TOK_UNION)
{
- s = parse_struct(ctx, l, 1);
+ s = parse_struct(ctx, l, 1, 0);
}
else if (t.type == TOK_TRAIT)
{
@@ -700,7 +722,7 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char *
{
// Simplistic Debug for now, I know.
code = xmalloc(1024);
- sprintf(code, "impl %s { fn to_string(self) -> char* { return \"%s { ... }\"; } }",
+ sprintf(code, "impl %s { fn to_string(self) -> char* { return \"%s {{ ... }}\"; } }",
name, name);
}
else if (0 == strcmp(trait, "Copy"))
diff --git a/src/parser/parser_decl.c b/src/parser/parser_decl.c
index 98f46e1..93a124d 100644
--- a/src/parser/parser_decl.c
+++ b/src/parser/parser_decl.c
@@ -99,10 +99,11 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
int count;
Type **arg_types;
char **param_names;
+ char **ctype_overrides;
int is_varargs = 0;
- char *args =
- parse_and_convert_args(ctx, l, &defaults, &count, &arg_types, &param_names, &is_varargs);
+ char *args = parse_and_convert_args(ctx, l, &defaults, &count, &arg_types, &param_names,
+ &is_varargs, &ctype_overrides);
char *ret = "void";
Type *ret_type_obj = type_new(TYPE_VOID);
@@ -191,6 +192,7 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
node->func.defaults = defaults;
node->func.ret_type_info = ret_type_obj;
node->func.is_varargs = is_varargs;
+ node->func.c_type_overrides = ctype_overrides;
if (gen_param)
{
@@ -579,6 +581,10 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
{
type_obj->inner = init->type_info->inner; // Shallow copy for inner
}
+ if (init->type_info->kind == TYPE_ALIAS)
+ {
+ type_obj->alias = init->type_info->alias;
+ }
// Copy function type args for lambda/closure support
if (init->type_info->args && init->type_info->arg_count > 0)
{
@@ -631,6 +637,59 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
// Register in symbol table with actual token
add_symbol_with_token(ctx, name, type, type_obj, name_tok);
+ if (init && type_obj)
+ {
+ Type *t = init->type_info;
+ if (!t && init->type == NODE_EXPR_VAR)
+ {
+ t = find_symbol_type_info(ctx, init->var_ref.name);
+ }
+
+ // Literal type construction for validation
+ Type *temp_literal_type = NULL;
+ if (!t && init->type == NODE_EXPR_LITERAL)
+ {
+ if (init->literal.type_kind == LITERAL_INT)
+ {
+ temp_literal_type = type_new(TYPE_INT);
+ }
+ else if (init->literal.type_kind == LITERAL_FLOAT)
+ {
+ temp_literal_type = type_new(TYPE_FLOAT);
+ }
+ else if (init->literal.type_kind == LITERAL_STRING)
+ {
+ temp_literal_type = type_new(TYPE_STRING);
+ }
+ else if (init->literal.type_kind == LITERAL_CHAR)
+ {
+ temp_literal_type = type_new(TYPE_CHAR);
+ }
+ t = temp_literal_type;
+ }
+
+ // Special case for literals: if implicit conversion works
+ if (t && !type_eq(type_obj, t))
+ {
+ // Allow integer compatibility if types are roughly ints (lax check in type_eq handles
+ // most, but let's be safe)
+ if (!check_opaque_alias_compat(ctx, type_obj, t))
+ {
+ char *expected = type_to_string(type_obj);
+ char *got = type_to_string(t);
+ zpanic_at(init->token, "Type validation failed. Expected '%s', but got '%s'",
+ expected, got);
+ free(expected);
+ free(got);
+ }
+ }
+
+ if (temp_literal_type)
+ {
+ free(temp_literal_type); // Simple free, shallow
+ }
+ }
+
// NEW: Capture Const Integer Values
if (init && init->type == NODE_EXPR_LITERAL && init->literal.type_kind == LITERAL_INT)
{
@@ -839,7 +898,7 @@ ASTNode *parse_def(ParserContext *ctx, Lexer *l)
return o;
}
-ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l)
+ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l, int is_opaque)
{
lexer_next(l); // consume 'type' or 'alias'
Token n = lexer_next(l);
@@ -859,8 +918,11 @@ ASTNode *parse_type_alias(ParserContext *ctx, Lexer *l)
strncpy(node->type_alias.alias, n.start, n.len);
node->type_alias.alias[n.len] = 0;
node->type_alias.original_type = o;
+ node->type_alias.is_opaque = is_opaque;
+ node->type_alias.defined_in_file = g_current_filename ? xstrdup(g_current_filename) : NULL;
- register_type_alias(ctx, node->type_alias.alias, o);
+ register_type_alias(ctx, node->type_alias.alias, o, is_opaque,
+ node->type_alias.defined_in_file);
return node;
}
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index df2dcf6..7c53d96 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -1,3 +1,43 @@
+#include "../codegen/codegen.h"
+
+int check_opaque_alias_compat(ParserContext *ctx, Type *a, Type *b)
+{
+ if (!a || !b)
+ {
+ return 0;
+ }
+
+ int a_is_opaque = (a->kind == TYPE_ALIAS && a->alias.is_opaque_alias);
+ int b_is_opaque = (b->kind == TYPE_ALIAS && b->alias.is_opaque_alias);
+
+ if (!a_is_opaque && !b_is_opaque)
+ {
+ return 1;
+ }
+
+ if (a_is_opaque)
+ {
+ if (a->alias.alias_defined_in_file && g_current_filename &&
+ strcmp(a->alias.alias_defined_in_file, g_current_filename) == 0)
+ {
+ return check_opaque_alias_compat(ctx, a->inner, b);
+ }
+ return 0;
+ }
+
+ if (b_is_opaque)
+ {
+ if (b->alias.alias_defined_in_file && g_current_filename &&
+ strcmp(b->alias.alias_defined_in_file, g_current_filename) == 0)
+ {
+ return check_opaque_alias_compat(ctx, a, b->inner);
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
#include "../zen/zen_facts.h"
#include "parser.h"
#include <ctype.h>
@@ -108,6 +148,8 @@ int is_type_copy(ParserContext *ctx, Type *t)
case TYPE_POINTER: // Pointers are Copy
case TYPE_FUNCTION:
case TYPE_ENUM: // Enums are integers
+ case TYPE_BITINT:
+ case TYPE_UBITINT:
return 1;
case TYPE_STRUCT:
@@ -116,6 +158,14 @@ int is_type_copy(ParserContext *ctx, Type *t)
{
return 1;
}
+
+ // If the struct is NOT defined (opaque/C type) and does NOT implement Drop,
+ // treat it as Copy (C behavior).
+ if (!find_struct_def(ctx, t->name) && !check_impl(ctx, "Drop", t->name))
+ {
+ return 1;
+ }
+
return 0;
case TYPE_ARRAY:
@@ -124,6 +174,13 @@ int is_type_copy(ParserContext *ctx, Type *t)
// but if it's a value assignment, C doesn't support it anyway unless wrapped in struct.
return 0;
+ case TYPE_ALIAS:
+ if (t->alias.is_opaque_alias)
+ {
+ return 1;
+ }
+ return is_type_copy(ctx, t->inner);
+
default:
return 1;
}
@@ -935,6 +992,17 @@ static ASTNode *create_fstring_block(ParserContext *ctx, const char *content)
free(txt);
}
+ // Handle escape {{
+ if (brace[1] == '{')
+ {
+ ASTNode *cat = ast_create(NODE_RAW_STMT);
+ cat->raw_stmt.content = xstrdup("strcat(_b, \"{\");");
+ tail->next = cat;
+ tail = cat;
+ cur = brace + 2;
+ continue;
+ }
+
char *end_brace = strchr(brace, '}');
if (!end_brace)
{
@@ -1072,6 +1140,7 @@ static ASTNode *create_fstring_block(ParserContext *ctx, const char *content)
static ASTNode *parse_int_literal(Token t)
{
ASTNode *node = ast_create(NODE_EXPR_LITERAL);
+ node->token = t;
node->literal.type_kind = LITERAL_INT;
node->type_info = type_new(TYPE_INT);
char *s = token_strdup(t);
@@ -1093,6 +1162,7 @@ static ASTNode *parse_int_literal(Token t)
static ASTNode *parse_float_literal(Token t)
{
ASTNode *node = ast_create(NODE_EXPR_LITERAL);
+ node->token = t;
node->literal.type_kind = LITERAL_FLOAT;
node->literal.float_val = atof(t.start);
node->type_info = type_new(TYPE_F64);
@@ -1100,9 +1170,32 @@ static ASTNode *parse_float_literal(Token t)
}
// Parse string literal
-static ASTNode *parse_string_literal(Token t)
+static ASTNode *parse_string_literal(ParserContext *ctx, Token t)
{
+ // Check for implicit interpolation
+ int has_interpolation = 0;
+ for (int i = 1; i < t.len - 1; i++)
+ {
+ if (t.start[i] == '{')
+ {
+ has_interpolation = 1;
+ break;
+ }
+ }
+
+ if (has_interpolation)
+ {
+
+ char *inner = xmalloc(t.len);
+ strncpy(inner, t.start + 1, t.len - 2);
+ inner[t.len - 2] = 0;
+ ASTNode *node = create_fstring_block(ctx, inner);
+ free(inner);
+ return node;
+ }
+
ASTNode *node = ast_create(NODE_EXPR_LITERAL);
+ node->token = t;
node->literal.type_kind = LITERAL_STRING;
node->literal.string_val = xmalloc(t.len);
strncpy(node->literal.string_val, t.start + 1, t.len - 2);
@@ -1126,6 +1219,7 @@ static ASTNode *parse_fstring_literal(ParserContext *ctx, Token t)
static ASTNode *parse_char_literal(Token t)
{
ASTNode *node = ast_create(NODE_EXPR_LITERAL);
+ node->token = t;
node->literal.type_kind = LITERAL_CHAR;
node->literal.string_val = token_strdup(t);
node->type_info = type_new(TYPE_I8);
@@ -1276,7 +1370,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
else if (t.type == TOK_STRING)
{
- node = parse_string_literal(t);
+ node = parse_string_literal(ctx, t);
}
else if (t.type == TOK_FSTRING)
{
@@ -2018,6 +2112,20 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
sprintf(prefixed, "%s_%s", ctx->current_module_prefix, acc);
struct_name = prefixed;
}
+
+ // Opaque Struct Check
+ ASTNode *def = find_struct_def(ctx, struct_name);
+ if (def && def->type == NODE_STRUCT && def->strct.is_opaque)
+ {
+ if (!def->strct.defined_in_file ||
+ (g_current_filename &&
+ strcmp(def->strct.defined_in_file, g_current_filename) != 0))
+ {
+ zpanic_at(lexer_peek(l),
+ "Cannot initialize opaque struct '%s' outside its module",
+ struct_name);
+ }
+ }
lexer_next(l);
node = ast_create(NODE_EXPR_STRUCT_INIT);
node->struct_init.struct_name = struct_name;
@@ -3592,7 +3700,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
else if (t->kind == TYPE_STRING)
{
- strcat(fmt, "%s");
+ strcat(fmt, "%ms");
}
else if (t->kind == TYPE_CHAR || t->kind == TYPE_I8 || t->kind == TYPE_U8 ||
t->kind == TYPE_BYTE)
@@ -4012,6 +4120,30 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
node->member.field = token_strdup(field);
node->member.is_pointer_access = 1;
+ // Opaque Check
+ int is_ptr_dummy = 0;
+ char *alloc_name = NULL;
+ char *sname =
+ resolve_struct_name_from_type(ctx, lhs->type_info, &is_ptr_dummy, &alloc_name);
+ if (sname)
+ {
+ ASTNode *def = find_struct_def(ctx, sname);
+ if (def && def->type == NODE_STRUCT && def->strct.is_opaque)
+ {
+ if (!def->strct.defined_in_file ||
+ (g_current_filename &&
+ strcmp(def->strct.defined_in_file, g_current_filename) != 0))
+ {
+ zpanic_at(field, "Cannot access private field '%s' of opaque struct '%s'",
+ node->member.field, sname);
+ }
+ }
+ if (alloc_name)
+ {
+ free(alloc_name);
+ }
+ }
+
node->type_info = get_field_type(ctx, lhs->type_info, node->member.field);
if (node->type_info)
{
@@ -4041,6 +4173,30 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
node->member.field = token_strdup(field);
node->member.is_pointer_access = 2;
+ // Opaque Check
+ int is_ptr_dummy = 0;
+ char *alloc_name = NULL;
+ char *sname =
+ resolve_struct_name_from_type(ctx, lhs->type_info, &is_ptr_dummy, &alloc_name);
+ if (sname)
+ {
+ ASTNode *def = find_struct_def(ctx, sname);
+ if (def && def->type == NODE_STRUCT && def->strct.is_opaque)
+ {
+ if (!def->strct.defined_in_file ||
+ (g_current_filename &&
+ strcmp(def->strct.defined_in_file, g_current_filename) != 0))
+ {
+ zpanic_at(field, "Cannot access private field '%s' of opaque struct '%s'",
+ node->member.field, sname);
+ }
+ }
+ if (alloc_name)
+ {
+ free(alloc_name);
+ }
+ }
+
node->type_info = get_field_type(ctx, lhs->type_info, node->member.field);
if (node->type_info)
{
@@ -4620,6 +4776,30 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
node->member.field = token_strdup(field);
node->member.is_pointer_access = 0;
+ // Opaque Check
+ int is_ptr_dummy = 0;
+ char *alloc_name = NULL;
+ char *sname =
+ resolve_struct_name_from_type(ctx, lhs->type_info, &is_ptr_dummy, &alloc_name);
+ if (sname)
+ {
+ ASTNode *def = find_struct_def(ctx, sname);
+ if (def && def->type == NODE_STRUCT && def->strct.is_opaque)
+ {
+ if (!def->strct.defined_in_file ||
+ (g_current_filename &&
+ strcmp(def->strct.defined_in_file, g_current_filename) != 0))
+ {
+ zpanic_at(field, "Cannot access private field '%s' of opaque struct '%s'",
+ node->member.field, sname);
+ }
+ }
+ if (alloc_name)
+ {
+ free(alloc_name);
+ }
+ }
+
node->member.field = token_strdup(field);
node->member.is_pointer_access = 0;
@@ -5241,6 +5421,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
// This gives a warning as "unused" but it's needed for the rewrite.
char *r_name =
resolve_struct_name_from_type(ctx, rhs->type_info, &is_rhs_ptr, &r_alloc);
+ (void)r_name;
if (r_alloc)
{
free(r_alloc);
@@ -5463,7 +5644,17 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
char *t1 = type_to_string(lhs->type_info);
char *t2 = type_to_string(rhs->type_info);
// Skip type check if either operand is void* (escape hatch type)
+ // or if either operand is a generic type parameter (T, K, V, etc.)
int skip_check = (strcmp(t1, "void*") == 0 || strcmp(t2, "void*") == 0);
+ if (lhs->type_info->kind == TYPE_GENERIC || rhs->type_info->kind == TYPE_GENERIC)
+ {
+ skip_check = 1;
+ }
+ // Also check if type name is a single uppercase letter (common generic param)
+ if ((strlen(t1) == 1 && isupper(t1[0])) || (strlen(t2) == 1 && isupper(t2[0])))
+ {
+ skip_check = 1;
+ }
// Allow comparing pointers/strings with integer literal 0 (NULL)
if (!skip_check)
@@ -5507,7 +5698,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
else
{
- if (type_eq(lhs->type_info, rhs->type_info))
+ if (type_eq(lhs->type_info, rhs->type_info) ||
+ check_opaque_alias_compat(ctx, lhs->type_info, rhs->type_info))
{
bin->type_info = lhs->type_info;
}
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index ab5b89c..0677cf5 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -14,6 +14,118 @@
char *curr_func_ret = NULL;
char *run_comptime_block(ParserContext *ctx, Lexer *l);
+extern char *g_current_filename;
+
+/**
+ * @brief Auto-imports std/slice.zc if not already imported.
+ *
+ * This is called when array iteration is detected in for-in loops,
+ * to ensure the Slice<T>, SliceIter<T>, and Option<T> templates are available.
+ */
+static void auto_import_std_slice(ParserContext *ctx)
+{
+ // Check if already imported via templates
+ GenericTemplate *t = ctx->templates;
+ while (t)
+ {
+ if (strcmp(t->name, "Slice") == 0)
+ {
+ return; // Already have the Slice template
+ }
+ t = t->next;
+ }
+
+ // Try to find and import std/slice.zc
+ static const char *std_paths[] = {"std/slice.zc", "./std/slice.zc", NULL};
+ static const char *system_paths[] = {"/usr/local/share/zenc", "/usr/share/zenc", NULL};
+
+ char resolved_path[1024];
+ int found = 0;
+
+ // First, try relative to current file
+ if (g_current_filename)
+ {
+ char *current_dir = xstrdup(g_current_filename);
+ char *last_slash = strrchr(current_dir, '/');
+ if (last_slash)
+ {
+ *last_slash = 0;
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/slice.zc", current_dir);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ free(current_dir);
+ }
+
+ // Try relative paths
+ if (!found)
+ {
+ for (int i = 0; std_paths[i] && !found; i++)
+ {
+ if (access(std_paths[i], R_OK) == 0)
+ {
+ strncpy(resolved_path, std_paths[i], sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ found = 1;
+ }
+ }
+ }
+
+ // Try system paths
+ if (!found)
+ {
+ for (int i = 0; system_paths[i] && !found; i++)
+ {
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/slice.zc", system_paths[i]);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return; // Could not find std/slice.zc, instantiate_generic will error
+ }
+
+ // Canonicalize path
+ char *real_fn = realpath(resolved_path, NULL);
+ if (real_fn)
+ {
+ strncpy(resolved_path, real_fn, sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ free(real_fn);
+ }
+
+ // Check if already imported
+ if (is_file_imported(ctx, resolved_path))
+ {
+ return;
+ }
+ mark_file_imported(ctx, resolved_path);
+
+ // Load and parse the file
+ char *src = load_file(resolved_path);
+ if (!src)
+ {
+ return; // Could not load file
+ }
+
+ Lexer i;
+ lexer_init(&i, src);
+
+ // Save and restore filename context
+ char *saved_fn = g_current_filename;
+ g_current_filename = resolved_path;
+
+ // Parse the slice module contents
+ parse_program_nodes(ctx, &i);
+
+ g_current_filename = saved_fn;
+}
static void check_assignment_condition(ASTNode *cond)
{
@@ -462,13 +574,7 @@ ASTNode *parse_defer(ParserContext *ctx, Lexer *l)
}
else
{
- s = ast_create(NODE_RAW_STMT);
- char *raw_content = consume_and_rewrite(ctx, l);
- // consume_and_rewrite strips the semicolon, so we must add it back for proper C generation
- char *safe_content = xmalloc(strlen(raw_content) + 2);
- sprintf(safe_content, "%s;", raw_content);
- free(raw_content);
- s->raw_stmt.content = safe_content;
+ s = parse_statement(ctx, l);
}
ctx->in_defer_block = prev_in_defer;
@@ -1139,6 +1245,7 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *obj_expr = start_expr;
char *iter_method = "iterator";
+ ASTNode *slice_decl = NULL; // Track if we need to add a slice declaration
// Check for reference iteration: for x in &vec
if (obj_expr->type == NODE_EXPR_UNARY && obj_expr->unary.op &&
@@ -1148,6 +1255,80 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
iter_method = "iter_ref";
}
+ // Check for array iteration: wrap with Slice<T>::from_array
+ if (obj_expr->type_info && obj_expr->type_info->kind == TYPE_ARRAY &&
+ obj_expr->type_info->array_size > 0)
+ {
+ // Create a var decl for the slice
+ slice_decl = ast_create(NODE_VAR_DECL);
+ slice_decl->var_decl.name = xstrdup("__zc_arr_slice");
+
+ // Build type string: Slice<elem_type>
+ char *elem_type_str = type_to_string(obj_expr->type_info->inner);
+ char slice_type[256];
+ sprintf(slice_type, "Slice<%s>", elem_type_str);
+ slice_decl->var_decl.type_str = xstrdup(slice_type);
+
+ ASTNode *from_array_call = ast_create(NODE_EXPR_CALL);
+ ASTNode *static_method = ast_create(NODE_EXPR_VAR);
+
+ // The function name for static methods is Type::method format
+ char func_name[512];
+ snprintf(func_name, 511, "%s::from_array", slice_type);
+ static_method->var_ref.name = xstrdup(func_name);
+
+ from_array_call->call.callee = static_method;
+
+ // Create arguments
+ ASTNode *arr_addr = ast_create(NODE_EXPR_UNARY);
+ arr_addr->unary.op = xstrdup("&");
+ arr_addr->unary.operand = obj_expr;
+
+ ASTNode *arr_cast = ast_create(NODE_EXPR_CAST);
+ char cast_type[256];
+ sprintf(cast_type, "%s*", elem_type_str);
+ arr_cast->cast.target_type = xstrdup(cast_type);
+ arr_cast->cast.expr = arr_addr;
+
+ ASTNode *size_arg = ast_create(NODE_EXPR_LITERAL);
+ size_arg->literal.type_kind = LITERAL_INT;
+ size_arg->literal.int_val = obj_expr->type_info->array_size;
+ char size_buf[32];
+ sprintf(size_buf, "%d", obj_expr->type_info->array_size);
+ size_arg->literal.string_val = xstrdup(size_buf);
+
+ arr_cast->next = size_arg;
+ from_array_call->call.args = arr_cast;
+ from_array_call->call.arg_count = 2;
+
+ slice_decl->var_decl.init_expr = from_array_call;
+
+ // Manually trigger generic instantiation for Slice<T>
+ // This ensures that Slice_int, Slice_float, etc. structures are generated
+ // First, ensure std/slice.zc is imported (auto-import if needed)
+ auto_import_std_slice(ctx);
+ Token dummy_tok = {0};
+ instantiate_generic(ctx, "Slice", elem_type_str, elem_type_str, dummy_tok);
+
+ // Instantiate SliceIter and Option too for the loop logic
+ char iter_type[256];
+ sprintf(iter_type, "SliceIter<%s>", elem_type_str);
+ instantiate_generic(ctx, "SliceIter", elem_type_str, elem_type_str, dummy_tok);
+
+ char option_type[256];
+ sprintf(option_type, "Option<%s>", elem_type_str);
+ instantiate_generic(ctx, "Option", elem_type_str, elem_type_str, dummy_tok);
+
+ // Replace obj_expr with a reference to the slice variable
+ ASTNode *slice_ref = ast_create(NODE_EXPR_VAR);
+ slice_ref->var_ref.name = xstrdup("__zc_arr_slice");
+ slice_ref->resolved_type =
+ xstrdup(slice_type); // Explicitly set type for codegen
+ obj_expr = slice_ref;
+
+ free(elem_type_str);
+ }
+
// var __it = obj.iterator();
ASTNode *it_decl = ast_create(NODE_VAR_DECL);
it_decl->var_decl.name = xstrdup("__it");
@@ -1188,6 +1369,34 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
stmts_tail = node; \
}
+ char *iter_type_ptr = NULL;
+ char *option_type_ptr = NULL;
+
+ if (slice_decl)
+ {
+ char *slice_t = slice_decl->var_decl.type_str;
+ char *start = strchr(slice_t, '<');
+ if (start)
+ {
+ char *end = strrchr(slice_t, '>');
+ if (end)
+ {
+ int len = end - start - 1;
+ char *elem = xmalloc(len + 1);
+ strncpy(elem, start + 1, len);
+ elem[len] = 0;
+
+ iter_type_ptr = xmalloc(256);
+ sprintf(iter_type_ptr, "SliceIter<%s>", elem);
+
+ option_type_ptr = xmalloc(256);
+ sprintf(option_type_ptr, "Option<%s>", elem);
+
+ free(elem);
+ }
+ }
+ }
+
// var __opt = __it.next();
ASTNode *opt_decl = ast_create(NODE_VAR_DECL);
opt_decl->var_decl.name = xstrdup("__opt");
@@ -1198,6 +1407,10 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *memb_next = ast_create(NODE_EXPR_MEMBER);
ASTNode *it_ref = ast_create(NODE_EXPR_VAR);
it_ref->var_ref.name = xstrdup("__it");
+ if (iter_type_ptr)
+ {
+ it_ref->resolved_type = xstrdup(iter_type_ptr);
+ }
memb_next->member.target = it_ref;
memb_next->member.field = xstrdup("next");
call_next->call.callee = memb_next;
@@ -1210,15 +1423,22 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *memb_is_none = ast_create(NODE_EXPR_MEMBER);
ASTNode *opt_ref1 = ast_create(NODE_EXPR_VAR);
opt_ref1->var_ref.name = xstrdup("__opt");
+ if (option_type_ptr)
+ {
+ opt_ref1->resolved_type = xstrdup(option_type_ptr);
+ }
memb_is_none->member.target = opt_ref1;
memb_is_none->member.field = xstrdup("is_none");
call_is_none->call.callee = memb_is_none;
+ call_is_none->call.args = NULL;
+ call_is_none->call.arg_count = 0;
- ASTNode *break_stmt = ast_create(NODE_BREAK);
-
+ // if (__opt.is_none()) break;
ASTNode *if_break = ast_create(NODE_IF);
if_break->if_stmt.condition = call_is_none;
+ ASTNode *break_stmt = ast_create(NODE_BREAK);
if_break->if_stmt.then_body = break_stmt;
+ if_break->if_stmt.else_body = NULL;
APPEND_STMT(if_break);
// var <user_var> = __opt.unwrap();
@@ -1231,25 +1451,28 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
ASTNode *memb_unwrap = ast_create(NODE_EXPR_MEMBER);
ASTNode *opt_ref2 = ast_create(NODE_EXPR_VAR);
opt_ref2->var_ref.name = xstrdup("__opt");
+ if (option_type_ptr)
+ {
+ opt_ref2->resolved_type = xstrdup(option_type_ptr);
+ }
memb_unwrap->member.target = opt_ref2;
memb_unwrap->member.field = xstrdup("unwrap");
call_unwrap->call.callee = memb_unwrap;
+ call_unwrap->call.args = NULL;
+ call_unwrap->call.arg_count = 0;
user_var_decl->var_decl.init_expr = call_unwrap;
APPEND_STMT(user_var_decl);
- // User Body
+ // User body statements
enter_scope(ctx);
add_symbol(ctx, var_name, NULL, NULL);
- ASTNode *user_body_node;
- if (lexer_peek(l).type == TOK_LBRACE)
+ // Body block
+ ASTNode *stmt = parse_statement(ctx, l);
+ ASTNode *user_body_node = stmt;
+ if (stmt && stmt->type != NODE_BLOCK)
{
- user_body_node = parse_block(ctx, l);
- }
- else
- {
- ASTNode *stmt = parse_statement(ctx, l);
ASTNode *blk = ast_create(NODE_BLOCK);
blk->block.statements = stmt;
user_body_node = blk;
@@ -1262,10 +1485,21 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l)
loop_body->block.statements = stmts_head;
while_loop->while_stmt.body = loop_body;
- // Wrap entire thing in a block to scope _it
+ // Wrap entire thing in a block to scope __it (and __zc_arr_slice if present)
ASTNode *outer_block = ast_create(NODE_BLOCK);
- it_decl->next = while_loop;
- outer_block->block.statements = it_decl;
+ if (slice_decl)
+ {
+ // Chain: slice_decl -> it_decl -> while_loop
+ slice_decl->next = it_decl;
+ it_decl->next = while_loop;
+ outer_block->block.statements = slice_decl;
+ }
+ else
+ {
+ // Chain: it_decl -> while_loop
+ it_decl->next = while_loop;
+ outer_block->block.statements = it_decl;
+ }
return outer_block;
}
@@ -1877,7 +2111,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
lexer_next(&lookahead);
TokenType next_type = lexer_peek(&lookahead).type;
- if (next_type == TOK_SEMICOLON || next_type == TOK_DOTDOT)
+ if (next_type == TOK_SEMICOLON || next_type == TOK_DOTDOT || next_type == TOK_RBRACE)
{
Token t = lexer_next(l); // consume string
@@ -1894,8 +2128,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
inner[t.len - 2] = 0;
}
- // ; means println (end of line), .. means print (continuation)
- int is_ln = (next_type == TOK_SEMICOLON);
+ int is_ln = (next_type == TOK_SEMICOLON || next_type == TOK_RBRACE);
char **used_syms = NULL;
int used_count = 0;
char *code =
@@ -1913,6 +2146,7 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l)
lexer_next(l); // consume optional ;
}
}
+ // If TOK_RBRACE, do not consume it, so parse_block can see it and terminate loop.
ASTNode *n = ast_create(NODE_RAW_STMT);
// Append semicolon to Statement Expression to make it a valid statement
@@ -3185,7 +3419,7 @@ char *run_comptime_block(ParserContext *ctx, Lexer *l)
ASTNode *fn = ref->node;
if (fn && fn->type == NODE_FUNCTION && fn->func.is_comptime)
{
- emit_func_signature(f, fn, NULL);
+ emit_func_signature(ctx, f, fn, NULL);
fprintf(f, ";\n");
codegen_node_single(ctx, fn, f);
}
diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c
index 84450ba..e53b56c 100644
--- a/src/parser/parser_struct.c
+++ b/src/parser/parser_struct.c
@@ -12,6 +12,114 @@
#include "zprep_plugin.h"
#include "../codegen/codegen.h"
+extern char *g_current_filename;
+
+/**
+ * @brief Auto-imports std/mem.zc if not already imported.
+ *
+ * This is called when the Drop trait is used (impl Drop for X).
+ */
+static void auto_import_std_mem(ParserContext *ctx)
+{
+ // Check if Drop trait is already registered (means mem.zc was imported)
+ if (check_impl(ctx, "Drop", "__trait_marker__"))
+ {
+ // Check_impl returns 0 if not found, but we need a different check
+ // Let's check if we can find any indicator that mem.zc was loaded
+ }
+
+ // Try to find and import std/mem.zc
+ static const char *std_paths[] = {"std/mem.zc", "./std/mem.zc", NULL};
+ static const char *system_paths[] = {"/usr/local/share/zenc", "/usr/share/zenc", NULL};
+
+ char resolved_path[1024];
+ int found = 0;
+
+ // First, try relative to current file
+ if (g_current_filename)
+ {
+ char *current_dir = xstrdup(g_current_filename);
+ char *last_slash = strrchr(current_dir, '/');
+ if (last_slash)
+ {
+ *last_slash = 0;
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/mem.zc", current_dir);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ free(current_dir);
+ }
+
+ // Try relative paths
+ if (!found)
+ {
+ for (int i = 0; std_paths[i] && !found; i++)
+ {
+ if (access(std_paths[i], R_OK) == 0)
+ {
+ strncpy(resolved_path, std_paths[i], sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ found = 1;
+ }
+ }
+ }
+
+ // Try system paths
+ if (!found)
+ {
+ for (int i = 0; system_paths[i] && !found; i++)
+ {
+ snprintf(resolved_path, sizeof(resolved_path), "%s/std/mem.zc", system_paths[i]);
+ if (access(resolved_path, R_OK) == 0)
+ {
+ found = 1;
+ }
+ }
+ }
+
+ if (!found)
+ {
+ return; // Could not find std/mem.zc
+ }
+
+ // Canonicalize path
+ char *real_fn = realpath(resolved_path, NULL);
+ if (real_fn)
+ {
+ strncpy(resolved_path, real_fn, sizeof(resolved_path) - 1);
+ resolved_path[sizeof(resolved_path) - 1] = '\0';
+ free(real_fn);
+ }
+
+ // Check if already imported
+ if (is_file_imported(ctx, resolved_path))
+ {
+ return;
+ }
+ mark_file_imported(ctx, resolved_path);
+
+ // Load and parse the file
+ char *src = load_file(resolved_path);
+ if (!src)
+ {
+ return; // Could not load file
+ }
+
+ Lexer i;
+ lexer_init(&i, src);
+
+ // Save and restore filename context
+ char *saved_fn = g_current_filename;
+ g_current_filename = resolved_path;
+
+ // Parse the mem module contents
+ parse_program_nodes(ctx, &i);
+
+ g_current_filename = saved_fn;
+}
+
// Trait Parsing
ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
{
@@ -100,7 +208,7 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
char **param_names = NULL;
int is_varargs = 0;
char *args = parse_and_convert_args(ctx, l, &defaults, &arg_count, &arg_types, &param_names,
- &is_varargs);
+ &is_varargs, NULL);
char *ret = xstrdup("void");
if (lexer_peek(l).type == TOK_ARROW)
@@ -149,6 +257,7 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
}
register_trait(name);
+ add_to_global_list(ctx, n_node); // Track for codegen (VTable emission)
return n_node;
}
@@ -206,6 +315,12 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
register_generic(ctx, target_gen_param);
}
+ // Auto-import std/mem.zc if implementing Drop, Copy, or Clone traits
+ if (strcmp(name1, "Drop") == 0 || strcmp(name1, "Copy") == 0 || strcmp(name1, "Clone") == 0)
+ {
+ auto_import_std_mem(ctx);
+ }
+
register_impl(ctx, name1, name2);
// RAII: Check for "Drop" trait implementation
@@ -652,7 +767,7 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
}
}
-ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
+ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union, int is_opaque)
{
lexer_next(l); // eat struct or union
@@ -705,6 +820,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
n->strct.is_union = is_union;
n->strct.fields = NULL;
n->strct.is_incomplete = 1;
+ n->strct.is_opaque = is_opaque;
return n;
}
@@ -800,10 +916,6 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
ASTNode *nf = ast_create(NODE_FIELD);
nf->field.name = xstrdup(f->field.name);
nf->field.type = xstrdup(f->field.type);
- // Copy type info? Ideally deep copy or ref
- // For now, we leave it NULL or shallow copy if needed, but mixins usually
- // aren't generic params themselves in the same way.
- // Let's shallow copy for safety if it exists.
nf->type_info = f->type_info;
if (!h)
@@ -829,7 +941,6 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
free(use_name);
continue;
}
- // ---------------------------------------
if (t.type == TOK_IDENT)
{
@@ -904,8 +1015,10 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
node->strct.generic_params = gps;
node->strct.generic_param_count = gp_count;
node->strct.is_union = is_union;
+ node->strct.is_opaque = is_opaque;
node->strct.used_structs = temp_used_structs;
node->strct.used_struct_count = temp_used_count;
+ node->strct.defined_in_file = g_current_filename ? xstrdup(g_current_filename) : NULL;
if (gp_count > 0)
{
@@ -1102,7 +1215,7 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
node->enm.name = ename;
node->enm.variants = h;
- node->enm.generic_param = gp; // 3. Store generic param
+ node->enm.generic_param = gp; // Store generic param
if (gp)
{
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index c01f061..49e961c 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -33,12 +33,25 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
char *name = token_strdup(t);
// Check for alias
- const char *aliased = find_type_alias(ctx, name);
- if (aliased)
+ TypeAlias *alias_node = find_type_alias_node(ctx, name);
+ if (alias_node)
{
free(name);
Lexer tmp;
- lexer_init(&tmp, aliased);
+ lexer_init(&tmp, alias_node->original_type);
+
+ if (alias_node->is_opaque)
+ {
+ Type *underlying = parse_type_formal(ctx, &tmp);
+ Type *wrapper = type_new(TYPE_ALIAS);
+ wrapper->name = xstrdup(alias_node->alias);
+ wrapper->inner = underlying;
+ wrapper->alias.is_opaque_alias = 1;
+ wrapper->alias.alias_defined_in_file =
+ alias_node->defined_in_file ? xstrdup(alias_node->defined_in_file) : NULL;
+ return wrapper;
+ }
+
return parse_type_formal(ctx, &tmp);
}
@@ -287,6 +300,90 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
free(name);
return type_new(TYPE_I16);
}
+
+ // C23 BitInt Support (i42, u256, etc.)
+ if ((name[0] == 'i' || name[0] == 'u') && isdigit(name[1]))
+ {
+ // Verify it is a purely numeric suffix
+ int valid = 1;
+ for (size_t k = 1; k < strlen(name); k++)
+ {
+ if (!isdigit(name[k]))
+ {
+ valid = 0;
+ break;
+ }
+ }
+ if (valid)
+ {
+ int width = atoi(name + 1);
+ if (width > 0)
+ {
+ // Map standard widths to standard types for standard ABI/C compabitility
+ if (name[0] == 'i')
+ {
+ if (width == 8)
+ {
+ free(name);
+ return type_new(TYPE_I8);
+ }
+ if (width == 16)
+ {
+ free(name);
+ return type_new(TYPE_I16);
+ }
+ if (width == 32)
+ {
+ free(name);
+ return type_new(TYPE_I32);
+ }
+ if (width == 64)
+ {
+ free(name);
+ return type_new(TYPE_I64);
+ }
+ if (width == 128)
+ {
+ free(name);
+ return type_new(TYPE_I128);
+ }
+ }
+ else
+ {
+ if (width == 8)
+ {
+ free(name);
+ return type_new(TYPE_U8);
+ }
+ if (width == 16)
+ {
+ free(name);
+ return type_new(TYPE_U16);
+ }
+ if (width == 32)
+ {
+ free(name);
+ return type_new(TYPE_U32);
+ }
+ if (width == 64)
+ {
+ free(name);
+ return type_new(TYPE_U64);
+ }
+ if (width == 128)
+ {
+ free(name);
+ return type_new(TYPE_U128);
+ }
+ }
+
+ Type *t = type_new(name[0] == 'u' ? TYPE_UBITINT : TYPE_BITINT);
+ t->array_size = width;
+ free(name);
+ return t;
+ }
+ }
+ }
if (strcmp(name, "u16") == 0)
{
free(name);
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 4e85500..28d2c11 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -402,23 +402,33 @@ void add_to_struct_list(ParserContext *ctx, ASTNode *node)
ctx->parsed_structs_list = r;
}
-void register_type_alias(ParserContext *ctx, const char *alias, const char *original)
+void register_type_alias(ParserContext *ctx, const char *alias, const char *original, int is_opaque,
+ const char *defined_in_file)
{
TypeAlias *ta = xmalloc(sizeof(TypeAlias));
ta->alias = xstrdup(alias);
ta->original_type = xstrdup(original);
+ ta->is_opaque = is_opaque;
+ ta->defined_in_file = defined_in_file ? xstrdup(defined_in_file) : NULL;
ta->next = ctx->type_aliases;
ctx->type_aliases = ta;
}
const char *find_type_alias(ParserContext *ctx, const char *alias)
{
+ TypeAlias *ta = find_type_alias_node(ctx, alias);
+ return ta ? ta->original_type : NULL;
+}
+
+TypeAlias *find_type_alias_node(ParserContext *ctx, const char *alias)
+{
TypeAlias *ta = ctx->type_aliases;
while (ta)
{
if (strcmp(ta->alias, alias) == 0)
{
- return ta->original_type;
+ // printf("DEBUG: Found Alias '%s' (Opaque: %d)\n", alias, ta->is_opaque);
+ return ta;
}
ta = ta->next;
}
@@ -3382,7 +3392,8 @@ char *consume_and_rewrite(ParserContext *ctx, Lexer *l)
}
char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out, int *count_out,
- Type ***types_out, char ***names_out, int *is_varargs_out)
+ Type ***types_out, char ***names_out, int *is_varargs_out,
+ char ***ctype_overrides_out)
{
Token t = lexer_next(l);
if (t.type != TOK_LPAREN)
@@ -3396,18 +3407,52 @@ char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out,
char **defaults = xmalloc(sizeof(char *) * 16);
Type **types = xmalloc(sizeof(Type *) * 16);
char **names = xmalloc(sizeof(char *) * 16);
+ char **ctype_overrides = xmalloc(sizeof(char *) * 16);
for (int i = 0; i < 16; i++)
{
defaults[i] = NULL;
types[i] = NULL;
names[i] = NULL;
+ ctype_overrides[i] = NULL;
}
if (lexer_peek(l).type != TOK_RPAREN)
{
while (1)
{
+ // Check for @ctype("...") before parameter
+ char *ctype_override = NULL;
+ if (lexer_peek(l).type == TOK_AT)
+ {
+ lexer_next(l); // eat @
+ Token attr = lexer_next(l);
+ if (attr.type == TOK_IDENT && attr.len == 5 && strncmp(attr.start, "ctype", 5) == 0)
+ {
+ if (lexer_next(l).type != TOK_LPAREN)
+ {
+ zpanic_at(lexer_peek(l), "Expected ( after @ctype");
+ }
+ Token ctype_tok = lexer_next(l);
+ if (ctype_tok.type != TOK_STRING)
+ {
+ zpanic_at(ctype_tok, "@ctype requires a string argument");
+ }
+ // Extract string content (strip quotes)
+ ctype_override = xmalloc(ctype_tok.len - 1);
+ strncpy(ctype_override, ctype_tok.start + 1, ctype_tok.len - 2);
+ ctype_override[ctype_tok.len - 2] = 0;
+ if (lexer_next(l).type != TOK_RPAREN)
+ {
+ zpanic_at(lexer_peek(l), "Expected ) after @ctype string");
+ }
+ }
+ else
+ {
+ zpanic_at(attr, "Unknown parameter attribute @%.*s", attr.len, attr.start);
+ }
+ }
+
Token t = lexer_next(l);
// Handle 'self'
if (t.type == TOK_IDENT && strncmp(t.start, "self", 4) == 0 && t.len == 4)
@@ -3460,6 +3505,7 @@ char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out,
types[count] = type_new_ptr(type_new(TYPE_VOID));
add_symbol(ctx, "self", "void*", types[count]);
}
+ ctype_overrides[count] = ctype_override;
count++;
}
else
@@ -3504,11 +3550,20 @@ char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out,
}
else
{
- strcat(buf, type_str);
+ // Use @ctype override if present
+ if (ctype_override)
+ {
+ strcat(buf, ctype_override);
+ }
+ else
+ {
+ strcat(buf, type_str);
+ }
strcat(buf, " ");
strcat(buf, name);
}
+ ctype_overrides[count] = ctype_override;
count++;
if (lexer_peek(l).type == TOK_OP && is_token(lexer_peek(l), "="))
@@ -3583,6 +3638,10 @@ char *parse_and_convert_args(ParserContext *ctx, Lexer *l, char ***defaults_out,
*count_out = count;
*types_out = types;
*names_out = names;
+ if (ctype_overrides_out)
+ {
+ *ctype_overrides_out = ctype_overrides;
+ }
return buf;
}
diff --git a/src/repl/repl.c b/src/repl/repl.c
index cb63293..b04b2c2 100644
--- a/src/repl/repl.c
+++ b/src/repl/repl.c
@@ -6,22 +6,977 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <ctype.h>
ASTNode *parse_program(ParserContext *ctx, Lexer *l);
static int is_header_line(const char *line)
{
- return (strncmp(line, "import ", 7) == 0 || strncmp(line, "include ", 8) == 0 ||
- strncmp(line, "#include", 8) == 0);
+ // Skip whitespace
+ while (*line && (*line == ' ' || *line == '\t'))
+ {
+ line++;
+ }
+ if (strncmp(line, "struct", 6) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "impl", 4) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "fn", 2) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "use", 3) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "include", 7) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "typedef", 7) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "enum", 4) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "const", 5) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "def", 3) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "#include", 8) == 0)
+ {
+ return 1;
+ }
+ if (strncmp(line, "import", 6) == 0)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void repl_error_callback(void *data, Token t, const char *msg)
+{
+ (void)data;
+ (void)t;
+ fprintf(stderr, "\033[1;31merror:\033[0m %s\n", msg);
+}
+
+static struct termios orig_termios;
+static int raw_mode_enabled = 0;
+
+static void disable_raw_mode()
+{
+ if (raw_mode_enabled)
+ {
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &orig_termios);
+ raw_mode_enabled = 0;
+ }
+}
+
+static void enable_raw_mode()
+{
+ if (!raw_mode_enabled)
+ {
+ tcgetattr(STDIN_FILENO, &orig_termios);
+ atexit(disable_raw_mode);
+ struct termios raw = orig_termios;
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ raw.c_oflag &= ~(OPOST);
+ raw.c_cflag |= (CS8);
+ raw.c_cc[VMIN] = 1;
+ raw.c_cc[VTIME] = 0;
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
+ raw_mode_enabled = 1;
+ }
+}
+
+static const char *KEYWORDS[] = {
+ "fn", "struct", "var", "let", "def", "const", "return", "if",
+ "else", "for", "while", "do", "switch", "case", "default", "break",
+ "continue", "typedef", "enum", "union", "sizeof", "typeof", "import", "include",
+ "defer", "guard", "match", "impl", "trait", "comptime", "asm", "plugin",
+ "true", "false", "null", "NULL", NULL};
+
+static const char *TYPES[] = {"void", "int", "char", "float", "double", "long",
+ "short", "unsigned", "signed", "bool", NULL};
+
+static int find_matching_brace(const char *buf, int pos)
+{
+ if (pos < 0 || pos >= (int)strlen(buf))
+ {
+ return -1;
+ }
+ char c = buf[pos];
+ int dir = 0;
+ char match = 0;
+ if (c == '{')
+ {
+ match = '}';
+ dir = 1;
+ }
+ else if (c == '(')
+ {
+ match = ')';
+ dir = 1;
+ }
+ else if (c == '[')
+ {
+ match = ']';
+ dir = 1;
+ }
+ else if (c == '}')
+ {
+ match = '{';
+ dir = -1;
+ }
+ else if (c == ')')
+ {
+ match = '(';
+ dir = -1;
+ }
+ else if (c == ']')
+ {
+ match = '[';
+ dir = -1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ int depth = 1;
+ int p = pos + dir;
+ int len = strlen(buf);
+ while (p >= 0 && p < len)
+ {
+ if (buf[p] == c)
+ {
+ depth++;
+ }
+ else if (buf[p] == match)
+ {
+ depth--;
+ if (depth == 0)
+ {
+ return p;
+ }
+ }
+ p += dir;
+ }
+ return -1;
+}
+
+// Calculate visible length of a string (ignoring ANSI codes)
+static int get_visible_length(const char *str)
+{
+ int len = 0;
+ int in_esc = 0;
+ while (*str)
+ {
+ if (*str == '\033')
+ {
+ in_esc = 1;
+ }
+ else if (in_esc)
+ {
+ if (*str == 'm' || *str == 'K') // End of SGR or EL
+ {
+ in_esc = 0;
+ }
+ if (isalpha(*str))
+ {
+ in_esc = 0; // Terminating char
+ }
+ }
+ else
+ {
+ len++;
+ }
+ str++;
+ }
+ return len;
+}
+
+// Simple syntax highlighter for the REPL
+static void repl_highlight(const char *buf, int cursor_pos);
+
+static int is_definition_of(const char *code, const char *name)
+{
+ Lexer l;
+ lexer_init(&l, code);
+ Token t = lexer_next(&l);
+ int is_header = 0;
+
+ if (t.type == TOK_UNION)
+ {
+ is_header = 1;
+ }
+ else if (t.type == TOK_IDENT)
+ {
+ if ((t.len == 2 && strncmp(t.start, "fn", 2) == 0) ||
+ (t.len == 6 && strncmp(t.start, "struct", 6) == 0) ||
+ (t.len == 4 && strncmp(t.start, "enum", 4) == 0) ||
+ (t.len == 7 && strncmp(t.start, "typedef", 7) == 0) ||
+ (t.len == 5 && strncmp(t.start, "const", 5) == 0))
+ {
+ is_header = 1;
+ }
+ }
+
+ if (is_header)
+ {
+ Token name_tok = lexer_next(&l);
+ if (name_tok.type == TOK_IDENT)
+ {
+ if (strlen(name) == (size_t)name_tok.len &&
+ strncmp(name, name_tok.start, name_tok.len) == 0)
+ {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void repl_highlight(const char *buf, int cursor_pos)
+{
+ const char *p = buf;
+
+ int match_pos = -1;
+ int brace_pos = -1;
+
+ // Check under cursor
+ if (find_matching_brace(buf, cursor_pos) != -1)
+ {
+ brace_pos = cursor_pos;
+ match_pos = find_matching_brace(buf, cursor_pos);
+ }
+ // Check before cursor (common behavior when typing)
+ else if (cursor_pos > 0 && find_matching_brace(buf, cursor_pos - 1) != -1)
+ {
+ brace_pos = cursor_pos - 1;
+ match_pos = find_matching_brace(buf, cursor_pos - 1);
+ }
+
+ while (*p)
+ {
+ long idx = p - buf;
+
+ // Highlight matching braces
+ if (idx == brace_pos || idx == match_pos)
+ {
+ printf("\033[1;44;37m"); // Bright White on Blue background
+ putchar(*p);
+ printf("\033[0m");
+ p++;
+ continue;
+ }
+
+ if (strncmp(p, "//", 2) == 0)
+ {
+ printf("\033[1;30m");
+ printf("%s", p);
+ printf("\033[0m");
+ break;
+ }
+ else if (*p == ':' && isalpha(p[1]))
+ {
+ printf("\033[1;35m");
+ while (*p && !isspace(*p))
+ {
+ putchar(*p);
+ p++;
+ }
+ printf("\033[0m");
+ }
+ else if (isdigit(*p))
+ {
+ printf("\033[1;35m");
+ while (isdigit(*p) || *p == '.' || *p == 'x' || *p == 'X')
+ {
+ putchar(*p);
+ p++;
+ }
+ printf("\033[0m");
+ }
+ else if (*p == '"' || *p == '\'')
+ {
+ char quote = *p;
+ printf("\033[1;32m");
+ putchar(*p);
+ p++;
+ while (*p && *p != quote)
+ {
+ if (*p == '\\' && p[1])
+ {
+ putchar(*p);
+ p++;
+ }
+ putchar(*p);
+ p++;
+ }
+ if (*p == quote)
+ {
+ putchar(*p);
+ p++;
+ }
+ printf("\033[0m");
+ }
+ else if (strchr(",;.", *p))
+ {
+ printf("\033[1;30m");
+ putchar(*p);
+ printf("\033[0m");
+ p++;
+ }
+ else if (strchr("{}[]()", *p))
+ {
+ printf("\033[0;36m");
+ putchar(*p);
+ printf("\033[0m");
+ p++;
+ }
+ else if (strchr("+-*/=<>!&|^~%", *p))
+ {
+ printf("\033[1;37m");
+ putchar(*p);
+ printf("\033[0m");
+ p++;
+ }
+ else if (isalpha(*p) || *p == '_')
+ {
+ const char *start = p;
+ while (isalnum(*p) || *p == '_')
+ {
+ p++;
+ }
+ int len = p - start;
+ char word[256];
+ if (len < 256)
+ {
+ strncpy(word, start, len);
+ word[len] = 0;
+
+ int is_keyword = 0;
+ for (int i = 0; KEYWORDS[i]; i++)
+ {
+ if (strcmp(word, KEYWORDS[i]) == 0)
+ {
+ is_keyword = 1;
+ break;
+ }
+ }
+
+ int is_type = 0;
+ if (!is_keyword)
+ {
+ for (int i = 0; TYPES[i]; i++)
+ {
+ if (strcmp(word, TYPES[i]) == 0)
+ {
+ is_type = 1;
+ break;
+ }
+ }
+ }
+
+ int is_func = 0;
+ if (!is_keyword && !is_type)
+ {
+ const char *peek = p;
+ while (*peek && isspace(*peek))
+ {
+ peek++;
+ }
+ if (*peek == '(')
+ {
+ is_func = 1;
+ }
+ }
+
+ int is_const = 0;
+ if (!is_keyword && !is_type && !is_func && len > 1)
+ {
+ int all_upper = 1;
+ int has_upper = 0;
+ for (int i = 0; word[i]; i++)
+ {
+ if (islower(word[i]))
+ {
+ all_upper = 0;
+ }
+ if (isupper(word[i]))
+ {
+ has_upper = 1;
+ }
+ }
+ if (all_upper && has_upper)
+ {
+ is_const = 1;
+ }
+ }
+
+ if (is_keyword)
+ {
+ printf("\033[1;36m");
+ }
+ else if (is_type)
+ {
+ printf("\033[1;33m");
+ }
+ else if (is_func)
+ {
+ printf("\033[1;34m");
+ }
+ else if (is_const)
+ {
+ printf("\033[1;31m");
+ }
+
+ printf("%s", word);
+ printf("\033[0m");
+ }
+ else
+ {
+ printf("%.*s", len, start);
+ }
+ }
+ else
+ {
+ putchar(*p);
+ p++;
+ }
+ }
+}
+
+static char *repl_complete(const char *buf, int pos)
+{
+ int start = pos;
+ while (start > 0 && (isalnum(buf[start - 1]) || buf[start - 1] == '_' ||
+ buf[start - 1] == ':' || buf[start - 1] == '!'))
+ {
+ start--;
+ }
+
+ int len = pos - start;
+ if (len == 0)
+ {
+ return NULL;
+ }
+
+ char prefix[256];
+ if (len >= 255)
+ {
+ return NULL;
+ }
+ strncpy(prefix, buf + start, len);
+ prefix[len] = 0;
+
+ char *match = NULL;
+ int match_count = 0;
+
+ for (int i = 0; KEYWORDS[i]; i++)
+ {
+ if (strncmp(KEYWORDS[i], prefix, len) == 0)
+ {
+ match = (char *)KEYWORDS[i];
+ match_count++;
+ }
+ }
+
+ static const char *COMMANDS[] = {
+ ":help", ":reset", ":imports", ":vars", ":funcs", ":structs", ":history", ":type",
+ ":time", ":c", ":doc", ":run", ":edit", ":save", ":load", ":watch",
+ ":unwatch", ":undo", ":delete", ":clear", ":quit", NULL};
+
+ if (prefix[0] == ':')
+ {
+ for (int i = 0; COMMANDS[i]; i++)
+ {
+ if (strncmp(COMMANDS[i], prefix, len) == 0)
+ {
+ match = (char *)COMMANDS[i];
+ match_count++;
+ }
+ }
+ }
+
+ if (match_count == 1)
+ {
+ return strdup(match + len);
+ }
+
+ return NULL;
+}
+
+static char *repl_readline(const char *prompt, char **history, int history_len, int indent_level)
+{
+ enable_raw_mode();
+
+ int buf_size = 1024;
+ char *buf = malloc(buf_size);
+ buf[0] = 0;
+ int len = 0;
+ int pos = 0;
+
+ if (indent_level > 0)
+ {
+ for (int i = 0; i < indent_level * 4; i++)
+ {
+ if (len >= buf_size - 1)
+ {
+ buf_size *= 2;
+ buf = realloc(buf, buf_size);
+ }
+ buf[len++] = ' ';
+ }
+ buf[len] = 0;
+ pos = len;
+ }
+
+ int history_idx = history_len;
+ char *saved_current_line = NULL;
+
+ int in_search_mode = 0;
+ char search_buf[256];
+ search_buf[0] = 0;
+ int search_match_idx = -1;
+
+ printf("\r\033[K%s", prompt);
+ repl_highlight(buf, pos);
+ fflush(stdout);
+
+ while (1)
+ {
+ char c;
+ if (read(STDIN_FILENO, &c, 1) != 1)
+ {
+ break;
+ }
+
+ if (c == '\x1b')
+ {
+ char seq[3];
+ if (read(STDIN_FILENO, &seq[0], 1) != 1)
+ {
+ continue;
+ }
+ if (read(STDIN_FILENO, &seq[1], 1) != 1)
+ {
+ continue;
+ }
+
+ if (seq[0] == '[')
+ {
+ if (seq[1] == 'A')
+ {
+ if (history_idx > 0)
+ {
+ if (history_idx == history_len)
+ {
+ if (saved_current_line)
+ {
+ free(saved_current_line);
+ }
+ saved_current_line = strdup(buf);
+ }
+ history_idx--;
+ if (history_idx >= 0 && history_idx < history_len)
+ {
+ free(buf);
+ buf = strdup(history[history_idx]);
+ buf_size = strlen(buf) + 1;
+ len = strlen(buf);
+ pos = len;
+ }
+ }
+ }
+ else if (seq[1] == 'B')
+ {
+ if (history_idx < history_len)
+ {
+ history_idx++;
+ free(buf);
+ if (history_idx == history_len)
+ {
+ if (saved_current_line)
+ {
+ buf = strdup(saved_current_line);
+ }
+ else
+ {
+ buf = strdup("");
+ }
+ }
+ else
+ {
+ buf = strdup(history[history_idx]);
+ }
+ buf_size = strlen(buf) + 1;
+ len = strlen(buf);
+ pos = len;
+ }
+ }
+ else if (seq[1] == 'C')
+ {
+ if (pos < len)
+ {
+ pos++;
+ }
+ }
+ else if (seq[1] == 'D')
+ {
+ if (pos > 0)
+ {
+ pos--;
+ }
+ }
+ else if (seq[1] == 'H')
+ {
+ pos = 0;
+ }
+ else if (seq[1] == 'F')
+ {
+ pos = len;
+ }
+ }
+ }
+ else if (c == 127 || c == 8)
+ {
+ if (pos > 0)
+ {
+ memmove(buf + pos - 1, buf + pos, len - pos + 1);
+ len--;
+ pos--;
+ }
+ }
+ else if (c == '\r' || c == '\n')
+ {
+ printf("\r\n");
+ break;
+ }
+ else if (c == 3)
+ {
+ printf("^C\r\n");
+ free(buf);
+ if (saved_current_line)
+ {
+ free(saved_current_line);
+ }
+ disable_raw_mode();
+ return strdup("");
+ }
+ else if (c == 4)
+ {
+ if (len == 0)
+ {
+ free(buf);
+ if (saved_current_line)
+ {
+ free(saved_current_line);
+ }
+ disable_raw_mode();
+ return NULL;
+ }
+ }
+ else if (c == '\t')
+ {
+ char *completion = repl_complete(buf, pos);
+ if (completion)
+ {
+ int clen = strlen(completion);
+ if (len + clen < buf_size - 1)
+ {
+ // Insert completion
+ memmove(buf + pos + clen, buf + pos, len - pos + 1);
+ memcpy(buf + pos, completion, clen);
+ len += clen;
+ pos += clen;
+ }
+ free(completion);
+ }
+ }
+ else if (c == 18)
+ {
+ if (!in_search_mode)
+ {
+ in_search_mode = 1;
+ search_buf[0] = 0;
+ search_match_idx = history_len;
+ }
+
+ int found = -1;
+ int start_idx = search_match_idx - 1;
+ if (start_idx >= history_len)
+ {
+ start_idx = history_len - 1;
+ }
+
+ for (int i = start_idx; i >= 0; i--)
+ {
+ if (strstr(history[i], search_buf))
+ {
+ found = i;
+ break;
+ }
+ }
+
+ if (found != -1)
+ {
+ search_match_idx = found;
+ free(buf);
+ buf = strdup(history[found]);
+ buf_size = strlen(buf) + 1;
+ len = strlen(buf);
+ pos = len;
+ history_idx = found; // Sync history navigation
+ }
+ }
+ else if (in_search_mode)
+ {
+ if (c == 127 || c == 8) // Backspace
+ {
+ int sl = strlen(search_buf);
+ if (sl > 0)
+ {
+ search_buf[sl - 1] = 0;
+ search_match_idx = history_len;
+ int found = -1;
+ for (int i = history_len - 1; i >= 0; i--)
+ {
+ if (strstr(history[i], search_buf))
+ {
+ found = i;
+ break;
+ }
+ }
+ if (found != -1)
+ {
+ search_match_idx = found;
+ free(buf);
+ buf = strdup(history[found]);
+ buf_size = strlen(buf) + 1;
+ len = strlen(buf);
+ pos = len;
+ history_idx = found;
+ }
+ }
+ }
+ else if (c == '\r' || c == '\n' || c == 27 || c == 7 ||
+ c == 3) // Enter/Esc/Ctrl+G/Ctrl+C
+ {
+ in_search_mode = 0;
+ if (c == 3)
+ {
+ // Abort
+ free(buf);
+ buf = strdup("");
+ len = 0;
+ pos = 0;
+ printf("^C\r\n");
+ return buf;
+ }
+ if (c == 7)
+ {
+ // Keep current match
+ }
+ else if (c == '\r' || c == '\n')
+ {
+ printf("\r\n");
+ break;
+ }
+ }
+ else if (!iscntrl(c))
+ {
+ int sl = strlen(search_buf);
+ if (sl < 255)
+ {
+ search_buf[sl] = c;
+ search_buf[sl + 1] = 0;
+
+ int found = -1;
+ for (int i = history_len - 1; i >= 0; i--)
+ {
+ if (strstr(history[i], search_buf))
+ {
+ found = i;
+ break;
+ }
+ }
+ if (found != -1)
+ {
+ search_match_idx = found;
+ free(buf);
+ buf = strdup(history[found]);
+ buf_size = strlen(buf) + 1;
+ len = strlen(buf);
+ pos = len;
+ history_idx = found;
+ }
+ }
+ }
+ }
+ else if (c == 1)
+ {
+ pos = 0;
+ }
+ else if (c == 5)
+ {
+ pos = len;
+ }
+ else if (c == 12)
+ {
+ printf("\033[2J\033[H");
+ }
+ else if (c == 21)
+ {
+ if (pos > 0)
+ {
+ memmove(buf, buf + pos, len - pos + 1);
+ len -= pos;
+ pos = 0;
+ }
+ }
+ else if (c == 11)
+ {
+ buf[pos] = 0;
+ len = pos;
+ }
+ else if (c == 14)
+ {
+ printf("^N\r\n");
+ free(buf);
+ if (saved_current_line)
+ {
+ free(saved_current_line);
+ }
+ disable_raw_mode();
+ return strdup(":reset");
+ }
+ else if (!iscntrl(c))
+ {
+ if (len >= buf_size - 1)
+ {
+ buf_size *= 2;
+ buf = realloc(buf, buf_size);
+ }
+ memmove(buf + pos + 1, buf + pos, len - pos + 1);
+ buf[pos] = c;
+ len++;
+ pos++;
+ }
+
+ if (in_search_mode)
+ {
+ printf("\r\033[K(reverse-i-search)`%s': %s", search_buf, buf);
+ }
+ else
+ {
+ printf("\r\033[K%s", prompt);
+ repl_highlight(buf, pos);
+ int prompt_len = get_visible_length(prompt);
+ if (pos + prompt_len > 0)
+ {
+ printf("\r\033[%dC", pos + prompt_len);
+ }
+ else
+ {
+ printf("\r");
+ }
+ }
+
+ fflush(stdout);
+ }
+
+ if (saved_current_line)
+ {
+ free(saved_current_line);
+ }
+ disable_raw_mode();
+
+ return buf;
+}
+
+static void repl_get_code(char **history, int len, char **out_global, char **out_main)
+{
+ size_t total_len = 0;
+ for (int i = 0; i < len; i++)
+ {
+ total_len += strlen(history[i]) + 2;
+ }
+
+ char *global_buf = malloc(total_len + 1);
+ char *main_buf = malloc(total_len + 1);
+ global_buf[0] = 0;
+ main_buf[0] = 0;
+
+ int brace_depth = 0;
+ int in_global = 0;
+
+ for (int i = 0; i < len; i++)
+ {
+ char *line = history[i];
+
+ if (brace_depth == 0)
+ {
+ if (is_header_line(line))
+ {
+ in_global = 1;
+ }
+ else
+ {
+ in_global = 0;
+ }
+ }
+
+ if (in_global)
+ {
+ strcat(global_buf, line);
+ strcat(global_buf, "\n");
+ }
+ else
+ {
+ strcat(main_buf, line);
+ strcat(main_buf, " ");
+ }
+
+ for (char *p = line; *p; p++)
+ {
+ if (*p == '{')
+ {
+ brace_depth++;
+ }
+ else if (*p == '}')
+ {
+ brace_depth--;
+ }
+ }
+ }
+
+ *out_global = global_buf;
+ *out_main = main_buf;
}
void run_repl(const char *self_path)
{
- printf("\033[1;36mZen C REPL (v0.1)\033[0m\n");
+ printf("\033[1;36mZen C REPL (%s)\033[0m\n", ZEN_VERSION);
printf("Type 'exit' or 'quit' to leave.\n");
printf("Type :help for commands.\n");
- // Dynamic history.
int history_cap = 64;
int history_len = 0;
char **history = xmalloc(history_cap * sizeof(char *));
@@ -69,7 +1024,6 @@ void run_repl(const char *self_path)
history_path[0] = 0;
}
- // Watch list.
char *watches[16];
int watches_len = 0;
for (int i = 0; i < 16; i++)
@@ -77,7 +1031,6 @@ void run_repl(const char *self_path)
watches[i] = NULL;
}
- // Load startup file (~/.zprep_init.zc) if exists
if (home)
{
char init_path[512];
@@ -128,21 +1081,39 @@ void run_repl(const char *self_path)
while (1)
{
- if (brace_depth > 0 || paren_depth > 0)
+ char cwd[1024];
+ char prompt_text[1280];
+ if (getcwd(cwd, sizeof(cwd)))
{
- printf("... ");
+ char *base = strrchr(cwd, '/');
+ if (base)
+ {
+ base++;
+ }
+ else
+ {
+ base = cwd;
+ }
+ snprintf(prompt_text, sizeof(prompt_text), "\033[1;32m%s >>>\033[0m ", base);
}
else
{
- printf("\033[1;32m>>>\033[0m ");
+ strcpy(prompt_text, "\033[1;32m>>>\033[0m ");
}
- if (!fgets(line_buf, sizeof(line_buf), stdin))
+ const char *prompt = (brace_depth > 0 || paren_depth > 0) ? "... " : prompt_text;
+ int indent = (brace_depth > 0) ? brace_depth : 0;
+ char *rline = repl_readline(prompt, history, history_len, indent);
+
+ if (!rline)
{
break;
}
+ strncpy(line_buf, rline, sizeof(line_buf) - 2);
+ line_buf[sizeof(line_buf) - 2] = 0;
+ strcat(line_buf, "\n");
+ free(rline);
- // Handle commands (only on fresh line).
if (NULL == input_buffer)
{
size_t len = strlen(line_buf);
@@ -162,8 +1133,13 @@ void run_repl(const char *self_path)
break;
}
- // Commands
- if (cmd_buf[0] == ':' || cmd_buf[0] == '!')
+ if (cmd_buf[0] == '!')
+ {
+ int ret = system(cmd_buf + 1);
+ printf("(exit code: %d)\n", ret);
+ continue;
+ }
+ if (cmd_buf[0] == ':')
{
if (0 == strcmp(cmd_buf, ":help"))
{
@@ -183,14 +1159,21 @@ void run_repl(const char *self_path)
printf(" :edit [n] Edit command n (default: last) in $EDITOR\n");
printf(" :save <f> Save session to file\n");
printf(" :load <f> Load file into session\n");
- printf(" :load <f> Load file into session\n");
- printf(" :watch <x> Watch expression output\n");
- printf(" :unwatch <n> Remove watch n\n");
printf(" :undo Remove last command\n");
printf(" :delete <n> Remove command at index n\n");
+ printf(" :watch <x> Watch expression output\n");
+ printf(" :unwatch <n> Remove watch n\n");
printf(" :clear Clear screen\n");
printf(" ! <cmd> Run shell command\n");
printf(" :quit Exit REPL\n");
+ printf("\nShortcuts:\n");
+ printf(" Up/Down History navigation\n");
+ printf(" Tab Completion\n");
+ printf(" Ctrl+A Go to start\n");
+ printf(" Ctrl+E Go to end\n");
+ printf(" Ctrl+L Clear screen\n");
+ printf(" Ctrl+U Clear line to start\n");
+ printf(" Ctrl+K Clear line to end\n");
continue;
}
else if (0 == strcmp(cmd_buf, ":reset"))
@@ -207,9 +1190,107 @@ void run_repl(const char *self_path)
{
break;
}
+ else if (0 == strncmp(cmd_buf, ":show ", 6))
+ {
+ char *name = cmd_buf + 6;
+ while (*name && isspace(*name))
+ {
+ name++;
+ }
+
+ int found = 0;
+ printf("Source definition for '%s':\n", name);
+
+ for (int i = history_len - 1; i >= 0; i--)
+ {
+ if (is_definition_of(history[i], name))
+ {
+ printf(" \033[90m// Found in history:\033[0m\n");
+ printf(" ");
+ repl_highlight(history[i], -1);
+ printf("\n");
+ found = 1;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ continue;
+ }
+
+ printf("Source definition for '%s':\n", name);
+
+ size_t show_code_size = 4096;
+ for (int i = 0; i < history_len; i++)
+ {
+ show_code_size += strlen(history[i]) + 2;
+ }
+ char *show_code = malloc(show_code_size);
+ strcpy(show_code, "");
+ for (int i = 0; i < history_len; i++)
+ {
+ strcat(show_code, history[i]);
+ strcat(show_code, "\n");
+ }
+
+ ParserContext ctx = {0};
+ ctx.is_repl = 1;
+ ctx.skip_preamble = 1;
+ ctx.is_fault_tolerant = 1;
+ ctx.on_error = repl_error_callback;
+ Lexer l;
+ lexer_init(&l, show_code);
+ ASTNode *nodes = parse_program(&ctx, &l);
+
+ ASTNode *search = nodes;
+ if (search && search->type == NODE_ROOT)
+ {
+ search = search->root.children;
+ }
+
+ for (ASTNode *n = search; n; n = n->next)
+ {
+ if (n->type == NODE_FUNCTION && 0 == strcmp(n->func.name, name))
+ {
+ printf(" fn %s(%s) -> %s\n", n->func.name,
+ n->func.args ? n->func.args : "",
+ n->func.ret_type ? n->func.ret_type : "void");
+ found = 1;
+ break;
+ }
+ else if (n->type == NODE_STRUCT && 0 == strcmp(n->strct.name, name))
+ {
+ printf(" struct %s {\n", n->strct.name);
+ for (ASTNode *field = n->strct.fields; field; field = field->next)
+ {
+ if (field->type == NODE_FIELD)
+ {
+ printf(" %s: %s;\n", field->field.name, field->field.type);
+ }
+ else if (field->type == NODE_VAR_DECL)
+ {
+ // Fields might be VAR_DECLs in some parses? No, usually
+ // NODE_FIELD for structs.
+ printf(" %s: %s;\n", field->var_decl.name,
+ field->var_decl.type_str);
+ }
+ }
+ printf(" }\n");
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ printf(" (not found)\n");
+ }
+ free(show_code);
+ continue;
+ }
else if (0 == strcmp(cmd_buf, ":clear"))
{
- printf("\033[2J\033[H"); // ANSI clear screen
+ printf("\033[2J\033[H");
continue;
}
else if (0 == strcmp(cmd_buf, ":undo"))
@@ -289,9 +1370,7 @@ void run_repl(const char *self_path)
const char *editor = getenv("EDITOR");
if (!editor)
{
- editor = "nano"; // Default fallback,
- // 'cause I know some of you
- // don't know how to exit Vim.
+ editor = "nano";
}
char cmd[1024];
@@ -300,7 +1379,6 @@ void run_repl(const char *self_path)
if (0 == status)
{
- // Read back file.
FILE *fr = fopen(edit_path, "r");
if (fr)
{
@@ -415,23 +1493,15 @@ void run_repl(const char *self_path)
FILE *f = fopen(filename, "w");
if (f)
{
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- fprintf(f, "%s\n", history[i]);
- }
- }
- // Write main function body.
- fprintf(f, "\nfn main() {\n");
- for (int i = 0; i < history_len; i++)
- {
- if (!is_header_line(history[i]))
- {
- fprintf(f, " %s\n", history[i]);
- }
- }
- fprintf(f, "}\n");
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
+
+ fprintf(f, "%s\n", global_code);
+ fprintf(f, "\nfn main() {\n%s\n}\n", main_code);
+
+ free(global_code);
+ free(main_code);
fclose(f);
printf("Session saved to %s\n", filename);
}
@@ -501,36 +1571,21 @@ void run_repl(const char *self_path)
else if (0 == strcmp(cmd_buf, ":vars") || 0 == strcmp(cmd_buf, ":funcs") ||
0 == strcmp(cmd_buf, ":structs"))
{
- size_t code_size = 4096;
- for (int i = 0; i < history_len; i++)
- {
- code_size += strlen(history[i]) + 2;
- }
- char *code = malloc(code_size + 128);
- strcpy(code, "");
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, "\n");
- }
- }
- strcat(code, "fn main() { ");
- for (int i = 0; i < history_len; i++)
- {
- if (!is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, " ");
- }
- }
- strcat(code, " }");
+ size_t code_size = strlen(global_code) + strlen(main_code) + 128;
+ char *code = malloc(code_size);
+ sprintf(code, "%s\nfn main() { %s }", global_code, main_code);
+ free(global_code);
+ free(main_code);
ParserContext ctx = {0};
ctx.is_repl = 1;
ctx.skip_preamble = 1;
+ ctx.is_fault_tolerant = 1;
+ ctx.on_error = repl_error_callback;
Lexer l;
lexer_init(&l, code);
@@ -553,11 +1608,27 @@ void run_repl(const char *self_path)
break;
}
}
- printf("Variables:\n");
+
+ // Generate probe code to print values
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
+
+ // Generate probe code to print values
+ size_t probe_size = strlen(global_code) + strlen(main_code) + 4096;
+ char *probe_code = malloc(probe_size);
+
+ sprintf(probe_code,
+ "%s\nfn main() { _z_suppress_stdout(); %s _z_restore_stdout(); "
+ "printf(\"Variables:\\n\"); ",
+ global_code, main_code);
+ free(global_code);
+ free(main_code);
+
+ int found_vars = 0;
if (main_func && main_func->func.body &&
main_func->func.body->type == NODE_BLOCK)
{
- int found = 0;
for (ASTNode *s = main_func->func.body->block.statements; s;
s = s->next)
{
@@ -565,19 +1636,92 @@ void run_repl(const char *self_path)
{
char *t =
s->var_decl.type_str ? s->var_decl.type_str : "Inferred";
- printf(" %s: %s\n", s->var_decl.name, t);
- found = 1;
+ // Heuristic for format
+ char fmt[64];
+ char val_expr[128];
+
+ if (s->var_decl.type_str)
+ {
+ if (strcmp(t, "int") == 0 || strcmp(t, "i32") == 0)
+ {
+ strcpy(fmt, "%d");
+ strcpy(val_expr, s->var_decl.name);
+ }
+ else if (strcmp(t, "i64") == 0)
+ {
+ strcpy(fmt, "%ld");
+ sprintf(val_expr, "(long)%s", s->var_decl.name);
+ }
+ else if (strcmp(t, "float") == 0 ||
+ strcmp(t, "double") == 0 ||
+ strcmp(t, "f32") == 0 || strcmp(t, "f64") == 0)
+ {
+ strcpy(fmt, "%f");
+ strcpy(val_expr, s->var_decl.name);
+ }
+ else if (strcmp(t, "bool") == 0)
+ {
+ strcpy(fmt, "%s");
+ sprintf(val_expr, "%s ? \"true\" : \"false\"",
+ s->var_decl.name);
+ }
+ else if (strcmp(t, "string") == 0 ||
+ strcmp(t, "char*") == 0)
+ {
+ strcpy(fmt, "\\\"%s\\\"");
+ strcpy(val_expr, s->var_decl.name);
+ } // quote strings
+ else if (strcmp(t, "char") == 0)
+ {
+ strcpy(fmt, "'%c'");
+ strcpy(val_expr, s->var_decl.name);
+ }
+ else
+ {
+ // Fallback: address
+ strcpy(fmt, "@%p");
+ sprintf(val_expr, "(void*)&%s", s->var_decl.name);
+ }
+ }
+ else
+ {
+ // Inferred: Safe fallback? Or try to guess?
+ // For now, minimal safety: print address
+ strcpy(fmt, "? @%p");
+ sprintf(val_expr, "(void*)&%s", s->var_decl.name);
+ }
+
+ char print_stmt[512];
+ snprintf(print_stmt, sizeof(print_stmt),
+ "printf(\" %s (%s): %s\\n\", %s); ", s->var_decl.name,
+ t, fmt, val_expr);
+ strcat(probe_code, print_stmt);
+ found_vars = 1;
}
}
- if (!found)
- {
- printf(" (none)\n");
- }
}
- else
+
+ if (!found_vars)
{
- printf(" (none)\n");
+ strcat(probe_code, "printf(\" (none)\\n\");");
+ }
+
+ strcat(probe_code, " }");
+
+ // Execute
+ char tmp_path[256];
+ snprintf(tmp_path, sizeof(tmp_path), "/tmp/zen_repl_vars_%d.zc", getpid());
+ FILE *f = fopen(tmp_path, "w");
+ if (f)
+ {
+ fprintf(f, "%s", probe_code);
+ fclose(f);
+ char cmd[512];
+ snprintf(cmd, sizeof(cmd), "%s run -q %s", self_path, tmp_path);
+ system(cmd);
+ remove(tmp_path);
}
+ free(probe_code);
}
else if (0 == strcmp(cmd_buf, ":funcs"))
{
@@ -621,36 +1765,21 @@ void run_repl(const char *self_path)
{
char *expr = cmd_buf + 6;
- size_t probe_size = 4096;
- for (int i = 0; i < history_len; i++)
- {
- probe_size += strlen(history[i]) + 2;
- }
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
- char *probe_code = malloc(probe_size + strlen(expr) + 256);
- strcpy(probe_code, "");
+ size_t probe_size =
+ strlen(global_code) + strlen(main_code) + strlen(expr) + 4096;
+ char *probe_code = malloc(probe_size);
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(probe_code, history[i]);
- strcat(probe_code, "\n");
- }
- }
-
- strcat(probe_code, "fn main() { _z_suppress_stdout(); ");
- for (int i = 0; i < history_len; i++)
- {
- if (!is_header_line(history[i]))
- {
- strcat(probe_code, history[i]);
- strcat(probe_code, " ");
- }
- }
+ sprintf(probe_code, "%s\nfn main() { _z_suppress_stdout(); %s", global_code,
+ main_code);
+ free(global_code);
+ free(main_code);
strcat(probe_code, " raw { typedef struct { int _u; } __REVEAL_TYPE__; } ");
- strcat(probe_code, " var _z_type_probe: __REVEAL_TYPE__; _z_type_probe = (");
+ strcat(probe_code, " let _z_type_probe: __REVEAL_TYPE__; _z_type_probe = (");
strcat(probe_code, expr);
strcat(probe_code, "); }");
@@ -686,18 +1815,51 @@ void run_repl(const char *self_path)
int found = 0;
while (fgets(buf, sizeof(buf), p))
{
- char *marker = "right operand has type '";
- char *start = strstr(buf, marker);
+ char *start = strstr(buf, "from type ");
+ char quote = 0;
+ if (!start)
+ {
+ start = strstr(buf, "incompatible type ");
+ }
+
if (start)
{
- start += strlen(marker);
- char *end = strchr(start, '\'');
- if (end)
+ char *q = strchr(start, '\'');
+ if (!q)
{
- *end = 0;
- printf("\033[1;36mType: %s\033[0m\n", start);
- found = 1;
- break;
+ q = strstr(start, "\xe2\x80\x98");
+ }
+
+ if (q)
+ {
+ if (*q == '\'')
+ {
+ start = q + 1;
+ quote = '\'';
+ }
+ else
+ {
+ start = q + 3;
+ quote = 0;
+ }
+
+ char *end = NULL;
+ if (quote)
+ {
+ end = strchr(start, quote);
+ }
+ else
+ {
+ end = strstr(start, "\xe2\x80\x99");
+ }
+
+ if (end)
+ {
+ *end = 0;
+ printf("\033[1;36mType: %s\033[0m\n", start);
+ found = 1;
+ break;
+ }
}
}
}
@@ -716,33 +1878,21 @@ void run_repl(const char *self_path)
// Benchmark an expression.
char *expr = cmd_buf + 6;
- size_t code_size = 4096;
- for (int i = 0; i < history_len; i++)
- {
- code_size += strlen(history[i]) + 2;
- }
- char *code = malloc(code_size + strlen(expr) + 256);
- strcpy(code, "");
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
+
+ size_t code_size =
+ strlen(global_code) + strlen(main_code) + strlen(expr) + 4096;
+ char *code = malloc(code_size);
+
+ sprintf(code,
+ "%s\ninclude \"time.h\"\nfn main() { _z_suppress_stdout();\n%s "
+ "_z_restore_stdout();\n",
+ global_code, main_code);
+ free(global_code);
+ free(main_code);
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, "\n");
- }
- }
- strcat(code, "include \"time.h\"\n");
- strcat(code, "fn main() { _z_suppress_stdout();\n");
- for (int i = 0; i < history_len; i++)
- {
- if (!is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, " ");
- }
- }
- strcat(code, "_z_restore_stdout();\n");
strcat(code, "raw { clock_t _start = clock(); }\n");
strcat(code, "for _i in 0..1000 { ");
strcat(code, expr);
@@ -800,17 +1950,11 @@ void run_repl(const char *self_path)
while (brace_depth > 0)
{
- printf("... ");
- char more[1024];
- if (!fgets(more, sizeof(more), stdin))
+ char *more = repl_readline("... ", history, history_len, brace_depth);
+ if (!more)
{
break;
}
- size_t mlen = strlen(more);
- if (mlen > 0 && more[mlen - 1] == '\n')
- {
- more[--mlen] = 0;
- }
strcat(expr_buf, "\n");
strcat(expr_buf, more);
for (char *p = more; *p; p++)
@@ -824,35 +1968,20 @@ void run_repl(const char *self_path)
brace_depth--;
}
}
+ free(more);
}
- size_t code_size = 4096 + strlen(expr_buf);
- for (int i = 0; i < history_len; i++)
- {
- code_size += strlen(history[i]) + 2;
- }
- char *code = malloc(code_size + 128);
- strcpy(code, "");
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, "\n");
- }
- }
- strcat(code, "fn main() {\n");
- for (int i = 0; i < history_len; i++)
- {
- if (!is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, " ");
- }
- }
- strcat(code, expr_buf);
- strcat(code, "\n}");
+ size_t code_size =
+ strlen(global_code) + strlen(main_code) + strlen(expr_buf) + 128;
+ char *code = malloc(code_size);
+
+ sprintf(code, "%s\nfn main() { %s %s }", global_code, main_code, expr_buf);
+ free(global_code);
+ free(main_code);
free(expr_buf);
char tmp_path[256];
@@ -877,33 +2006,16 @@ void run_repl(const char *self_path)
}
else if (0 == strcmp(cmd_buf, ":run"))
{
- size_t code_size = 4096;
- for (int i = 0; i < history_len; i++)
- {
- code_size += strlen(history[i]) + 2;
- }
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
+
+ size_t code_size = strlen(global_code) + strlen(main_code) + 128;
char *code = malloc(code_size);
- strcpy(code, "");
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(code, history[i]);
- strcat(code, "\n");
- }
- }
- strcat(code, "fn main() {\n");
- for (int i = 0; i < history_len; i++)
- {
- if (!is_header_line(history[i]))
- {
- strcat(code, " ");
- strcat(code, history[i]);
- strcat(code, "\n");
- }
- }
- strcat(code, "}\n");
+ sprintf(code, "%s\nfn main() { %s }", global_code, main_code);
+ free(global_code);
+ free(main_code);
char tmp_path[256];
sprintf(tmp_path, "/tmp/zprep_repl_run_%d.zc", rand());
@@ -1082,7 +2194,6 @@ void run_repl(const char *self_path)
}
if (!found)
{
- // Fallback: try man pages, show only SYNOPSIS.
char man_cmd[256];
sprintf(man_cmd,
"man 3 %s 2>/dev/null | sed -n '/^SYNOPSIS/,/^[A-Z]/p' | "
@@ -1187,7 +2298,6 @@ void run_repl(const char *self_path)
continue;
}
- // Add to history.
if (history_len >= history_cap)
{
history_cap *= 2;
@@ -1201,40 +2311,20 @@ void run_repl(const char *self_path)
brace_depth = 0;
paren_depth = 0;
- size_t total_size = 4096;
- for (int i = 0; i < history_len; i++)
- {
- total_size += strlen(history[i]) + 2;
- }
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len, &global_code, &main_code);
+
+ size_t total_size = strlen(global_code) + strlen(main_code) + 4096;
if (watches_len > 0)
{
- total_size += 16 * 1024; // Plenty of space for watches. Yeah static ik.
+ total_size += 16 * 1024;
}
char *full_code = malloc(total_size);
- strcpy(full_code, "");
-
- // Hoisting pass.
- for (int i = 0; i < history_len; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(full_code, history[i]);
- strcat(full_code, "\n");
- }
- }
-
- strcat(full_code, "fn main() { _z_suppress_stdout(); ");
-
- for (int i = 0; i < history_len - 1; i++)
- {
- if (is_header_line(history[i]))
- {
- continue;
- }
- strcat(full_code, history[i]);
- strcat(full_code, " ");
- }
+ sprintf(full_code, "%s\nfn main() { _z_suppress_stdout(); %s", global_code, main_code);
+ free(global_code);
+ free(main_code);
strcat(full_code, "_z_restore_stdout(); ");
@@ -1249,6 +2339,8 @@ void run_repl(const char *self_path)
ParserContext ctx = {0};
ctx.is_repl = 1;
ctx.skip_preamble = 1;
+ ctx.is_fault_tolerant = 1;
+ ctx.on_error = repl_error_callback;
Lexer l;
lexer_init(&l, check_buf);
ASTNode *node = parse_statement(&ctx, &l);
@@ -1272,33 +2364,17 @@ void run_repl(const char *self_path)
if (is_expr)
{
- size_t probesz = 4096;
- for (int i = 0; i < history_len - 1; i++)
- {
- probesz += strlen(history[i]) + 2;
- }
- char *probe_code = malloc(probesz + strlen(last_line) + 512);
- strcpy(probe_code, "");
+ char *global_code = NULL;
+ char *main_code = NULL;
+ repl_get_code(history, history_len - 1, &global_code, &main_code);
- for (int i = 0; i < history_len - 1; i++)
- {
- if (is_header_line(history[i]))
- {
- strcat(probe_code, history[i]);
- strcat(probe_code, "\n");
- }
- }
-
- strcat(probe_code, "fn main() { _z_suppress_stdout(); ");
+ size_t probesz = strlen(global_code) + strlen(main_code) + strlen(last_line) + 4096;
+ char *probe_code = malloc(probesz);
- for (int i = 0; i < history_len - 1; i++)
- {
- if (!is_header_line(history[i]))
- {
- strcat(probe_code, history[i]);
- strcat(probe_code, " ");
- }
- }
+ sprintf(probe_code, "%s\nfn main() { _z_suppress_stdout(); %s", global_code,
+ main_code);
+ free(global_code);
+ free(main_code);
strcat(probe_code, " raw { typedef struct { int _u; } __REVEAL_TYPE__; } ");
strcat(probe_code, " var _z_type_probe: __REVEAL_TYPE__; _z_type_probe = (");
@@ -1356,10 +2432,9 @@ void run_repl(const char *self_path)
if (watches_len > 0)
{
- strcat(full_code, "; "); // separator.
+ strcat(full_code, "; ");
for (int i = 0; i < watches_len; i++)
{
- // Use printf for label, then print "{expr}" for value.
char wbuf[1024];
sprintf(wbuf,
"printf(\"\\033[90mwatch:%s = \\033[0m\"); print \"{%s}\"; "
@@ -1401,7 +2476,8 @@ void run_repl(const char *self_path)
FILE *hf = fopen(history_path, "w");
if (hf)
{
- for (int i = 0; i < history_len; i++)
+ int start = history_len > 1000 ? history_len - 1000 : 0;
+ for (int i = start; i < history_len; i++)
{
fprintf(hf, "%s\n", history[i]);
}
@@ -1409,11 +2485,14 @@ void run_repl(const char *self_path)
}
}
- for (int i = 0; i < history_len; i++)
+ if (history)
{
- free(history[i]);
+ for (int i = 0; i < history_len; i++)
+ {
+ free(history[i]);
+ }
+ free(history);
}
- free(history);
if (input_buffer)
{
free(input_buffer);
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 56a7690..d6d9853 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -533,9 +533,81 @@ char g_cflags[MAX_FLAGS_SIZE] = "";
int g_warning_count = 0;
CompilerConfig g_config = {0};
+// Helper for environment expansion
+static void expand_env_vars(char *dest, size_t dest_size, const char *src)
+{
+ char *d = dest;
+ const char *s = src;
+ size_t remaining = dest_size - 1;
+
+ while (*s && remaining > 0)
+ {
+ if (*s == '$' && *(s + 1) == '{')
+ {
+ const char *end = strchr(s + 2, '}');
+ if (end)
+ {
+ char var_name[256];
+ int len = end - (s + 2);
+ if (len < 255)
+ {
+ strncpy(var_name, s + 2, len);
+ var_name[len] = 0;
+ char *val = getenv(var_name);
+ if (val)
+ {
+ size_t val_len = strlen(val);
+ if (val_len < remaining)
+ {
+ strcpy(d, val);
+ d += val_len;
+ remaining -= val_len;
+ s = end + 1;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ *d++ = *s++;
+ remaining--;
+ }
+ *d = 0;
+}
+
+// Helper to determine active OS
+static int is_os_active(const char *os_name)
+{
+ if (0 == strcmp(os_name, "linux"))
+ {
+#ifdef __linux__
+ return 1;
+#else
+ return 0;
+#endif
+ }
+ else if (0 == strcmp(os_name, "windows"))
+ {
+#ifdef _WIN32
+ return 1;
+#else
+ return 0;
+#endif
+ }
+ else if (0 == strcmp(os_name, "macos") || 0 == strcmp(os_name, "darwin"))
+ {
+#ifdef __APPLE__
+ return 1;
+#else
+ return 0;
+#endif
+ }
+ return 0;
+}
+
void scan_build_directives(ParserContext *ctx, const char *src)
{
- (void)ctx; // Currently unused, reserved for future use
+ (void)ctx;
const char *p = src;
while (*p)
{
@@ -554,103 +626,113 @@ void scan_build_directives(ParserContext *ctx, const char *src)
len++;
}
- char line[2048];
+ char raw_line[2048];
if (len >= 2047)
{
len = 2047;
}
- strncpy(line, start, len);
- line[len] = 0;
+ strncpy(raw_line, start, len);
+ raw_line[len] = 0;
+
+ char line[2048];
+ expand_env_vars(line, sizeof(line), raw_line);
- if (0 == strncmp(line, "link:", 5))
+ char *directive = line;
+ char *colon = strchr(line, ':');
+ if (colon)
{
- char *val = line + 5;
- while (*val == ' ')
+ *colon = 0;
+ if (is_os_active(line))
+ {
+ directive = colon + 1;
+ while (*directive == ' ')
+ {
+ directive++;
+ }
+ }
+ else if (0 == strcmp(line, "linux") || 0 == strcmp(line, "windows") ||
+ 0 == strcmp(line, "macos"))
{
- val++;
+ goto next_line;
}
- if (strlen(g_link_flags) > 0)
+ else
{
- strcat(g_link_flags, " ");
+ *colon = ':';
+ directive = line;
}
- strcat(g_link_flags, val);
}
- else if (0 == strncmp(line, "cflags:", 7))
+
+ // Process Directive
+ if (0 == strncmp(directive, "link:", 5))
{
- char *val = line + 7;
- while (*val == ' ')
+ if (strlen(g_link_flags) > 0)
{
- val++;
+ strcat(g_link_flags, " ");
}
+ strcat(g_link_flags, directive + 5);
+ }
+ else if (0 == strncmp(directive, "cflags:", 7))
+ {
if (strlen(g_cflags) > 0)
{
strcat(g_cflags, " ");
}
- strcat(g_cflags, val);
+ strcat(g_cflags, directive + 7);
}
- else if (0 == strncmp(line, "include:", 8))
+ else if (0 == strncmp(directive, "include:", 8))
{
- char *val = line + 8;
- while (*val == ' ')
- {
- val++;
- }
char flags[2048];
- sprintf(flags, "-I%s", val);
+ sprintf(flags, "-I%s", directive + 8);
if (strlen(g_cflags) > 0)
{
strcat(g_cflags, " ");
}
strcat(g_cflags, flags);
}
- else if (strncmp(line, "lib:", 4) == 0)
+ else if (strncmp(directive, "lib:", 4) == 0)
{
- char *val = line + 4;
- while (*val == ' ')
- {
- val++;
- }
char flags[2048];
- sprintf(flags, "-L%s", val);
+ sprintf(flags, "-L%s", directive + 4);
if (strlen(g_link_flags) > 0)
{
strcat(g_link_flags, " ");
}
strcat(g_link_flags, flags);
}
- else if (strncmp(line, "define:", 7) == 0)
+ else if (strncmp(directive, "framework:", 10) == 0)
{
- char *val = line + 7;
- while (*val == ' ')
+ char flags[2048];
+ sprintf(flags, "-framework %s", directive + 10);
+ if (strlen(g_link_flags) > 0)
{
- val++;
+ strcat(g_link_flags, " ");
}
+ strcat(g_link_flags, flags);
+ }
+ else if (strncmp(directive, "define:", 7) == 0)
+ {
char flags[2048];
- sprintf(flags, "-D%s", val);
+ sprintf(flags, "-D%s", directive + 7);
if (strlen(g_cflags) > 0)
{
strcat(g_cflags, " ");
}
strcat(g_cflags, flags);
}
- else if (0 == strncmp(line, "shell:", 6))
+ else if (0 == strncmp(directive, "shell:", 6))
{
- char *cmd = line + 6;
- // printf("[zprep] Running shell: %s\n", cmd);
- int res = system(cmd);
- if (res != 0)
+ if (system(directive + 6) != 0)
{
- zwarn("Shell directive failed: %s", cmd);
+ zwarn("Shell directive failed: %s", directive + 6);
}
}
- else if (strncmp(line, "get:", 4) == 0)
+ else if (strncmp(directive, "get:", 4) == 0)
{
- char *url = line + 4;
+ char *url = directive + 4;
while (*url == ' ')
{
url++;
}
-
char *filename = strrchr(url, '/');
if (!filename)
{
@@ -660,8 +742,6 @@ void scan_build_directives(ParserContext *ctx, const char *src)
{
filename++;
}
-
- // Check if file exists to avoid redownloading.
FILE *f = fopen(filename, "r");
if (f)
{
@@ -669,16 +749,13 @@ void scan_build_directives(ParserContext *ctx, const char *src)
}
else
{
- printf("[zprep] Downloading %s...\n", filename);
char cmd[8192];
if (z_is_windows())
{
- // On Windows, try curl which is often built-in now
sprintf(cmd, "curl -s -L \"%s\" -o \"%s\"", url, filename);
}
else
{
- // Try wget, then curl.
sprintf(cmd, "wget -q \"%s\" -O \"%s\" || curl -s -L \"%s\" -o \"%s\"", url,
filename, url, filename);
}
@@ -688,40 +765,27 @@ void scan_build_directives(ParserContext *ctx, const char *src)
}
}
}
- else if (strncmp(line, "pkg-config:", 11) == 0)
+ else if (strncmp(directive, "pkg-config:", 11) == 0)
{
- char *libs = line + 11;
- while (*libs == ' ')
- {
- libs++;
- }
-
- if (z_is_windows())
- {
- zwarn("pkg-config is usually not available on Windows. Build directive "
- "'pkg-config:%s' might fail.",
- libs);
- }
-
+ char *libs = directive + 11;
char cmd[4096];
sprintf(cmd, "pkg-config --cflags %s", libs);
FILE *fp = popen(cmd, "r");
if (fp)
{
- char flags[4096];
- flags[0] = 0;
- if (fgets(flags, sizeof(flags), fp))
+ char buf[1024];
+ if (fgets(buf, sizeof(buf), fp))
{
- int len = strlen(flags);
- if (len > 0 && flags[len - 1] == '\n')
+ size_t l = strlen(buf);
+ if (l > 0 && buf[l - 1] == '\n')
{
- flags[len - 1] = 0;
+ buf[l - 1] = 0;
}
if (strlen(g_cflags) > 0)
{
strcat(g_cflags, " ");
}
- strcat(g_cflags, flags);
+ strcat(g_cflags, buf);
}
pclose(fp);
}
@@ -730,32 +794,35 @@ void scan_build_directives(ParserContext *ctx, const char *src)
fp = popen(cmd, "r");
if (fp)
{
- char flags[4096];
- flags[0] = 0;
- if (fgets(flags, sizeof(flags), fp))
+ char buf[1024];
+ if (fgets(buf, sizeof(buf), fp))
{
- int len = strlen(flags);
- if (len > 0 && flags[len - 1] == '\n')
+ size_t l = strlen(buf);
+ if (l > 0 && buf[l - 1] == '\n')
{
- flags[len - 1] = 0;
+ buf[l - 1] = 0;
}
if (strlen(g_link_flags) > 0)
{
strcat(g_link_flags, " ");
}
- strcat(g_link_flags, flags);
+ strcat(g_link_flags, buf);
}
pclose(fp);
}
}
+ else
+ {
+ zwarn("Unknown build directive: '%s'", directive);
+ }
p += len;
}
+ next_line:
while (*p && *p != '\n')
{
p++;
}
-
if (*p == '\n')
{
p++;
diff --git a/src/zprep.h b/src/zprep.h
index e248871..84400b3 100644
--- a/src/zprep.h
+++ b/src/zprep.h
@@ -108,6 +108,7 @@ typedef enum
TOK_PREPROC, ///< Preprocessor directive (#...).
TOK_ALIAS, ///< 'alias' keyword.
TOK_COMMENT, ///< Comment (usually skipped).
+ TOK_OPAQUE, ///< 'opaque' keyword.
TOK_UNKNOWN ///< Unknown token.
} TokenType;
@@ -358,6 +359,7 @@ typedef struct
int mode_transpile; ///< 1 if 'transpile' command (to C).
int use_cpp; ///< 1 if --cpp (emit C++ compatible code).
int use_cuda; ///< 1 if --cuda (emit CUDA-compatible code).
+ int use_objc; ///< 1 if --objc (emit Objective-C compatible code).
// GCC Flags accumulator.
char gcc_flags[4096]; ///< Flags passed to the backend compiler.
diff --git a/std.zc b/std.zc
index f0b2cd1..3dcc45a 100644
--- a/std.zc
+++ b/std.zc
@@ -19,3 +19,5 @@ import "./std/queue.zc"
import "./std/env.zc"
import "./std/slice.zc"
import "./std/regex.zc"
+import "./std/process.zc"
+
diff --git a/std/core.zc b/std/core.zc
index f450517..7379db4 100644
--- a/std/core.zc
+++ b/std/core.zc
@@ -7,11 +7,11 @@ include <stdarg.h>
let __zen_hash_seed: usize = 14695981039346656037;
-raw {
-void _zen_panic(const char* file, int line, const char* func, const char* msg) {
+extern fn exit(code: int);
+
+fn _zen_panic(file: const char*, line: int, func: const char*, msg: const char*) {
fprintf(stderr, "%s:%d (%s): Panic: %s\n", file, line, func, msg);
exit(1);
}
-}
#define panic(msg) _zen_panic(__FILE__, __LINE__, __func__, msg) \ No newline at end of file
diff --git a/std/cuda.zc b/std/cuda.zc
index c6a9403..8fc6545 100644
--- a/std/cuda.zc
+++ b/std/cuda.zc
@@ -101,6 +101,8 @@ fn cuda_ok() -> bool {
}
+// Minimal raw block: required for cudaDeviceProp struct field access
+// The cudaDeviceProp struct cannot be declared in Zen-C without type conflicts
raw {
void _z_cuda_get_props(int dev, char* name, size_t* total_mem, int* sm_count, int* major, int* minor, int* max_threads, int* warp_size) {
struct cudaDeviceProp prop;
diff --git a/std/env.zc b/std/env.zc
index 959784f..c63fd3d 100644
--- a/std/env.zc
+++ b/std/env.zc
@@ -2,23 +2,12 @@ import "./core.zc"
import "./option.zc"
import "./string.zc"
-raw {
- char *_z_env_get(char *name) {
- return getenv(name);
- }
-
- int _z_env_set(char *name, char *value, int overwrite) {
- return setenv(name, value, overwrite);
- }
-
- int _z_env_unset(char *name) {
- return unsetenv(name);
- }
-}
+include <stdlib.h>
-extern fn _z_env_get(name: char*) -> char*;
-extern fn _z_env_set(name: char*, value: char*, overwrite: int) -> int;
-extern fn _z_env_unset(name: char*) -> int;
+// Direct externs with const char* to match C stdlib declarations
+extern fn getenv(name: const char*) -> char*;
+extern fn setenv(name: const char*, value: const char*, overwrite: int) -> int;
+extern fn unsetenv(name: const char*) -> int;
@derive(Eq)
enum EnvRes {
@@ -30,7 +19,7 @@ struct Env {}
impl Env {
fn get(name: string) -> Option<string> {
- let value: string = _z_env_get(name);
+ let value: string = getenv(name);
if (value == NULL) {
return Option<string>::None();
}
@@ -39,7 +28,7 @@ impl Env {
}
fn get_dup(name: string) -> Option<String> {
- let value: string = _z_env_get(name);
+ let value: string = getenv(name);
if (value == NULL) {
return Option<String>::None();
}
@@ -52,13 +41,13 @@ impl Env {
}
fn set(name: string, value: string) -> EnvRes {
- let ret: int = _z_env_set(name, value, 1);
+ let ret: int = setenv(name, value, 1);
return (ret == 0) ? EnvRes::OK() : EnvRes::ERR();
}
fn unset(name: string) -> EnvRes {
- let ret: int = _z_env_unset(name);
+ let ret: int = unsetenv(name);
return (ret == 0) ? EnvRes::OK() : EnvRes::ERR();
}
diff --git a/std/fs.zc b/std/fs.zc
index c19f9f1..a00993b 100644
--- a/std/fs.zc
+++ b/std/fs.zc
@@ -2,22 +2,32 @@ import "./core.zc"
import "./result.zc"
import "./string.zc"
import "./vec.zc"
+import "./mem.zc"
def Z_SEEK_SET = 0;
def Z_SEEK_END = 2;
def Z_F_OK = 0;
-
-// TODO: restructure this tomorrow.
+include <dirent.h>
+include <sys/stat.h>
+include <unistd.h>
+include <stdlib.h>
+include <stdio.h>
+
+// Direct externs for simple functions with const char* parameters
+extern fn access(pathname: const char*, mode: int) -> int;
+extern fn unlink(pathname: const char*) -> int;
+extern fn rmdir(pathname: const char*) -> int;
+extern fn malloc(size: usize) -> void*;
+extern fn free(ptr: void*);
+
+// Minimal raw block: required for opaque FILE*/DIR* types and C struct access
+// These cannot be expressed in Zen-C extern declarations without type conflicts
raw {
- #include <dirent.h>
- #include <sys/stat.h>
- #include <unistd.h>
-
- // typedef needed for Vec<DirEntry*> generation if inferred
typedef struct DirEntry* DirEntryPtr;
- void* _z_fs_fopen(char* path, char* mode) {
+ // FILE* wrappers - fopen/fclose/etc use FILE* which conflicts with void*
+ void* _z_fs_fopen(const char* path, const char* mode) {
return fopen(path, mode);
}
@@ -40,20 +50,9 @@ raw {
int64_t _z_fs_ftell(void* stream) {
return (int64_t)ftell((FILE*)stream);
}
-
- int _z_fs_access(char* pathname, int mode) {
- return access(pathname, mode);
- }
-
- int _z_fs_unlink(char* pathname) {
- return unlink(pathname);
- }
-
- int _z_fs_rmdir(char* pathname) {
- return rmdir(pathname);
- }
-
- void* _z_fs_opendir(char* name) {
+
+ // DIR* wrappers - opendir/closedir/readdir use DIR* which conflicts with void*
+ void* _z_fs_opendir(const char* name) {
return opendir(name);
}
@@ -61,15 +60,8 @@ raw {
return closedir((DIR*)dir);
}
- void* _z_fs_malloc(size_t size) {
- return malloc(size);
- }
-
- void _z_fs_free(void* ptr) {
- free(ptr);
- }
-
- int _z_fs_get_metadata(char* path, uint64_t* size, int* is_dir, int* is_file) {
+ // struct stat access - cannot define matching Zen-C struct for stat
+ int _z_fs_get_metadata(const char* path, uint64_t* size, int* is_dir, int* is_file) {
struct stat st;
if (stat(path, &st) != 0) return -1;
*size = st.st_size;
@@ -78,6 +70,7 @@ raw {
return 0;
}
+ // struct dirent access - readdir returns struct dirent*
int _z_fs_read_entry(void* dir, char* out_name, int buf_size, int* is_dir) {
struct dirent* ent = readdir((DIR*)dir);
if (!ent) return 0;
@@ -87,7 +80,8 @@ raw {
return 1;
}
- int _z_fs_mkdir(char* path) {
+ // mkdir has different signatures on Windows vs POSIX
+ int _z_fs_mkdir(const char* path) {
#ifdef _WIN32
return mkdir(path);
#else
@@ -96,22 +90,18 @@ raw {
}
}
-extern fn _z_fs_mkdir(path: char*) -> int;
-extern fn _z_fs_get_metadata(path: char*, size: U64*, is_dir: int*, is_file: int*) -> int;
+extern fn _z_fs_mkdir(path: const char*) -> int;
+extern fn _z_fs_get_metadata(path: const char*, size: U64*, is_dir: int*, is_file: int*) -> int;
extern fn _z_fs_read_entry(dir: void*, out_name: char*, buf_size: int, is_dir: int*) -> int;
-extern fn _z_fs_fopen(path: char*, mode: char*) -> void*;
+extern fn _z_fs_fopen(path: const char*, mode: const char*) -> void*;
extern fn _z_fs_fclose(stream: void*) -> int;
extern fn _z_fs_fread(ptr: void*, size: usize, nmemb: usize, stream: void*) -> usize;
extern fn _z_fs_fwrite(ptr: void*, size: usize, nmemb: usize, stream: void*) -> usize;
-extern fn _z_fs_fseek(stream: void*, offset: long, whence: int) -> int;
-extern fn _z_fs_ftell(stream: void*) -> long;
-extern fn _z_fs_access(pathname: char*, mode: int) -> int;
-extern fn _z_fs_unlink(pathname: char*) -> int;
-extern fn _z_fs_rmdir(pathname: char*) -> int;
-extern fn _z_fs_opendir(name: char*) -> void*;
+extern fn _z_fs_fseek(stream: void*, offset: I64, whence: int) -> int;
+extern fn _z_fs_ftell(stream: void*) -> I64;
+extern fn _z_fs_opendir(name: const char*) -> void*;
extern fn _z_fs_closedir(dir: void*) -> int;
-extern fn _z_fs_malloc(size: usize) -> void*;
-extern fn _z_fs_free(ptr: void*);
+
struct File {
handle: void*;
@@ -153,7 +143,7 @@ impl File {
let size = _z_fs_ftell(self.handle);
_z_fs_fseek(self.handle, 0, Z_SEEK_SET);
- let buffer: char* = _z_fs_malloc((usize)size + 1);
+ let buffer: char* = malloc((usize)size + 1);
if (buffer == NULL) {
return Result<String>::Err("Out of memory");
}
@@ -162,7 +152,7 @@ impl File {
buffer[read] = 0;
let s = String::new(buffer);
- _z_fs_free(buffer);
+ free(buffer);
let res = Result<String>::Ok(s);
s.forget();
@@ -201,7 +191,7 @@ impl File {
}
fn exists(path: char*) -> bool {
- return _z_fs_access(path, Z_F_OK) == 0;
+ return access(path, Z_F_OK) == 0;
}
fn metadata(path: char*) -> Result<Metadata> {
@@ -228,14 +218,14 @@ impl File {
}
fn remove_file(path: char*) -> Result<bool> {
- if (_z_fs_unlink(path) != 0) {
+ if (unlink(path) != 0) {
return Result<bool>::Err("Failed to remove file");
}
return Result<bool>::Ok(true);
}
fn remove_dir(path: char*) -> Result<bool> {
- if (_z_fs_rmdir(path) != 0) {
+ if (rmdir(path) != 0) {
return Result<bool>::Err("Failed to remove directory");
}
return Result<bool>::Ok(true);
@@ -248,7 +238,7 @@ impl File {
}
let entries = Vec<DirEntry>::new();
- let name_buf: char* = _z_fs_malloc(256);
+ let name_buf: char* = malloc(256);
if (name_buf == NULL) {
_z_fs_closedir(dir);
@@ -277,7 +267,7 @@ impl File {
ent.name.forget();
}
- _z_fs_free(name_buf);
+ free(name_buf);
_z_fs_closedir(dir);
let res = Result< Vec<DirEntry> >::Ok(entries);
diff --git a/std/io.zc b/std/io.zc
index 2793ecf..a5a7359 100644
--- a/std/io.zc
+++ b/std/io.zc
@@ -2,37 +2,51 @@
import "./core.zc"
import "./string.zc"
-raw {
- int _z_vprintf(char* fmt, va_list ap) {
- return vprintf((const char*)fmt, ap);
- }
-
- int _z_vsnprintf(char* str, size_t size, char* fmt, va_list ap) {
- return vsnprintf(str, size, (const char*)fmt, ap);
- }
+include <stdio.h>
+include <stdarg.h>
- void* _z_get_stdin() { return stdin; }
- int _z_get_eof() { return EOF; }
+// These work directly with const char* in extern declarations
+extern fn vprintf(fmt: const char*, ap: va_list) -> int;
+
+// vsnprintf is problematic on macOS because it's a macro that expands to a builtin with a different signature
+// so we wrap it in a C function to avoid the conflict
+extern fn _z_vsnprintf(str: char*, size: usize, fmt: const char*, ap: va_list) -> int;
+
+// EOF is typically -1, but we define it for portability
+def Z_EOF = -1;
+
+// Minimal raw block: only for truly opaque FILE* types that can't be
+// represented in Zen-C extern declarations without type conflicts.
+// These wrappers use void* to avoid FILE* declaration conflicts.
+raw {
+ void* _z_get_stdin(void) { return stdin; }
int _z_fgetc(void* stream) { return fgetc((FILE*)stream); }
+ int _z_vsnprintf(char* str, size_t size, const char* fmt, va_list ap) {
+ return vsnprintf(str, size, fmt, ap);
+ }
}
-extern fn _z_vprintf(fmt: char*, ap: va_list) -> int;
-extern fn _z_vsnprintf(str: char*, size: usize, fmt: char*, ap: va_list) -> int;
+extern fn _z_get_stdin() -> void*;
+extern fn _z_fgetc(stream: void*) -> int;
fn format(fmt: char*, ...) -> char* {
static let buffer: char[1024];
let ap: va_list;
va_start(ap, fmt);
+
_z_vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
+
return (char*)buffer;
}
fn format_into(buffer: char*, size: usize, fmt: char*, ...) -> int {
let ap: va_list;
va_start(ap, fmt);
+
let ret = _z_vsnprintf(buffer, size, fmt, ap);
va_end(ap);
+
return ret;
}
@@ -42,15 +56,17 @@ fn format_new(fmt: char*, ...) -> char* {
let ap: va_list;
va_start(ap, fmt);
+
_z_vsnprintf(buffer, 1024, fmt, ap);
va_end(ap);
+
return buffer;
}
fn print(fmt: char*, ...) -> int {
let ap: va_list;
va_start(ap, fmt);
- let ret = _z_vprintf(fmt, ap);
+ let ret = vprintf(fmt, ap);
va_end(ap);
return ret;
}
@@ -58,7 +74,7 @@ fn print(fmt: char*, ...) -> int {
fn println(fmt: char*, ...) -> int {
let ap: va_list;
va_start(ap, fmt);
- let ret = _z_vprintf(fmt, ap);
+ let ret = vprintf(fmt, ap);
va_end(ap);
puts("");
return ret + 1;
@@ -72,11 +88,10 @@ fn readln() -> char* {
let c: int;
let std_in = _z_get_stdin();
- let eof_val = _z_get_eof();
while (true) {
c = _z_fgetc(std_in);
- if (c == eof_val) break;
+ if (c == Z_EOF) break;
if (c == 10) break; // '\n'
if (len + 1 >= cap) {
@@ -93,7 +108,7 @@ fn readln() -> char* {
len = len + 1;
}
- if (len == 0 && c == eof_val) {
+ if (len == 0 && c == Z_EOF) {
free(line);
return NULL;
}
diff --git a/std/json.zc b/std/json.zc
index e6a15cd..9f5cf73 100644
--- a/std/json.zc
+++ b/std/json.zc
@@ -5,6 +5,7 @@ import "./map.zc"
import "./string.zc"
import "./result.zc"
import "./option.zc"
+import "./mem.zc"
@derive(Eq)
enum JsonType {
@@ -450,3 +451,74 @@ impl JsonValue {
}
}
}
+
+impl Drop for JsonValue {
+ fn drop(self) {
+ self.free();
+ }
+}
+
+impl JsonValue {
+ fn to_string(self) -> String {
+ let s = String::new("");
+ self.stringify(&s);
+ return s;
+ }
+
+ fn stringify(self, buf: String*) {
+ if (self.kind.tag == JsonType::JSON_NULL().tag) {
+ buf.append_c_ptr("null");
+ } else if (self.kind.tag == JsonType::JSON_BOOL().tag) {
+ if (self.bool_val) { buf.append_c_ptr("true"); } else { buf.append_c_ptr("false"); }
+ } else if (self.kind.tag == JsonType::JSON_NUMBER().tag) {
+ let tmp: char[64];
+ sprintf((char*)tmp, "%.15g", self.number_val); // Use %.15g for precision
+ buf.append_c_ptr((char*)tmp);
+ } else if (self.kind.tag == JsonType::JSON_STRING().tag) {
+ buf.append_c_ptr("\"");
+ let p = self.string_val;
+ let len = strlen(p);
+ for (let i = 0; i < len; i = i + 1) {
+ let c = p[i];
+ if (c == '"') buf.append_c_ptr("\\\"");
+ else if (c == '\\') buf.append_c_ptr("\\\\");
+ else if (c == '\n') buf.append_c_ptr("\\n");
+ else if (c == '\t') buf.append_c_ptr("\\t");
+ else if (c == '\r') buf.append_c_ptr("\\r");
+ else if (c == '\b') buf.append_c_ptr("\\b");
+ else if (c == '\f') buf.append_c_ptr("\\f");
+ else {
+ let tmp: char[2]; tmp[0] = c; tmp[1] = 0;
+ buf.append_c_ptr((char*)tmp);
+ }
+ }
+ buf.append_c_ptr("\"");
+ } else if (self.kind.tag == JsonType::JSON_ARRAY().tag) {
+ buf.append_c_ptr("[");
+ let v = self.array_val;
+ for (let i: usize = 0; i < v.length(); i = i + 1) {
+ if (i > 0) buf.append_c_ptr(",");
+ let item = v.get(i);
+ (*item).stringify(buf);
+ }
+ buf.append_c_ptr("]");
+ } else if (self.kind.tag == JsonType::JSON_OBJECT().tag) {
+ buf.append_c_ptr("{{");
+ let m = self.object_val;
+ let first = true;
+ for (let i: usize = 0; i < m.capacity(); i = i + 1) {
+ if (m.is_slot_occupied(i)) {
+ if (!first) buf.append_c_ptr(",");
+ first = false;
+ let key = m.key_at(i);
+ buf.append_c_ptr("\"");
+ buf.append_c_ptr(key); // Assuming keys are simple for now, but really should escape them too
+ buf.append_c_ptr("\":");
+ let val = m.val_at(i);
+ val.stringify(buf);
+ }
+ }
+ buf.append_c_ptr("}");
+ }
+ }
+}
diff --git a/std/map.zc b/std/map.zc
index 8e58cdc..8376da2 100644
--- a/std/map.zc
+++ b/std/map.zc
@@ -1,17 +1,22 @@
import "./core.zc"
import "./option.zc"
+import "./mem.zc"
-raw {
- extern size_t __zen_hash_seed;
- size_t _map_hash_str(const char* str) {
- size_t hash = __zen_hash_seed;
- while (*str) {
- hash ^= (unsigned char)*str++;
- hash *= 1099511628211UL;
- }
- return hash;
+// Pure Zen-C string hash using FNV-1a algorithm
+fn _map_hash_str(str: const char*) -> usize {
+ let hash = __zen_hash_seed;
+ let i: usize = 0;
+
+ while (str[i] != 0) {
+ // Cast char to U8 for unsigned byte value
+ let b: U8 = (U8)str[i];
+ hash = hash ^ (usize)b;
+ hash = hash * (usize)1099511628211;
+ i = i + 1;
}
+
+ return hash;
}
struct Map<V> {
@@ -248,3 +253,9 @@ impl Map<V> {
};
}
}
+
+impl Drop for Map<V> {
+ fn drop(self) {
+ self.free();
+ }
+}
diff --git a/std/mem.zc b/std/mem.zc
index 6ee96e8..f1a5f5a 100644
--- a/std/mem.zc
+++ b/std/mem.zc
@@ -49,28 +49,7 @@ impl Box<T> {
}
}
-struct Slice<T> {
- data: T*;
- len: usize;
-}
-
-impl Slice<T> {
- fn new(data: T*, len: usize) -> Self {
- return Self { data: data, len: len };
- }
-
- fn get(self, i: usize) -> T {
- return self.data[i];
- }
-
- fn set(self, i: usize, val: T) {
- self.data[i] = val;
- }
-
- fn is_empty(self) -> bool {
- return self.len == 0;
- }
-}
+// Note: Slice<T> is defined in std/slice.zc with iteration support
fn mem_zero<T>(ptr: T*, count: usize) {
memset(ptr, 0, sizeof(T) * count);
diff --git a/std/net.zc b/std/net.zc
index 72c3fcb..d410a4d 100644
--- a/std/net.zc
+++ b/std/net.zc
@@ -8,12 +8,22 @@ include <errno.h>
import "./core.zc"
import "./result.zc"
import "./string.zc"
+import "./mem.zc"
def Z_AF_INET = 2;
def Z_SOCK_STREAM = 1;
+// Direct externs for simple socket functions
+extern fn socket(domain: int, type: int, proto: int) -> int;
+extern fn close(fd: int) -> int;
+extern fn read(fd: int, buf: void*, count: usize) -> isize;
+
+// Minimal raw block: required for struct sockaddr_in usage
+// These functions encapsulate sockaddr_in setup because the struct layout
+// cannot be declared in Zen-C without type conflicts with C headers.
+// Also includes inet_pton, htons, bind, connect, listen, accept wrappers.
raw {
- static int _z_net_bind(int fd, char *host, int port) {
+ static int _z_net_bind(int fd, const char *host, int port) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -27,7 +37,7 @@ raw {
return 0;
}
- static int _z_net_connect(int fd, char *host, int port) {
+ static int _z_net_connect(int fd, const char *host, int port) {
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
@@ -36,28 +46,20 @@ raw {
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) return -2;
return 0;
}
-
+
static int _z_net_accept(int fd) {
return accept(fd, NULL, NULL);
}
- static ssize_t _z_net_read(int fd, char* buf, size_t n) {
- return read(fd, (void*)buf, n);
- }
-
- static ssize_t _z_net_write(int fd, char* buf, size_t n) {
+ static ssize_t _z_net_write(int fd, const char* buf, size_t n) {
return write(fd, (const void*)buf, n);
}
}
-extern fn socket(domain: int, type: int, proto: int) -> int;
-extern fn close(fd: int) -> int;
-
-extern fn _z_net_bind(fd: int, host: char*, port: int) -> int;
-extern fn _z_net_connect(fd: int, host: char*, port: int) -> int;
+extern fn _z_net_bind(fd: int, host: const char*, port: int) -> int;
+extern fn _z_net_connect(fd: int, host: const char*, port: int) -> int;
extern fn _z_net_accept(fd: int) -> int;
-extern fn _z_net_read(fd: int, buf: char*, n: usize) -> isize;
-extern fn _z_net_write(fd: int, buf: char*, n: usize) -> isize;
+extern fn _z_net_write(fd: int, buf: const char*, n: usize) -> isize;
struct TcpStream {
@@ -66,7 +68,7 @@ struct TcpStream {
impl TcpStream {
fn read(self, buf: char*, len: usize) -> Result<usize> {
- let n = _z_net_read(self.fd, buf, len);
+ let n = read(self.fd, (void*)buf, len);
if (n < 0) return Result<usize>::Err("Read failed");
return Result<usize>::Ok((usize)n);
}
@@ -96,6 +98,12 @@ impl TcpStream {
}
}
+impl Drop for TcpStream {
+ fn drop(self) {
+ self.close();
+ }
+}
+
struct TcpListener {
fd: int;
}
@@ -126,3 +134,9 @@ impl TcpListener {
}
}
}
+
+impl Drop for TcpListener {
+ fn drop(self) {
+ self.close();
+ }
+}
diff --git a/std/process.zc b/std/process.zc
new file mode 100644
index 0000000..3ce43b6
--- /dev/null
+++ b/std/process.zc
@@ -0,0 +1,136 @@
+
+import "./core.zc";
+import "./vec.zc";
+import "./mem.zc";
+import "./string.zc";
+import "./option.zc";
+
+include <stdio.h>
+include <stdlib.h>
+
+// system() can be externed directly with const char*
+extern fn system(command: const char*) -> int;
+
+// Minimal raw block: only for opaque FILE* types
+// popen/pclose/fgets use FILE* which conflicts with void*
+raw {
+ void *_z_popen(const char *command, const char *type) {
+ return (void *)popen(command, type);
+ }
+
+ int _z_pclose(void *stream) {
+ return pclose((FILE *)stream);
+ }
+
+ char *_z_fgets(char *s, int size, void *stream) {
+ return fgets(s, size, (FILE *)stream);
+ }
+}
+
+extern fn _z_popen(command: const char*, type: const char*) -> void*;
+extern fn _z_pclose(stream: void*) -> int;
+extern fn _z_fgets(s: char*, size: int, stream: void*) -> char*;
+
+struct Output {
+ stdout: String;
+ exit_code: int;
+}
+
+struct Command {
+ program: String;
+ args: Vec<String>;
+}
+
+impl Command {
+ fn new(program: char*) -> Command {
+ return Command {
+ program: String::from(program),
+ args: Vec<String>::new()
+ };
+ }
+
+ fn arg(self, arg: char*) -> Command* {
+ self.args.push(String::from(arg));
+ return self;
+ }
+
+ fn _build_cmd(self) -> String {
+ let cmd_str = self.program.substring(0, self.program.length());
+
+ for arg in &self.args {
+ let space = String::from(" ");
+ cmd_str.append(&space);
+ space.free();
+
+ cmd_str.append(arg);
+ }
+
+ return cmd_str;
+ }
+
+ fn output(self) -> Output {
+ let cmd_str = self._build_cmd();
+ let cmd_c = cmd_str.c_str();
+
+ let fp = _z_popen(cmd_c, "r");
+
+ if (fp == 0) {
+ cmd_str.free();
+ // TODO: Better error handling...
+ return Output {
+ stdout: String::from(""),
+ exit_code: -1
+ };
+ }
+
+ let out = String::from("");
+ let buf_size: usize = 1024;
+ let buf = (char*)malloc(buf_size);
+
+ while (true) {
+ let res = _z_fgets(buf, (int)buf_size, fp);
+ if (res == 0) break;
+
+ let chunk = String::from(buf);
+ out.append(&chunk);
+ chunk.free();
+ }
+
+ let code = _z_pclose(fp);
+ free(buf);
+ cmd_str.free();
+
+ return Output {
+ stdout: out,
+ exit_code: code
+ };
+ }
+
+ fn status(self) -> int {
+ let cmd_str = self._build_cmd();
+ let code = system(cmd_str.c_str());
+ cmd_str.free();
+ return code;
+ }
+
+ fn free(self) {
+ self.program.free();
+
+ for s in &self.args {
+ s.free();
+ }
+ self.args.free();
+ }
+}
+
+impl Drop for Command {
+ fn drop(self) {
+ self.free();
+ }
+}
+
+impl Drop for Output {
+ fn drop(self) {
+ self.stdout.free();
+ }
+}
diff --git a/std/set.zc b/std/set.zc
index ba6c93f..e1faab3 100644
--- a/std/set.zc
+++ b/std/set.zc
@@ -2,17 +2,17 @@
import "./core.zc"
import "./option.zc"
-raw {
- extern size_t __zen_hash_seed;
- size_t _set_hash(const void* data, size_t len) {
- size_t hash = __zen_hash_seed;
- const unsigned char* bytes = (const unsigned char*)data;
- for (size_t i = 0; i < len; i++) {
- hash ^= bytes[i];
- hash *= 1099511628211UL;
- }
- return hash;
+// Pure Zen-C generic hash using FNV-1a algorithm
+fn _set_hash(data: const void*, len: usize) -> usize {
+ let hash = __zen_hash_seed;
+ let bytes: U8* = (U8*)data;
+
+ for (let i: usize = 0; i < len; i = i + 1) {
+ hash = hash ^ (usize)bytes[i];
+ hash = hash * (usize)1099511628211;
}
+
+ return hash;
}
struct Set<T> {
diff --git a/std/slice.zc b/std/slice.zc
index 778c6ed..c757fbd 100644
--- a/std/slice.zc
+++ b/std/slice.zc
@@ -1,10 +1,50 @@
+import "./option.zc"
+
struct Slice<T> {
data: T*;
len: usize;
}
+struct SliceIter<T> {
+ data: T*;
+ count: usize;
+ idx: usize;
+}
+
+impl SliceIter<T> {
+ fn next(self) -> Option<T> {
+ if (self.idx < self.count) {
+ let item = self.data[self.idx];
+ self.idx = self.idx + 1;
+ return Option<T>::Some(item);
+ }
+ return Option<T>::None();
+ }
+
+ fn iterator(self) -> SliceIter<T> {
+ return *self;
+ }
+}
+
impl Slice<T> {
+ fn from_array(ptr: T*, len: usize) -> Slice<T> {
+ return Slice<T> { data: ptr, len: len };
+ }
+
+ // Alias for backwards compatibility with std/mem.zc
+ fn new(data: T*, len: usize) -> Slice<T> {
+ return Slice<T> { data: data, len: len };
+ }
+
+ fn iterator(self) -> SliceIter<T> {
+ return SliceIter<T> {
+ data: self.data,
+ count: self.len,
+ idx: 0
+ };
+ }
+
fn length(self) -> usize {
return self.len;
}
diff --git a/std/string.zc b/std/string.zc
index fe5b0ad..0bc9539 100644
--- a/std/string.zc
+++ b/std/string.zc
@@ -55,6 +55,28 @@ impl String {
}
}
+ fn append_c(self, s: char*) {
+ if (self.vec.len > 0) {
+ self.vec.len = self.vec.len - 1;
+ }
+ let len = strlen(s);
+ for (let i = 0; i < len; i = i + 1) {
+ self.vec.push(s[i]);
+ }
+ self.vec.push(0);
+ }
+
+ fn append_c_ptr(ptr: String*, s: char*) {
+ if (ptr.vec.len > 0) {
+ ptr.vec.len = ptr.vec.len - 1;
+ }
+ let len = strlen(s);
+ for (let i = 0; i < len; i = i + 1) {
+ ptr.vec.push(s[i]);
+ }
+ ptr.vec.push(0);
+ }
+
fn add(self, other: String*) -> String {
let new_s = String::from(self.c_str());
new_s.append(other);
diff --git a/std/thread.zc b/std/thread.zc
index e90943b..16f3ca1 100644
--- a/std/thread.zc
+++ b/std/thread.zc
@@ -5,7 +5,13 @@ include <unistd.h>
import "./core.zc"
import "./result.zc"
+import "./mem.zc"
+// Essential raw block: required for pthread operations and closure trampolining
+// This block cannot be eliminated because:
+// 1. z_closure_T is an internal compiler type for Zen-C closures
+// 2. pthread_t, pthread_mutex_t are opaque types that can't be extern'd with void*
+// 3. The trampoline function needs to cast and execute Zen-C closures
raw {
typedef void (*ZenThreadFunc)(void*);
@@ -120,11 +126,17 @@ impl Mutex {
if (self.handle) {
_z_mutex_destroy(self.handle);
free(self.handle);
+ self.handle = NULL;
}
}
}
+impl Drop for Mutex {
+ fn drop(self) {
+ self.free();
+ }
+}
+
fn sleep_ms(ms: int) {
_z_usleep(ms * 1000);
}
-
diff --git a/std/time.zc b/std/time.zc
index 1191821..fa764ed 100644
--- a/std/time.zc
+++ b/std/time.zc
@@ -1,18 +1,31 @@
-
import "./core.zc"
+include <time.h>
+include <unistd.h>
+include <sys/time.h>
+include <stdlib.h>
+
+// Minimal raw block: required because gettimeofday() uses struct timeval
+// which can't be declared in Zen-C without type conflicts, and time()
+// has conflicting type signature (time_t* vs void*)
raw {
- #include <time.h>
- #include <unistd.h>
- #include <sys/time.h>
-
static uint64_t _time_now_impl(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)(tv.tv_sec) * 1000 + (uint64_t)(tv.tv_usec) / 1000;
}
+
+ static int64_t _z_time_time(void) {
+ return (int64_t)time(NULL);
+ }
}
+extern fn srand(seed: U32);
+extern fn rand() -> int;
+extern fn usleep(micros: U32) -> int;
+extern fn _time_now_impl() -> U64;
+extern fn _z_time_time() -> I64;
+
struct Duration {
millis: U64;
}
@@ -33,10 +46,8 @@ extern size_t __zen_hash_seed;
impl Time {
fn randomize_hash() {
- raw {
- srand(time(NULL));
- __zen_hash_seed ^= (size_t)rand();
- }
+ srand((U32)_z_time_time());
+ __zen_hash_seed ^= (size_t)rand();
}
fn now() -> U64 {
diff --git a/tests/features/_opaque_alias_lib.zc b/tests/features/_opaque_alias_lib.zc
new file mode 100644
index 0000000..7ca4abc
--- /dev/null
+++ b/tests/features/_opaque_alias_lib.zc
@@ -0,0 +1,13 @@
+opaque alias Handle = int;
+
+fn new_handle(v: int) -> Handle {
+ return v; // Implicit cast int -> Handle (OK in module)
+}
+
+fn get_val(h: Handle) -> int {
+ return h; // Implicit cast Handle -> int (OK in module)
+}
+
+fn compare_handles(a: Handle, b: Handle) -> bool {
+ return a == b; // Strict equality (OK)
+}
diff --git a/tests/features/_opaque_lib.zc b/tests/features/_opaque_lib.zc
new file mode 100644
index 0000000..de4d4c4
--- /dev/null
+++ b/tests/features/_opaque_lib.zc
@@ -0,0 +1,15 @@
+opaque struct SecretBox {
+ value: int;
+}
+
+fn new_box(v: int) -> SecretBox {
+ return SecretBox { value: v };
+}
+
+fn get_value(b: SecretBox*) -> int {
+ return b.value;
+}
+
+fn set_value(b: SecretBox*, v: int) {
+ b.value = v;
+}
diff --git a/tests/features/test_build_directives.zc b/tests/features/test_build_directives.zc
index 7edd317..d3f1cba 100644
--- a/tests/features/test_build_directives.zc
+++ b/tests/features/test_build_directives.zc
@@ -1,19 +1,8 @@
-//> link: -lm
-//> cflags: -O2
-// Declare C math function (since we don't have a math stdlib module yet)
-extern fn sin(x: double) -> double;
+//> shell: echo "Env Worked" > ${PWD}/build_dir_env.txt
+//> linux: shell: echo "Linux Worked" > ${PWD}/build_dir_linux.txt
+//> windows: shell: echo "Windows Worked" > ${PWD}/build_dir_windows.txt
-test "test_build_directives" {
- println "Running Build Directives Test...";
- let x = 3.14159 / 2.0; // PI/2
- let s = sin(x);
- // sin(PI/2) should be 1.0
- println "sin(PI/2) = {s}";
-
- if (s > 0.99 && s < 1.01) {
- println "Math Link Success!";
- } else {
- println "Math Link Failure (Value wrong)";
- }
+fn main() {
+ return 0;
}
diff --git a/tests/features/test_implicit_fstring.zc b/tests/features/test_implicit_fstring.zc
new file mode 100644
index 0000000..85a6c86
--- /dev/null
+++ b/tests/features/test_implicit_fstring.zc
@@ -0,0 +1,19 @@
+
+test "implicit_fstring_interpolation" {
+ let result = 123;
+ let s = "{result}";
+ // Should be "123"
+ assert(strcmp(s, "123") == 0, "Implicit f-string failed");
+}
+
+test "implicit_fstring_complex" {
+ let a = 10;
+ let b = 20;
+ let s = "Sum: {a + b}";
+ assert(strcmp(s, "Sum: 30") == 0, "Complex implicit f-string failed");
+}
+
+test "no_interpolation" {
+ let s = "Hello World";
+ assert(strcmp(s, "Hello World") == 0, "Plain string failed");
+}
diff --git a/tests/features/test_opaque.zc b/tests/features/test_opaque.zc
new file mode 100644
index 0000000..5c84b2a
--- /dev/null
+++ b/tests/features/test_opaque.zc
@@ -0,0 +1,18 @@
+import "_opaque_lib.zc";
+
+fn main() {
+ let b = new_box(42);
+
+ // Stack allocation should work (size known)
+ let b2: SecretBox;
+ b2 = b;
+
+ // Public methods should work
+ let v = get_value(&b2);
+ assert(v == 42, "Value should be 42");
+
+ set_value(&b2, 100);
+ assert(get_value(&b2) == 100, "Value should be 100");
+
+ println "Opaque struct test passed";
+}
diff --git a/tests/features/test_opaque_alias.zc b/tests/features/test_opaque_alias.zc
new file mode 100644
index 0000000..062fa1f
--- /dev/null
+++ b/tests/features/test_opaque_alias.zc
@@ -0,0 +1,13 @@
+import "_opaque_alias_lib.zc";
+
+fn main() {
+ let h = new_handle(42);
+ let v = get_val(h);
+
+ assert(v == 42, "Opaque Alias FAIL");
+
+ let h2 = new_handle(42);
+ assert(compare_handles(h, h2), "Equality FAIL");
+
+ println "Opaque Alias OK";
+}
diff --git a/tests/features/test_traits_suite.zc b/tests/features/test_traits_suite.zc
index 205bdf6..2ff8378 100644
--- a/tests/features/test_traits_suite.zc
+++ b/tests/features/test_traits_suite.zc
@@ -90,7 +90,7 @@ test "test_derive" {
// Debug
let s = p1.to_string();
- assert(strcmp(s, "Point { ... }") == 0, "Debug string matches");
+ assert(strcmp(s, "Point {{ ... }}") == 0, "Debug string matches");
// Clone
let p2 = p1.clone();
diff --git a/tests/memory/test_memory_safety.zc b/tests/memory/test_memory_safety.zc
index a5cc960..b672cc9 100644
--- a/tests/memory/test_memory_safety.zc
+++ b/tests/memory/test_memory_safety.zc
@@ -1,5 +1,6 @@
import "std/mem.zc"
+import "std/slice.zc"
// ** Globals **
let DROP_COUNT = 0;
@@ -127,11 +128,13 @@ test "test_slice" {
let data: int[5] = [1, 2, 3, 4, 5];
let s = Slice<int>::new(&data[0], 5);
f" Slice len: {(int)s.len}";
- let v2 = s.get(2);
+ let opt_v2 = s.get(2);
+ let v2 = opt_v2.unwrap();
f" Slice[2]: {v2}";
assert(v2 == 3, "Slice get failed");
- s.set(0, 99);
- let v0 = s.get(0);
+ s.data[0] = 99;
+ let opt_v0 = s.get(0);
+ let v0 = opt_v0.unwrap();
f" After set: Slice[0] = {v0}";
assert(v0 == 99, "Slice set failed");
" ✓ Slice works!";
diff --git a/tests/memory/test_unsafe.zc b/tests/memory/test_unsafe.zc
index fe1150f..6114d6c 100644
--- a/tests/memory/test_unsafe.zc
+++ b/tests/memory/test_unsafe.zc
@@ -54,3 +54,18 @@ test "test_static_local" {
assert b == 2;
assert c == 3;
}
+
+struct CastFoo {
+ val: int;
+}
+
+fn test_cast_precedence_helper(ptr: void*) -> int {
+ return ((CastFoo*)ptr)->val;
+}
+
+test "test_cast_precedence" {
+ let f = CastFoo{val: 42};
+ let ptr = (void*)&f;
+ let val = test_cast_precedence_helper(ptr);
+ assert(val == 42, "Cast precedence failed");
+}
diff --git a/tests/run_example_transpile.sh b/tests/run_example_transpile.sh
new file mode 100755
index 0000000..c08a3ea
--- /dev/null
+++ b/tests/run_example_transpile.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+ZC="./zc"
+EXAMPLES_DIR="examples"
+FAIL_COUNT=0
+PASS_COUNT=0
+
+echo "Running Example Transpilation Tests..."
+
+while IFS= read -r file; do
+ echo -n "Transpiling $file... "
+
+ OUTPUT=$($ZC transpile "$file" 2>&1)
+ EXIT_CODE=$?
+
+ if [ $EXIT_CODE -eq 0 ]; then
+ echo "PASS"
+ PASS_COUNT=$((PASS_COUNT + 1))
+ [ -f "out.c" ] && rm "out.c"
+ [ -f "a.out" ] && rm "a.out"
+ else
+ echo "FAIL"
+ echo "$OUTPUT"
+ FAIL_COUNT=$((FAIL_COUNT + 1))
+ fi
+
+done < <(find "$EXAMPLES_DIR" -name "*.zc")
+
+echo "----------------------------------------"
+echo "Summary:"
+echo "-> Passed: $PASS_COUNT"
+echo "-> Failed: $FAIL_COUNT"
+echo "----------------------------------------"
+
+if [ $FAIL_COUNT -ne 0 ]; then
+ exit 1
+fi
+
+exit 0
diff --git a/tests/std/test_direct_array_iteration.zc b/tests/std/test_direct_array_iteration.zc
new file mode 100644
index 0000000..359951f
--- /dev/null
+++ b/tests/std/test_direct_array_iteration.zc
@@ -0,0 +1,37 @@
+import "std/slice.zc"
+
+test "direct array iteration" {
+ let arr: int[5] = [1, 2, 3, 4, 5];
+
+ let sum = 0;
+ for val in arr {
+ sum = sum + val;
+ }
+
+ assert(sum == 15, "Sum should be 1+2+3+4+5 = 15");
+}
+
+test "direct array iteration with different types" {
+ let floats: float[3] = [1.5, 2.5, 3.0];
+ let count = 0;
+
+ for f in floats {
+ count = count + 1;
+ }
+
+ assert(count == 3, "Should iterate over all 3 elements");
+}
+
+// TODO: Nested array iteration needs special handling
+// test "nested array iteration" {
+// let matrix: int[2][3] = [[1, 2, 3], [4, 5, 6]];
+// let total = 0;
+//
+// for row in matrix {
+// for val in row {
+// total = total + val;
+// }
+// }
+//
+// assert(total == 21, "Sum should be 1+2+3+4+5+6 = 21");
+// }
diff --git a/tests/std/test_env.zc b/tests/std/test_env.zc
index 25d5bc1..4b68712 100644
--- a/tests/std/test_env.zc
+++ b/tests/std/test_env.zc
@@ -30,7 +30,7 @@ test "test_std_env_get_dup" {
assert(env_var.is_some(), "env_var should have a value");
let value = env_var.unwrap();
- assert(value.c_str() == "ok3", "value should be ok3");
+ assert(strcmp(value.c_str(), "ok3") == 0, "value should be ok3");
value.free();
diff --git a/tests/std/test_json_serialization.zc b/tests/std/test_json_serialization.zc
new file mode 100644
index 0000000..9fd5b32
--- /dev/null
+++ b/tests/std/test_json_serialization.zc
@@ -0,0 +1,149 @@
+import "std/json.zc"
+import "std/io.zc"
+
+test "primitives" {
+ // Null
+ let v = JsonValue::null();
+ let s = v.to_string();
+ let expected = String::from("null");
+ if (!s.eq(&expected)) {
+ panic("Null serialization failed");
+ }
+ expected.free();
+ s.free();
+
+ // Bool True
+ v = JsonValue::bool(true);
+ s = v.to_string();
+ expected = String::from("true");
+ if (!s.eq(&expected)) {
+ panic("Bool true serialization failed");
+ }
+ expected.free();
+ s.free();
+
+ // Bool False
+ v = JsonValue::bool(false);
+ s = v.to_string();
+ expected = String::from("false");
+ if (!s.eq(&expected)) {
+ panic("Bool false serialization failed");
+ }
+ expected.free();
+ s.free();
+
+ // Number Int
+ v = JsonValue::number(123.0);
+ s = v.to_string();
+ expected = String::from("123");
+ if (!s.eq(&expected)) {
+ println "{s.c_str()}";
+ panic("Number 123 serialization failed");
+ }
+ expected.free();
+ s.free();
+
+ // Number Float
+ v = JsonValue::number(12.5);
+ s = v.to_string();
+ expected = String::from("12.5");
+ if (!s.eq(&expected)) {
+ panic("Number 12.5 serialization failed");
+ }
+ expected.free();
+ s.free();
+
+ // String Simple
+ v = JsonValue::string("hello");
+ s = v.to_string();
+ expected = String::from("\"hello\"");
+ if (!s.eq(&expected)) {
+ println "{s.c_str()}";
+ panic("String hello serialization failed");
+ }
+ expected.free();
+ s.free();
+
+ // String Escaped
+ v = JsonValue::string("hello \"world\"");
+ s = v.to_string();
+ expected = String::from("\"hello \\\"world\\\"\"");
+ if (!s.eq(&expected)) {
+ println "Got: {s.c_str()}";
+ panic("String escaped serialization failed");
+ }
+ expected.free();
+ s.free();
+}
+
+test "array" {
+ let v = JsonValue::array();
+ v.push(JsonValue::number(1.0));
+ v.push(JsonValue::bool(true));
+ v.push(JsonValue::string("a"));
+
+ let s = v.to_string();
+ let expected = String::from("[1,true,\"a\"]");
+ if (!s.eq(&expected)) {
+ println "Got: {s.c_str()}";
+ panic("Array serialization failed");
+ }
+ expected.free();
+ s.free();
+}
+
+test "object" {
+ let v = JsonValue::object();
+ v.set("key", JsonValue::string("value"));
+
+ let s = v.to_string();
+ // Round trip verification to avoid parser bug with literals
+ let parsed_res = JsonValue::parse(s.c_str());
+ if (parsed_res.is_err()) {
+ panic("Object round trip parse failed");
+ }
+ let parsed = parsed_res.unwrap();
+ if (!parsed.is_object()) panic("Round trip not object");
+
+ let val_opt = (*parsed).get_string("key");
+ if (val_opt.is_none()) panic("Round trip missing 'key'");
+
+ let val_str = val_opt.unwrap();
+ if (strcmp(val_str, "value") != 0) panic("Round trip wrong value");
+
+ // Cleanup
+ (*parsed).free();
+ free(parsed);
+ s.free();
+}
+
+test "nested" {
+ // {"arr":[1,2]}
+ let v = JsonValue::object();
+ let arr = JsonValue::array();
+ arr.push(JsonValue::number(1.0));
+ arr.push(JsonValue::number(2.0));
+ v.set("arr", arr);
+
+ let s = v.to_string();
+
+ // Round trip
+ let parsed_res = JsonValue::parse(s.c_str());
+ if (parsed_res.is_err()) {
+ panic("Round trip parse failed");
+ }
+ let parsed = parsed_res.unwrap();
+ if (!parsed.is_object()) panic("Round trip type mismatch");
+
+ let arr_opt = (*parsed).get_array("arr");
+ if (arr_opt.is_none()) panic("Round trip missing arr");
+
+ let arr_ptr = arr_opt.unwrap();
+ if (!(*arr_ptr).is_array()) panic("Inner not array");
+ if ((*arr_ptr).len() != 2) panic("Wrong array length");
+
+ // Cleanup
+ (*parsed).free();
+ free(parsed);
+ s.free();
+} \ No newline at end of file
diff --git a/tests/std/test_process.zc b/tests/std/test_process.zc
new file mode 100644
index 0000000..a3ba6ce
--- /dev/null
+++ b/tests/std/test_process.zc
@@ -0,0 +1,26 @@
+
+import "std/process.zc";
+import "std/string.zc";
+
+test "process output" {
+ let cmd = Command::new("echo");
+ cmd.arg("hello");
+
+ let out = cmd.output();
+
+ assert(out.exit_code == 0);
+ // echo usually outputs newline
+ assert(out.stdout.contains('h'));
+ assert(out.stdout.contains('e'));
+ assert(out.stdout.contains('l'));
+ assert(out.stdout.contains('o'));
+
+ // out is dropped automatically
+ // cmd is dropped automatically
+}
+
+test "process status" {
+ let cmd = Command::new("true"); // true command returns 0
+ let status = cmd.status();
+ assert(status == 0);
+}
diff --git a/tests/std/test_slice_iteration.zc b/tests/std/test_slice_iteration.zc
new file mode 100644
index 0000000..b7eddf4
--- /dev/null
+++ b/tests/std/test_slice_iteration.zc
@@ -0,0 +1,29 @@
+import "std/slice.zc"
+import "std/io.zc"
+
+test "slice from array iteration" {
+ let ints: int[5] = [1, 2, 3, 4, 5];
+ let slice = Slice<int>::from_array((int*)(&ints), 5);
+
+ // Test iteration
+ let sum = 0;
+ for val in slice {
+ sum = sum + val;
+ }
+
+ if (sum != 15) {
+ panic("Slice iteration failed: expected sum 15");
+ }
+}
+
+test "slice methods" {
+ let arr: int[3] = [10, 20, 30];
+ let slice = Slice<int>::from_array((int*)(&arr), 3);
+
+ if (slice.length() != 3) panic("Slice length wrong");
+ if (slice.is_empty()) panic("Slice should not be empty");
+
+ let opt = slice.get(1);
+ if (opt.is_none()) panic("Slice get failed");
+ if (opt.unwrap() != 20) panic("Slice get returned wrong value");
+}