From a76cd79be2878f84f297226f4cfcc260c88283cf Mon Sep 17 00:00:00 2001 From: 0264408 Date: Tue, 16 Jun 2026 16:55:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0CLAUDE.md=E6=96=87?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CLAUDE.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4705108 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,58 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Build & Run + +```bash +# Build +cargo build + +# Run REPL (interactive) +cargo run + +# Execute a script file +cargo run -- examples/script.ast + +# Run tests (none yet; the project has no test/ directory) +cargo test +``` + +This is a pure-Rust project with no external dependencies (`edition = "2024"`). + +## Architecture + +**Aster** is a tree-walking interpreter for a custom dynamically-typed scripting language. The pipeline follows the classic compiler frontend pattern: + +``` +Source text → Lexer → Tokens → Parser → AST → Interpreter → Output +``` + +### Module map + +| Module | Responsibility | +|---|---| +| `lexer/` | Tokenizer. `Lexer::tokenize()` takes `&str` and returns `(Vec, Vec)`. Tokens carry `line`/`column` for error reporting. Supports `//` single-line comments. | +| `parser/` | Recursive-descent parser (Pratt-style for expressions). `Parser::parse()` returns `(Vec, Vec)`. Uses `synchronize()` for error recovery — skips to the next statement boundary on parse failure. | +| `ast/` | AST node definitions. `Expr` (in `expr.rs`) covers literals, variables, assignment, property access/indexing, unary/binary/logical ops, calls, lambdas, and object/array literals. `Stmt` (in `stmt.rs`) covers let, expression stmts, blocks, if/while/for, functions, return/break/continue. | +| `interpreter/` | Tree-walking evaluator. `Interpreter` holds an `env: Rc>`. `Env` is a linked-list of scopes for lexical nesting. The `Signal` enum propagates `Return`/`Break`/`Continue` through the call stack. `builtins/` registers native functions (`print`, `input`, `clock`) organized as `io` and `os` modules (also available as global functions). | +| `error/` | Three error variants: `LexError` (line+column), `ParseError` (token), `RuntimeError` (optional token). All implement `Display` and `std::error::Error`. | +| `main.rs` | Two modes: `run_file` (parse-then-execute, exits with code 65 on lex/parse errors, 70 on runtime errors) and `run_repl` (per-line evaluation with `:exit`/`:reset` commands). | + +### Key design decisions + +- **No external crate dependencies.** Everything is built on Rust's stdlib. +- **Rc> for shared ownership.** `Env` chains, `Value::Object`, `Value::Array`, and `Value::Function` all use `Rc>` for interior mutability — matching the dynamic, garbage-collected feel without a GC. +- **Error-tolerant parsing.** Both lexer and parser collect errors into a `Vec` rather than failing on the first error, so multiple diagnostics can be reported per run. +- **Closures capture by environment.** `Function` structs store the `Env` at definition time; lambda expressions (`fn(params) { body }`) work the same way. +- **Compound assignment operators** (`+=`, `-=`, `*=`, `/=`, `%=`) are parsed into `Expr::Assign`/`Set`/`IndexSet` with an `AssignOp` variant and evaluated by `apply_assign_op`. + +### Language syntax overview + +Variables: `let x = 42;` +Functions: `fn add(a, b) { return a + b; }` +Closures: `fn(x, y) { return x + y; }` +Control flow: `if`/`while`/`for` (C-style), `break`/`continue`, `return` +Data: objects `{ key: val }`, arrays `[1, 2, 3]`, indexing `arr[i]`, property access `obj.prop` +Operators: `+ - * / %`, `== != < > <= >=`, `&& || !`, `= += -= *= /= %=` +Builtins: `print(...)`, `input(prompt?)`, `os.clock()` (also `clock()` directly)